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 return; 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_event - 103 * Event handler for a netlink socket. 104 * 105 * @this: event notifier block 106 * @event: event type 107 * @ptr: event payload 108 * 109 **/ 110 static int 111 scsi_nl_rcv_event(struct notifier_block *this, unsigned long event, void *ptr) 112 { 113 struct netlink_notify *n = ptr; 114 115 if (n->protocol != NETLINK_SCSITRANSPORT) 116 return NOTIFY_DONE; 117 118 /* 119 * Currently, we are not tracking PID's, etc. There is nothing 120 * to handle. 121 */ 122 123 return NOTIFY_DONE; 124 } 125 126 static struct notifier_block scsi_netlink_notifier = { 127 .notifier_call = scsi_nl_rcv_event, 128 }; 129 130 131 /** 132 * scsi_netlink_init - 133 * Called by SCSI subsystem to intialize the SCSI transport netlink 134 * interface 135 * 136 **/ 137 void 138 scsi_netlink_init(void) 139 { 140 int error; 141 142 error = netlink_register_notifier(&scsi_netlink_notifier); 143 if (error) { 144 printk(KERN_ERR "%s: register of event handler failed - %d\n", 145 __FUNCTION__, error); 146 return; 147 } 148 149 scsi_nl_sock = netlink_kernel_create(&init_net, NETLINK_SCSITRANSPORT, 150 SCSI_NL_GRP_CNT, scsi_nl_rcv_msg, NULL, 151 THIS_MODULE); 152 if (!scsi_nl_sock) { 153 printk(KERN_ERR "%s: register of recieve handler failed\n", 154 __FUNCTION__); 155 netlink_unregister_notifier(&scsi_netlink_notifier); 156 } 157 158 return; 159 } 160 161 162 /** 163 * scsi_netlink_exit - 164 * Called by SCSI subsystem to disable the SCSI transport netlink 165 * interface 166 * 167 **/ 168 void 169 scsi_netlink_exit(void) 170 { 171 if (scsi_nl_sock) { 172 sock_release(scsi_nl_sock->sk_socket); 173 netlink_unregister_notifier(&scsi_netlink_notifier); 174 } 175 176 return; 177 } 178 179 180