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 <linux/delay.h> 25 #include <linux/slab.h> 26 #include <net/sock.h> 27 #include <net/netlink.h> 28 29 #include <scsi/scsi_netlink.h> 30 #include "scsi_priv.h" 31 32 struct sock *scsi_nl_sock = NULL; 33 EXPORT_SYMBOL_GPL(scsi_nl_sock); 34 35 static DEFINE_SPINLOCK(scsi_nl_lock); 36 static struct list_head scsi_nl_drivers; 37 38 static u32 scsi_nl_state; 39 #define STATE_EHANDLER_BSY 0x00000001 40 41 struct scsi_nl_transport { 42 int (*msg_handler)(struct sk_buff *); 43 void (*event_handler)(struct notifier_block *, unsigned long, void *); 44 unsigned int refcnt; 45 int flags; 46 }; 47 48 /* flags values (bit flags) */ 49 #define HANDLER_DELETING 0x1 50 51 static struct scsi_nl_transport transports[SCSI_NL_MAX_TRANSPORTS] = 52 { {NULL, }, }; 53 54 55 struct scsi_nl_drvr { 56 struct list_head next; 57 int (*dmsg_handler)(struct Scsi_Host *shost, void *payload, 58 u32 len, u32 pid); 59 void (*devt_handler)(struct notifier_block *nb, 60 unsigned long event, void *notify_ptr); 61 struct scsi_host_template *hostt; 62 u64 vendor_id; 63 unsigned int refcnt; 64 int flags; 65 }; 66 67 68 69 /** 70 * scsi_nl_rcv_msg - Receive message handler. 71 * @skb: socket receive buffer 72 * 73 * Description: Extracts message from a receive buffer. 74 * Validates message header and calls appropriate transport message handler 75 * 76 * 77 **/ 78 static void 79 scsi_nl_rcv_msg(struct sk_buff *skb) 80 { 81 struct nlmsghdr *nlh; 82 struct scsi_nl_hdr *hdr; 83 unsigned long flags; 84 u32 rlen; 85 int err, tport; 86 87 while (skb->len >= NLMSG_SPACE(0)) { 88 err = 0; 89 90 nlh = nlmsg_hdr(skb); 91 if ((nlh->nlmsg_len < (sizeof(*nlh) + sizeof(*hdr))) || 92 (skb->len < nlh->nlmsg_len)) { 93 printk(KERN_WARNING "%s: discarding partial skb\n", 94 __func__); 95 return; 96 } 97 98 rlen = NLMSG_ALIGN(nlh->nlmsg_len); 99 if (rlen > skb->len) 100 rlen = skb->len; 101 102 if (nlh->nlmsg_type != SCSI_TRANSPORT_MSG) { 103 err = -EBADMSG; 104 goto next_msg; 105 } 106 107 hdr = NLMSG_DATA(nlh); 108 if ((hdr->version != SCSI_NL_VERSION) || 109 (hdr->magic != SCSI_NL_MAGIC)) { 110 err = -EPROTOTYPE; 111 goto next_msg; 112 } 113 114 if (security_netlink_recv(skb, CAP_SYS_ADMIN)) { 115 err = -EPERM; 116 goto next_msg; 117 } 118 119 if (nlh->nlmsg_len < (sizeof(*nlh) + hdr->msglen)) { 120 printk(KERN_WARNING "%s: discarding partial message\n", 121 __func__); 122 goto next_msg; 123 } 124 125 /* 126 * Deliver message to the appropriate transport 127 */ 128 spin_lock_irqsave(&scsi_nl_lock, flags); 129 130 tport = hdr->transport; 131 if ((tport < SCSI_NL_MAX_TRANSPORTS) && 132 !(transports[tport].flags & HANDLER_DELETING) && 133 (transports[tport].msg_handler)) { 134 transports[tport].refcnt++; 135 spin_unlock_irqrestore(&scsi_nl_lock, flags); 136 err = transports[tport].msg_handler(skb); 137 spin_lock_irqsave(&scsi_nl_lock, flags); 138 transports[tport].refcnt--; 139 } else 140 err = -ENOENT; 141 142 spin_unlock_irqrestore(&scsi_nl_lock, flags); 143 144 next_msg: 145 if ((err) || (nlh->nlmsg_flags & NLM_F_ACK)) 146 netlink_ack(skb, nlh, err); 147 148 skb_pull(skb, rlen); 149 } 150 } 151 152 153 /** 154 * scsi_nl_rcv_event - Event handler for a netlink socket. 155 * @this: event notifier block 156 * @event: event type 157 * @ptr: event payload 158 * 159 **/ 160 static int 161 scsi_nl_rcv_event(struct notifier_block *this, unsigned long event, void *ptr) 162 { 163 struct netlink_notify *n = ptr; 164 struct scsi_nl_drvr *driver; 165 unsigned long flags; 166 int tport; 167 168 if (n->protocol != NETLINK_SCSITRANSPORT) 169 return NOTIFY_DONE; 170 171 spin_lock_irqsave(&scsi_nl_lock, flags); 172 scsi_nl_state |= STATE_EHANDLER_BSY; 173 174 /* 175 * Pass event on to any transports that may be listening 176 */ 177 for (tport = 0; tport < SCSI_NL_MAX_TRANSPORTS; tport++) { 178 if (!(transports[tport].flags & HANDLER_DELETING) && 179 (transports[tport].event_handler)) { 180 spin_unlock_irqrestore(&scsi_nl_lock, flags); 181 transports[tport].event_handler(this, event, ptr); 182 spin_lock_irqsave(&scsi_nl_lock, flags); 183 } 184 } 185 186 /* 187 * Pass event on to any drivers that may be listening 188 */ 189 list_for_each_entry(driver, &scsi_nl_drivers, next) { 190 if (!(driver->flags & HANDLER_DELETING) && 191 (driver->devt_handler)) { 192 spin_unlock_irqrestore(&scsi_nl_lock, flags); 193 driver->devt_handler(this, event, ptr); 194 spin_lock_irqsave(&scsi_nl_lock, flags); 195 } 196 } 197 198 scsi_nl_state &= ~STATE_EHANDLER_BSY; 199 spin_unlock_irqrestore(&scsi_nl_lock, flags); 200 201 return NOTIFY_DONE; 202 } 203 204 static struct notifier_block scsi_netlink_notifier = { 205 .notifier_call = scsi_nl_rcv_event, 206 }; 207 208 209 /* 210 * GENERIC SCSI transport receive and event handlers 211 */ 212 213 /** 214 * scsi_generic_msg_handler - receive message handler for GENERIC transport messages 215 * @skb: socket receive buffer 216 **/ 217 static int 218 scsi_generic_msg_handler(struct sk_buff *skb) 219 { 220 struct nlmsghdr *nlh = nlmsg_hdr(skb); 221 struct scsi_nl_hdr *snlh = NLMSG_DATA(nlh); 222 struct scsi_nl_drvr *driver; 223 struct Scsi_Host *shost; 224 unsigned long flags; 225 int err = 0, match, pid; 226 227 pid = NETLINK_CREDS(skb)->pid; 228 229 switch (snlh->msgtype) { 230 case SCSI_NL_SHOST_VENDOR: 231 { 232 struct scsi_nl_host_vendor_msg *msg = NLMSG_DATA(nlh); 233 234 /* Locate the driver that corresponds to the message */ 235 spin_lock_irqsave(&scsi_nl_lock, flags); 236 match = 0; 237 list_for_each_entry(driver, &scsi_nl_drivers, next) { 238 if (driver->vendor_id == msg->vendor_id) { 239 match = 1; 240 break; 241 } 242 } 243 244 if ((!match) || (!driver->dmsg_handler)) { 245 spin_unlock_irqrestore(&scsi_nl_lock, flags); 246 err = -ESRCH; 247 goto rcv_exit; 248 } 249 250 if (driver->flags & HANDLER_DELETING) { 251 spin_unlock_irqrestore(&scsi_nl_lock, flags); 252 err = -ESHUTDOWN; 253 goto rcv_exit; 254 } 255 256 driver->refcnt++; 257 spin_unlock_irqrestore(&scsi_nl_lock, flags); 258 259 260 /* if successful, scsi_host_lookup takes a shost reference */ 261 shost = scsi_host_lookup(msg->host_no); 262 if (!shost) { 263 err = -ENODEV; 264 goto driver_exit; 265 } 266 267 /* is this host owned by the vendor ? */ 268 if (shost->hostt != driver->hostt) { 269 err = -EINVAL; 270 goto vendormsg_put; 271 } 272 273 /* pass message on to the driver */ 274 err = driver->dmsg_handler(shost, (void *)&msg[1], 275 msg->vmsg_datalen, pid); 276 277 vendormsg_put: 278 /* release reference by scsi_host_lookup */ 279 scsi_host_put(shost); 280 281 driver_exit: 282 /* release our own reference on the registration object */ 283 spin_lock_irqsave(&scsi_nl_lock, flags); 284 driver->refcnt--; 285 spin_unlock_irqrestore(&scsi_nl_lock, flags); 286 break; 287 } 288 289 default: 290 err = -EBADR; 291 break; 292 } 293 294 rcv_exit: 295 if (err) 296 printk(KERN_WARNING "%s: Msgtype %d failed - err %d\n", 297 __func__, snlh->msgtype, err); 298 return err; 299 } 300 301 302 /** 303 * scsi_nl_add_transport - 304 * Registers message and event handlers for a transport. Enables 305 * receipt of netlink messages and events to a transport. 306 * 307 * @tport: transport registering handlers 308 * @msg_handler: receive message handler callback 309 * @event_handler: receive event handler callback 310 **/ 311 int 312 scsi_nl_add_transport(u8 tport, 313 int (*msg_handler)(struct sk_buff *), 314 void (*event_handler)(struct notifier_block *, unsigned long, void *)) 315 { 316 unsigned long flags; 317 int err = 0; 318 319 if (tport >= SCSI_NL_MAX_TRANSPORTS) 320 return -EINVAL; 321 322 spin_lock_irqsave(&scsi_nl_lock, flags); 323 324 if (scsi_nl_state & STATE_EHANDLER_BSY) { 325 spin_unlock_irqrestore(&scsi_nl_lock, flags); 326 msleep(1); 327 spin_lock_irqsave(&scsi_nl_lock, flags); 328 } 329 330 if (transports[tport].msg_handler || transports[tport].event_handler) { 331 err = -EALREADY; 332 goto register_out; 333 } 334 335 transports[tport].msg_handler = msg_handler; 336 transports[tport].event_handler = event_handler; 337 transports[tport].flags = 0; 338 transports[tport].refcnt = 0; 339 340 register_out: 341 spin_unlock_irqrestore(&scsi_nl_lock, flags); 342 343 return err; 344 } 345 EXPORT_SYMBOL_GPL(scsi_nl_add_transport); 346 347 348 /** 349 * scsi_nl_remove_transport - 350 * Disable transport receiption of messages and events 351 * 352 * @tport: transport deregistering handlers 353 * 354 **/ 355 void 356 scsi_nl_remove_transport(u8 tport) 357 { 358 unsigned long flags; 359 360 spin_lock_irqsave(&scsi_nl_lock, flags); 361 if (scsi_nl_state & STATE_EHANDLER_BSY) { 362 spin_unlock_irqrestore(&scsi_nl_lock, flags); 363 msleep(1); 364 spin_lock_irqsave(&scsi_nl_lock, flags); 365 } 366 367 if (tport < SCSI_NL_MAX_TRANSPORTS) { 368 transports[tport].flags |= HANDLER_DELETING; 369 370 while (transports[tport].refcnt != 0) { 371 spin_unlock_irqrestore(&scsi_nl_lock, flags); 372 schedule_timeout_uninterruptible(HZ/4); 373 spin_lock_irqsave(&scsi_nl_lock, flags); 374 } 375 transports[tport].msg_handler = NULL; 376 transports[tport].event_handler = NULL; 377 transports[tport].flags = 0; 378 } 379 380 spin_unlock_irqrestore(&scsi_nl_lock, flags); 381 382 return; 383 } 384 EXPORT_SYMBOL_GPL(scsi_nl_remove_transport); 385 386 387 /** 388 * scsi_nl_add_driver - 389 * A driver is registering its interfaces for SCSI netlink messages 390 * 391 * @vendor_id: A unique identification value for the driver. 392 * @hostt: address of the driver's host template. Used 393 * to verify an shost is bound to the driver 394 * @nlmsg_handler: receive message handler callback 395 * @nlevt_handler: receive event handler callback 396 * 397 * Returns: 398 * 0 on Success 399 * error result otherwise 400 **/ 401 int 402 scsi_nl_add_driver(u64 vendor_id, struct scsi_host_template *hostt, 403 int (*nlmsg_handler)(struct Scsi_Host *shost, void *payload, 404 u32 len, u32 pid), 405 void (*nlevt_handler)(struct notifier_block *nb, 406 unsigned long event, void *notify_ptr)) 407 { 408 struct scsi_nl_drvr *driver; 409 unsigned long flags; 410 411 driver = kzalloc(sizeof(*driver), GFP_KERNEL); 412 if (unlikely(!driver)) { 413 printk(KERN_ERR "%s: allocation failure\n", __func__); 414 return -ENOMEM; 415 } 416 417 driver->dmsg_handler = nlmsg_handler; 418 driver->devt_handler = nlevt_handler; 419 driver->hostt = hostt; 420 driver->vendor_id = vendor_id; 421 422 spin_lock_irqsave(&scsi_nl_lock, flags); 423 if (scsi_nl_state & STATE_EHANDLER_BSY) { 424 spin_unlock_irqrestore(&scsi_nl_lock, flags); 425 msleep(1); 426 spin_lock_irqsave(&scsi_nl_lock, flags); 427 } 428 list_add_tail(&driver->next, &scsi_nl_drivers); 429 spin_unlock_irqrestore(&scsi_nl_lock, flags); 430 431 return 0; 432 } 433 EXPORT_SYMBOL_GPL(scsi_nl_add_driver); 434 435 436 /** 437 * scsi_nl_remove_driver - 438 * An driver is unregistering with the SCSI netlink messages 439 * 440 * @vendor_id: The unique identification value for the driver. 441 **/ 442 void 443 scsi_nl_remove_driver(u64 vendor_id) 444 { 445 struct scsi_nl_drvr *driver; 446 unsigned long flags; 447 448 spin_lock_irqsave(&scsi_nl_lock, flags); 449 if (scsi_nl_state & STATE_EHANDLER_BSY) { 450 spin_unlock_irqrestore(&scsi_nl_lock, flags); 451 msleep(1); 452 spin_lock_irqsave(&scsi_nl_lock, flags); 453 } 454 455 list_for_each_entry(driver, &scsi_nl_drivers, next) { 456 if (driver->vendor_id == vendor_id) { 457 driver->flags |= HANDLER_DELETING; 458 while (driver->refcnt != 0) { 459 spin_unlock_irqrestore(&scsi_nl_lock, flags); 460 schedule_timeout_uninterruptible(HZ/4); 461 spin_lock_irqsave(&scsi_nl_lock, flags); 462 } 463 list_del(&driver->next); 464 kfree(driver); 465 spin_unlock_irqrestore(&scsi_nl_lock, flags); 466 return; 467 } 468 } 469 470 spin_unlock_irqrestore(&scsi_nl_lock, flags); 471 472 printk(KERN_ERR "%s: removal of driver failed - vendor_id 0x%llx\n", 473 __func__, (unsigned long long)vendor_id); 474 return; 475 } 476 EXPORT_SYMBOL_GPL(scsi_nl_remove_driver); 477 478 479 /** 480 * scsi_netlink_init - Called by SCSI subsystem to initialize 481 * the SCSI transport netlink interface 482 * 483 **/ 484 void 485 scsi_netlink_init(void) 486 { 487 int error; 488 489 INIT_LIST_HEAD(&scsi_nl_drivers); 490 491 error = netlink_register_notifier(&scsi_netlink_notifier); 492 if (error) { 493 printk(KERN_ERR "%s: register of event handler failed - %d\n", 494 __func__, error); 495 return; 496 } 497 498 scsi_nl_sock = netlink_kernel_create(&init_net, NETLINK_SCSITRANSPORT, 499 SCSI_NL_GRP_CNT, scsi_nl_rcv_msg, NULL, 500 THIS_MODULE); 501 if (!scsi_nl_sock) { 502 printk(KERN_ERR "%s: register of recieve handler failed\n", 503 __func__); 504 netlink_unregister_notifier(&scsi_netlink_notifier); 505 return; 506 } 507 508 /* Register the entry points for the generic SCSI transport */ 509 error = scsi_nl_add_transport(SCSI_NL_TRANSPORT, 510 scsi_generic_msg_handler, NULL); 511 if (error) 512 printk(KERN_ERR "%s: register of GENERIC transport handler" 513 " failed - %d\n", __func__, error); 514 return; 515 } 516 517 518 /** 519 * scsi_netlink_exit - Called by SCSI subsystem to disable the SCSI transport netlink interface 520 * 521 **/ 522 void 523 scsi_netlink_exit(void) 524 { 525 scsi_nl_remove_transport(SCSI_NL_TRANSPORT); 526 527 if (scsi_nl_sock) { 528 netlink_kernel_release(scsi_nl_sock); 529 netlink_unregister_notifier(&scsi_netlink_notifier); 530 } 531 532 return; 533 } 534 535 536 /* 537 * Exported Interfaces 538 */ 539 540 /** 541 * scsi_nl_send_transport_msg - 542 * Generic function to send a single message from a SCSI transport to 543 * a single process 544 * 545 * @pid: receiving pid 546 * @hdr: message payload 547 * 548 **/ 549 void 550 scsi_nl_send_transport_msg(u32 pid, struct scsi_nl_hdr *hdr) 551 { 552 struct sk_buff *skb; 553 struct nlmsghdr *nlh; 554 const char *fn; 555 char *datab; 556 u32 len, skblen; 557 int err; 558 559 if (!scsi_nl_sock) { 560 err = -ENOENT; 561 fn = "netlink socket"; 562 goto msg_fail; 563 } 564 565 len = NLMSG_SPACE(hdr->msglen); 566 skblen = NLMSG_SPACE(len); 567 568 skb = alloc_skb(skblen, GFP_KERNEL); 569 if (!skb) { 570 err = -ENOBUFS; 571 fn = "alloc_skb"; 572 goto msg_fail; 573 } 574 575 nlh = nlmsg_put(skb, pid, 0, SCSI_TRANSPORT_MSG, len - sizeof(*nlh), 0); 576 if (!nlh) { 577 err = -ENOBUFS; 578 fn = "nlmsg_put"; 579 goto msg_fail_skb; 580 } 581 datab = NLMSG_DATA(nlh); 582 memcpy(datab, hdr, hdr->msglen); 583 584 err = nlmsg_unicast(scsi_nl_sock, skb, pid); 585 if (err < 0) { 586 fn = "nlmsg_unicast"; 587 /* nlmsg_unicast already kfree_skb'd */ 588 goto msg_fail; 589 } 590 591 return; 592 593 msg_fail_skb: 594 kfree_skb(skb); 595 msg_fail: 596 printk(KERN_WARNING 597 "%s: Dropped Message : pid %d Transport %d, msgtype x%x, " 598 "msglen %d: %s : err %d\n", 599 __func__, pid, hdr->transport, hdr->msgtype, hdr->msglen, 600 fn, err); 601 return; 602 } 603 EXPORT_SYMBOL_GPL(scsi_nl_send_transport_msg); 604 605 606 /** 607 * scsi_nl_send_vendor_msg - called to send a shost vendor unique message 608 * to a specific process id. 609 * 610 * @pid: process id of the receiver 611 * @host_no: host # sending the message 612 * @vendor_id: unique identifier for the driver's vendor 613 * @data_len: amount, in bytes, of vendor unique payload data 614 * @data_buf: pointer to vendor unique data buffer 615 * 616 * Returns: 617 * 0 on successful return 618 * otherwise, failing error code 619 * 620 * Notes: 621 * This routine assumes no locks are held on entry. 622 */ 623 int 624 scsi_nl_send_vendor_msg(u32 pid, unsigned short host_no, u64 vendor_id, 625 char *data_buf, u32 data_len) 626 { 627 struct sk_buff *skb; 628 struct nlmsghdr *nlh; 629 struct scsi_nl_host_vendor_msg *msg; 630 u32 len, skblen; 631 int err; 632 633 if (!scsi_nl_sock) { 634 err = -ENOENT; 635 goto send_vendor_fail; 636 } 637 638 len = SCSI_NL_MSGALIGN(sizeof(*msg) + data_len); 639 skblen = NLMSG_SPACE(len); 640 641 skb = alloc_skb(skblen, GFP_KERNEL); 642 if (!skb) { 643 err = -ENOBUFS; 644 goto send_vendor_fail; 645 } 646 647 nlh = nlmsg_put(skb, 0, 0, SCSI_TRANSPORT_MSG, 648 skblen - sizeof(*nlh), 0); 649 if (!nlh) { 650 err = -ENOBUFS; 651 goto send_vendor_fail_skb; 652 } 653 msg = NLMSG_DATA(nlh); 654 655 INIT_SCSI_NL_HDR(&msg->snlh, SCSI_NL_TRANSPORT, 656 SCSI_NL_SHOST_VENDOR, len); 657 msg->vendor_id = vendor_id; 658 msg->host_no = host_no; 659 msg->vmsg_datalen = data_len; /* bytes */ 660 memcpy(&msg[1], data_buf, data_len); 661 662 err = nlmsg_unicast(scsi_nl_sock, skb, pid); 663 if (err) 664 /* nlmsg_multicast already kfree_skb'd */ 665 goto send_vendor_fail; 666 667 return 0; 668 669 send_vendor_fail_skb: 670 kfree_skb(skb); 671 send_vendor_fail: 672 printk(KERN_WARNING 673 "%s: Dropped SCSI Msg : host %d vendor_unique - err %d\n", 674 __func__, host_no, err); 675 return err; 676 } 677 EXPORT_SYMBOL(scsi_nl_send_vendor_msg); 678 679 680