1 /* 2 * scsi_netlink.c - SCSI Transport Netlink Interface 3 * 4 * Copyright (C) 2006 James Smart, Emulex Corporation 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 */ 21 #include <linux/time.h> 22 #include <linux/jiffies.h> 23 #include <linux/security.h> 24 #include <net/sock.h> 25 #include <net/netlink.h> 26 27 #include <scsi/scsi_netlink.h> 28 #include "scsi_priv.h" 29 30 struct sock *scsi_nl_sock = NULL; 31 EXPORT_SYMBOL_GPL(scsi_nl_sock); 32 33 34 /** 35 * scsi_nl_rcv_msg - 36 * Receive message handler. Extracts message from a receive buffer. 37 * Validates message header and calls appropriate transport message handler 38 * 39 * @skb: socket receive buffer 40 * 41 **/ 42 static void 43 scsi_nl_rcv_msg(struct sk_buff *skb) 44 { 45 struct nlmsghdr *nlh; 46 struct scsi_nl_hdr *hdr; 47 uint32_t rlen; 48 int err; 49 50 while (skb->len >= NLMSG_SPACE(0)) { 51 err = 0; 52 53 nlh = nlmsg_hdr(skb); 54 if ((nlh->nlmsg_len < (sizeof(*nlh) + sizeof(*hdr))) || 55 (skb->len < nlh->nlmsg_len)) { 56 printk(KERN_WARNING "%s: discarding partial skb\n", 57 __FUNCTION__); 58 return; 59 } 60 61 rlen = NLMSG_ALIGN(nlh->nlmsg_len); 62 if (rlen > skb->len) 63 rlen = skb->len; 64 65 if (nlh->nlmsg_type != SCSI_TRANSPORT_MSG) { 66 err = -EBADMSG; 67 goto next_msg; 68 } 69 70 hdr = NLMSG_DATA(nlh); 71 if ((hdr->version != SCSI_NL_VERSION) || 72 (hdr->magic != SCSI_NL_MAGIC)) { 73 err = -EPROTOTYPE; 74 goto next_msg; 75 } 76 77 if (security_netlink_recv(skb, CAP_SYS_ADMIN)) { 78 err = -EPERM; 79 goto next_msg; 80 } 81 82 if (nlh->nlmsg_len < (sizeof(*nlh) + hdr->msglen)) { 83 printk(KERN_WARNING "%s: discarding partial message\n", 84 __FUNCTION__); 85 return; 86 } 87 88 /* 89 * We currently don't support anyone sending us a message 90 */ 91 92 next_msg: 93 if ((err) || (nlh->nlmsg_flags & NLM_F_ACK)) 94 netlink_ack(skb, nlh, err); 95 96 skb_pull(skb, rlen); 97 } 98 } 99 100 101 /** 102 * scsi_nl_rcv_msg - 103 * Receive handler for a socket. Extracts a received message buffer from 104 * the socket, and starts message processing. 105 * 106 * @sk: socket 107 * @len: unused 108 * 109 **/ 110 static void 111 scsi_nl_rcv(struct sock *sk, int len) 112 { 113 struct sk_buff *skb; 114 115 while ((skb = skb_dequeue(&sk->sk_receive_queue))) { 116 scsi_nl_rcv_msg(skb); 117 kfree_skb(skb); 118 } 119 } 120 121 122 /** 123 * scsi_nl_rcv_event - 124 * Event handler for a netlink socket. 125 * 126 * @this: event notifier block 127 * @event: event type 128 * @ptr: event payload 129 * 130 **/ 131 static int 132 scsi_nl_rcv_event(struct notifier_block *this, unsigned long event, void *ptr) 133 { 134 struct netlink_notify *n = ptr; 135 136 if (n->protocol != NETLINK_SCSITRANSPORT) 137 return NOTIFY_DONE; 138 139 /* 140 * Currently, we are not tracking PID's, etc. There is nothing 141 * to handle. 142 */ 143 144 return NOTIFY_DONE; 145 } 146 147 static struct notifier_block scsi_netlink_notifier = { 148 .notifier_call = scsi_nl_rcv_event, 149 }; 150 151 152 /** 153 * scsi_netlink_init - 154 * Called by SCSI subsystem to intialize the SCSI transport netlink 155 * interface 156 * 157 **/ 158 void 159 scsi_netlink_init(void) 160 { 161 int error; 162 163 error = netlink_register_notifier(&scsi_netlink_notifier); 164 if (error) { 165 printk(KERN_ERR "%s: register of event handler failed - %d\n", 166 __FUNCTION__, error); 167 return; 168 } 169 170 scsi_nl_sock = netlink_kernel_create(NETLINK_SCSITRANSPORT, 171 SCSI_NL_GRP_CNT, scsi_nl_rcv, NULL, 172 THIS_MODULE); 173 if (!scsi_nl_sock) { 174 printk(KERN_ERR "%s: register of recieve handler failed\n", 175 __FUNCTION__); 176 netlink_unregister_notifier(&scsi_netlink_notifier); 177 } 178 179 return; 180 } 181 182 183 /** 184 * scsi_netlink_exit - 185 * Called by SCSI subsystem to disable the SCSI transport netlink 186 * interface 187 * 188 **/ 189 void 190 scsi_netlink_exit(void) 191 { 192 if (scsi_nl_sock) { 193 sock_release(scsi_nl_sock->sk_socket); 194 netlink_unregister_notifier(&scsi_netlink_notifier); 195 } 196 197 return; 198 } 199 200 201