123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- /*
- * scsi_netlink.c - SCSI Transport Netlink Interface
- *
- * Copyright (C) 2006 James Smart, Emulex Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
- #include <linux/time.h>
- #include <linux/jiffies.h>
- #include <linux/security.h>
- #include <net/sock.h>
- #include <net/netlink.h>
- #include <scsi/scsi_netlink.h>
- #include "scsi_priv.h"
- struct sock *scsi_nl_sock = NULL;
- EXPORT_SYMBOL_GPL(scsi_nl_sock);
- /**
- * scsi_nl_rcv_msg -
- * Receive message handler. Extracts message from a receive buffer.
- * Validates message header and calls appropriate transport message handler
- *
- * @skb: socket receive buffer
- *
- **/
- static void
- scsi_nl_rcv_msg(struct sk_buff *skb)
- {
- struct nlmsghdr *nlh;
- struct scsi_nl_hdr *hdr;
- uint32_t rlen;
- int err;
- while (skb->len >= NLMSG_SPACE(0)) {
- err = 0;
- nlh = nlmsg_hdr(skb);
- if ((nlh->nlmsg_len < (sizeof(*nlh) + sizeof(*hdr))) ||
- (skb->len < nlh->nlmsg_len)) {
- printk(KERN_WARNING "%s: discarding partial skb\n",
- __FUNCTION__);
- return;
- }
- rlen = NLMSG_ALIGN(nlh->nlmsg_len);
- if (rlen > skb->len)
- rlen = skb->len;
- if (nlh->nlmsg_type != SCSI_TRANSPORT_MSG) {
- err = -EBADMSG;
- goto next_msg;
- }
- hdr = NLMSG_DATA(nlh);
- if ((hdr->version != SCSI_NL_VERSION) ||
- (hdr->magic != SCSI_NL_MAGIC)) {
- err = -EPROTOTYPE;
- goto next_msg;
- }
- if (security_netlink_recv(skb, CAP_SYS_ADMIN)) {
- err = -EPERM;
- goto next_msg;
- }
- if (nlh->nlmsg_len < (sizeof(*nlh) + hdr->msglen)) {
- printk(KERN_WARNING "%s: discarding partial message\n",
- __FUNCTION__);
- return;
- }
- /*
- * We currently don't support anyone sending us a message
- */
- next_msg:
- if ((err) || (nlh->nlmsg_flags & NLM_F_ACK))
- netlink_ack(skb, nlh, err);
- skb_pull(skb, rlen);
- }
- }
- /**
- * scsi_nl_rcv_msg -
- * Receive handler for a socket. Extracts a received message buffer from
- * the socket, and starts message processing.
- *
- * @sk: socket
- * @len: unused
- *
- **/
- static void
- scsi_nl_rcv(struct sock *sk, int len)
- {
- struct sk_buff *skb;
- while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
- scsi_nl_rcv_msg(skb);
- kfree_skb(skb);
- }
- }
- /**
- * scsi_nl_rcv_event -
- * Event handler for a netlink socket.
- *
- * @this: event notifier block
- * @event: event type
- * @ptr: event payload
- *
- **/
- static int
- scsi_nl_rcv_event(struct notifier_block *this, unsigned long event, void *ptr)
- {
- struct netlink_notify *n = ptr;
- if (n->protocol != NETLINK_SCSITRANSPORT)
- return NOTIFY_DONE;
- /*
- * Currently, we are not tracking PID's, etc. There is nothing
- * to handle.
- */
- return NOTIFY_DONE;
- }
- static struct notifier_block scsi_netlink_notifier = {
- .notifier_call = scsi_nl_rcv_event,
- };
- /**
- * scsi_netlink_init -
- * Called by SCSI subsystem to intialize the SCSI transport netlink
- * interface
- *
- **/
- void
- scsi_netlink_init(void)
- {
- int error;
- error = netlink_register_notifier(&scsi_netlink_notifier);
- if (error) {
- printk(KERN_ERR "%s: register of event handler failed - %d\n",
- __FUNCTION__, error);
- return;
- }
- scsi_nl_sock = netlink_kernel_create(NETLINK_SCSITRANSPORT,
- SCSI_NL_GRP_CNT, scsi_nl_rcv, NULL,
- THIS_MODULE);
- if (!scsi_nl_sock) {
- printk(KERN_ERR "%s: register of recieve handler failed\n",
- __FUNCTION__);
- netlink_unregister_notifier(&scsi_netlink_notifier);
- }
- return;
- }
- /**
- * scsi_netlink_exit -
- * Called by SCSI subsystem to disable the SCSI transport netlink
- * interface
- *
- **/
- void
- scsi_netlink_exit(void)
- {
- if (scsi_nl_sock) {
- sock_release(scsi_nl_sock->sk_socket);
- netlink_unregister_notifier(&scsi_netlink_notifier);
- }
- return;
- }
|