scsi_netlink.c revision eb44820c28bc9a042e1157b41c677018a8fdfc74
184314fd4740ad73550c76dee4a9578979d84af48James Smart/*
284314fd4740ad73550c76dee4a9578979d84af48James Smart *  scsi_netlink.c  - SCSI Transport Netlink Interface
384314fd4740ad73550c76dee4a9578979d84af48James Smart *
484314fd4740ad73550c76dee4a9578979d84af48James Smart *  Copyright (C) 2006   James Smart, Emulex Corporation
584314fd4740ad73550c76dee4a9578979d84af48James Smart *
684314fd4740ad73550c76dee4a9578979d84af48James Smart *  This program is free software; you can redistribute it and/or modify
784314fd4740ad73550c76dee4a9578979d84af48James Smart *  it under the terms of the GNU General Public License as published by
884314fd4740ad73550c76dee4a9578979d84af48James Smart *  the Free Software Foundation; either version 2 of the License, or
984314fd4740ad73550c76dee4a9578979d84af48James Smart *  (at your option) any later version.
1084314fd4740ad73550c76dee4a9578979d84af48James Smart *
1184314fd4740ad73550c76dee4a9578979d84af48James Smart *  This program is distributed in the hope that it will be useful,
1284314fd4740ad73550c76dee4a9578979d84af48James Smart *  but WITHOUT ANY WARRANTY; without even the implied warranty of
1384314fd4740ad73550c76dee4a9578979d84af48James Smart *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1484314fd4740ad73550c76dee4a9578979d84af48James Smart *  GNU General Public License for more details.
1584314fd4740ad73550c76dee4a9578979d84af48James Smart *
1684314fd4740ad73550c76dee4a9578979d84af48James Smart *  You should have received a copy of the GNU General Public License
1784314fd4740ad73550c76dee4a9578979d84af48James Smart *  along with this program; if not, write to the Free Software
1884314fd4740ad73550c76dee4a9578979d84af48James Smart *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
1984314fd4740ad73550c76dee4a9578979d84af48James Smart *
2084314fd4740ad73550c76dee4a9578979d84af48James Smart */
2184314fd4740ad73550c76dee4a9578979d84af48James Smart#include <linux/time.h>
2284314fd4740ad73550c76dee4a9578979d84af48James Smart#include <linux/jiffies.h>
2384314fd4740ad73550c76dee4a9578979d84af48James Smart#include <linux/security.h>
2484314fd4740ad73550c76dee4a9578979d84af48James Smart#include <net/sock.h>
2584314fd4740ad73550c76dee4a9578979d84af48James Smart#include <net/netlink.h>
2684314fd4740ad73550c76dee4a9578979d84af48James Smart
2784314fd4740ad73550c76dee4a9578979d84af48James Smart#include <scsi/scsi_netlink.h>
2884314fd4740ad73550c76dee4a9578979d84af48James Smart#include "scsi_priv.h"
2984314fd4740ad73550c76dee4a9578979d84af48James Smart
3084314fd4740ad73550c76dee4a9578979d84af48James Smartstruct sock *scsi_nl_sock = NULL;
3184314fd4740ad73550c76dee4a9578979d84af48James SmartEXPORT_SYMBOL_GPL(scsi_nl_sock);
3284314fd4740ad73550c76dee4a9578979d84af48James Smart
3384314fd4740ad73550c76dee4a9578979d84af48James Smart
3484314fd4740ad73550c76dee4a9578979d84af48James Smart/**
35eb44820c28bc9a042e1157b41c677018a8fdfc74Rob Landley * scsi_nl_rcv_msg - Receive message handler.
36eb44820c28bc9a042e1157b41c677018a8fdfc74Rob Landley * @skb:		socket receive buffer
37eb44820c28bc9a042e1157b41c677018a8fdfc74Rob Landley *
38eb44820c28bc9a042e1157b41c677018a8fdfc74Rob Landley * Description: Extracts message from a receive buffer.
3984314fd4740ad73550c76dee4a9578979d84af48James Smart *    Validates message header and calls appropriate transport message handler
4084314fd4740ad73550c76dee4a9578979d84af48James Smart *
4184314fd4740ad73550c76dee4a9578979d84af48James Smart *
4284314fd4740ad73550c76dee4a9578979d84af48James Smart **/
4384314fd4740ad73550c76dee4a9578979d84af48James Smartstatic void
4484314fd4740ad73550c76dee4a9578979d84af48James Smartscsi_nl_rcv_msg(struct sk_buff *skb)
4584314fd4740ad73550c76dee4a9578979d84af48James Smart{
4684314fd4740ad73550c76dee4a9578979d84af48James Smart	struct nlmsghdr *nlh;
4784314fd4740ad73550c76dee4a9578979d84af48James Smart	struct scsi_nl_hdr *hdr;
4884314fd4740ad73550c76dee4a9578979d84af48James Smart	uint32_t rlen;
4984314fd4740ad73550c76dee4a9578979d84af48James Smart	int err;
5084314fd4740ad73550c76dee4a9578979d84af48James Smart
5184314fd4740ad73550c76dee4a9578979d84af48James Smart	while (skb->len >= NLMSG_SPACE(0)) {
5284314fd4740ad73550c76dee4a9578979d84af48James Smart		err = 0;
5384314fd4740ad73550c76dee4a9578979d84af48James Smart
54b529ccf2799c14346d1518e9bdf1f88f03643e99Arnaldo Carvalho de Melo		nlh = nlmsg_hdr(skb);
5584314fd4740ad73550c76dee4a9578979d84af48James Smart		if ((nlh->nlmsg_len < (sizeof(*nlh) + sizeof(*hdr))) ||
5684314fd4740ad73550c76dee4a9578979d84af48James Smart		    (skb->len < nlh->nlmsg_len)) {
5784314fd4740ad73550c76dee4a9578979d84af48James Smart			printk(KERN_WARNING "%s: discarding partial skb\n",
5884314fd4740ad73550c76dee4a9578979d84af48James Smart				 __FUNCTION__);
5984314fd4740ad73550c76dee4a9578979d84af48James Smart			return;
6084314fd4740ad73550c76dee4a9578979d84af48James Smart		}
6184314fd4740ad73550c76dee4a9578979d84af48James Smart
6284314fd4740ad73550c76dee4a9578979d84af48James Smart		rlen = NLMSG_ALIGN(nlh->nlmsg_len);
6384314fd4740ad73550c76dee4a9578979d84af48James Smart		if (rlen > skb->len)
6484314fd4740ad73550c76dee4a9578979d84af48James Smart			rlen = skb->len;
6584314fd4740ad73550c76dee4a9578979d84af48James Smart
6684314fd4740ad73550c76dee4a9578979d84af48James Smart		if (nlh->nlmsg_type != SCSI_TRANSPORT_MSG) {
6784314fd4740ad73550c76dee4a9578979d84af48James Smart			err = -EBADMSG;
68cd40b7d3983c708aabe3d3008ec64ffce56d33b0Denis V. Lunev			return;
6984314fd4740ad73550c76dee4a9578979d84af48James Smart		}
7084314fd4740ad73550c76dee4a9578979d84af48James Smart
7184314fd4740ad73550c76dee4a9578979d84af48James Smart		hdr = NLMSG_DATA(nlh);
7284314fd4740ad73550c76dee4a9578979d84af48James Smart		if ((hdr->version != SCSI_NL_VERSION) ||
7384314fd4740ad73550c76dee4a9578979d84af48James Smart		    (hdr->magic != SCSI_NL_MAGIC)) {
7484314fd4740ad73550c76dee4a9578979d84af48James Smart			err = -EPROTOTYPE;
7584314fd4740ad73550c76dee4a9578979d84af48James Smart			goto next_msg;
7684314fd4740ad73550c76dee4a9578979d84af48James Smart		}
7784314fd4740ad73550c76dee4a9578979d84af48James Smart
7884314fd4740ad73550c76dee4a9578979d84af48James Smart		if (security_netlink_recv(skb, CAP_SYS_ADMIN)) {
7984314fd4740ad73550c76dee4a9578979d84af48James Smart			err = -EPERM;
8084314fd4740ad73550c76dee4a9578979d84af48James Smart			goto next_msg;
8184314fd4740ad73550c76dee4a9578979d84af48James Smart		}
8284314fd4740ad73550c76dee4a9578979d84af48James Smart
8384314fd4740ad73550c76dee4a9578979d84af48James Smart		if (nlh->nlmsg_len < (sizeof(*nlh) + hdr->msglen)) {
8484314fd4740ad73550c76dee4a9578979d84af48James Smart			printk(KERN_WARNING "%s: discarding partial message\n",
8584314fd4740ad73550c76dee4a9578979d84af48James Smart				 __FUNCTION__);
8684314fd4740ad73550c76dee4a9578979d84af48James Smart			return;
8784314fd4740ad73550c76dee4a9578979d84af48James Smart		}
8884314fd4740ad73550c76dee4a9578979d84af48James Smart
8984314fd4740ad73550c76dee4a9578979d84af48James Smart		/*
9084314fd4740ad73550c76dee4a9578979d84af48James Smart		 * We currently don't support anyone sending us a message
9184314fd4740ad73550c76dee4a9578979d84af48James Smart		 */
9284314fd4740ad73550c76dee4a9578979d84af48James Smart
9384314fd4740ad73550c76dee4a9578979d84af48James Smartnext_msg:
9484314fd4740ad73550c76dee4a9578979d84af48James Smart		if ((err) || (nlh->nlmsg_flags & NLM_F_ACK))
9584314fd4740ad73550c76dee4a9578979d84af48James Smart			netlink_ack(skb, nlh, err);
9684314fd4740ad73550c76dee4a9578979d84af48James Smart
9784314fd4740ad73550c76dee4a9578979d84af48James Smart		skb_pull(skb, rlen);
9884314fd4740ad73550c76dee4a9578979d84af48James Smart	}
9984314fd4740ad73550c76dee4a9578979d84af48James Smart}
10084314fd4740ad73550c76dee4a9578979d84af48James Smart
10184314fd4740ad73550c76dee4a9578979d84af48James Smart
10284314fd4740ad73550c76dee4a9578979d84af48James Smart/**
103eb44820c28bc9a042e1157b41c677018a8fdfc74Rob Landley * scsi_nl_rcv_event - Event handler for a netlink socket.
10484314fd4740ad73550c76dee4a9578979d84af48James Smart * @this:		event notifier block
10584314fd4740ad73550c76dee4a9578979d84af48James Smart * @event:		event type
10684314fd4740ad73550c76dee4a9578979d84af48James Smart * @ptr:		event payload
10784314fd4740ad73550c76dee4a9578979d84af48James Smart *
10884314fd4740ad73550c76dee4a9578979d84af48James Smart **/
10984314fd4740ad73550c76dee4a9578979d84af48James Smartstatic int
11084314fd4740ad73550c76dee4a9578979d84af48James Smartscsi_nl_rcv_event(struct notifier_block *this, unsigned long event, void *ptr)
11184314fd4740ad73550c76dee4a9578979d84af48James Smart{
11284314fd4740ad73550c76dee4a9578979d84af48James Smart	struct netlink_notify *n = ptr;
11384314fd4740ad73550c76dee4a9578979d84af48James Smart
11484314fd4740ad73550c76dee4a9578979d84af48James Smart	if (n->protocol != NETLINK_SCSITRANSPORT)
11584314fd4740ad73550c76dee4a9578979d84af48James Smart		return NOTIFY_DONE;
11684314fd4740ad73550c76dee4a9578979d84af48James Smart
11784314fd4740ad73550c76dee4a9578979d84af48James Smart	/*
11884314fd4740ad73550c76dee4a9578979d84af48James Smart	 * Currently, we are not tracking PID's, etc. There is nothing
11984314fd4740ad73550c76dee4a9578979d84af48James Smart	 * to handle.
12084314fd4740ad73550c76dee4a9578979d84af48James Smart	 */
12184314fd4740ad73550c76dee4a9578979d84af48James Smart
12284314fd4740ad73550c76dee4a9578979d84af48James Smart	return NOTIFY_DONE;
12384314fd4740ad73550c76dee4a9578979d84af48James Smart}
12484314fd4740ad73550c76dee4a9578979d84af48James Smart
12584314fd4740ad73550c76dee4a9578979d84af48James Smartstatic struct notifier_block scsi_netlink_notifier = {
12684314fd4740ad73550c76dee4a9578979d84af48James Smart	.notifier_call  = scsi_nl_rcv_event,
12784314fd4740ad73550c76dee4a9578979d84af48James Smart};
12884314fd4740ad73550c76dee4a9578979d84af48James Smart
12984314fd4740ad73550c76dee4a9578979d84af48James Smart
13084314fd4740ad73550c76dee4a9578979d84af48James Smart/**
131eb44820c28bc9a042e1157b41c677018a8fdfc74Rob Landley * scsi_netlink_init - Called by SCSI subsystem to intialize the SCSI transport netlink interface
13284314fd4740ad73550c76dee4a9578979d84af48James Smart *
13384314fd4740ad73550c76dee4a9578979d84af48James Smart **/
13484314fd4740ad73550c76dee4a9578979d84af48James Smartvoid
13584314fd4740ad73550c76dee4a9578979d84af48James Smartscsi_netlink_init(void)
13684314fd4740ad73550c76dee4a9578979d84af48James Smart{
13784314fd4740ad73550c76dee4a9578979d84af48James Smart	int error;
13884314fd4740ad73550c76dee4a9578979d84af48James Smart
13984314fd4740ad73550c76dee4a9578979d84af48James Smart	error = netlink_register_notifier(&scsi_netlink_notifier);
14084314fd4740ad73550c76dee4a9578979d84af48James Smart	if (error) {
14184314fd4740ad73550c76dee4a9578979d84af48James Smart		printk(KERN_ERR "%s: register of event handler failed - %d\n",
14284314fd4740ad73550c76dee4a9578979d84af48James Smart				__FUNCTION__, error);
14384314fd4740ad73550c76dee4a9578979d84af48James Smart		return;
14484314fd4740ad73550c76dee4a9578979d84af48James Smart	}
14584314fd4740ad73550c76dee4a9578979d84af48James Smart
146b4b510290b056b86611757ce1175a230f1080f53Eric W. Biederman	scsi_nl_sock = netlink_kernel_create(&init_net, NETLINK_SCSITRANSPORT,
147cd40b7d3983c708aabe3d3008ec64ffce56d33b0Denis V. Lunev				SCSI_NL_GRP_CNT, scsi_nl_rcv_msg, NULL,
148af65bdfce98d7965fbe93a48b8128444a2eea024Patrick McHardy				THIS_MODULE);
14984314fd4740ad73550c76dee4a9578979d84af48James Smart	if (!scsi_nl_sock) {
15084314fd4740ad73550c76dee4a9578979d84af48James Smart		printk(KERN_ERR "%s: register of recieve handler failed\n",
15184314fd4740ad73550c76dee4a9578979d84af48James Smart				__FUNCTION__);
15284314fd4740ad73550c76dee4a9578979d84af48James Smart		netlink_unregister_notifier(&scsi_netlink_notifier);
15384314fd4740ad73550c76dee4a9578979d84af48James Smart	}
15484314fd4740ad73550c76dee4a9578979d84af48James Smart
15584314fd4740ad73550c76dee4a9578979d84af48James Smart	return;
15684314fd4740ad73550c76dee4a9578979d84af48James Smart}
15784314fd4740ad73550c76dee4a9578979d84af48James Smart
15884314fd4740ad73550c76dee4a9578979d84af48James Smart
15984314fd4740ad73550c76dee4a9578979d84af48James Smart/**
160eb44820c28bc9a042e1157b41c677018a8fdfc74Rob Landley * scsi_netlink_exit - Called by SCSI subsystem to disable the SCSI transport netlink interface
16184314fd4740ad73550c76dee4a9578979d84af48James Smart *
16284314fd4740ad73550c76dee4a9578979d84af48James Smart **/
16384314fd4740ad73550c76dee4a9578979d84af48James Smartvoid
16484314fd4740ad73550c76dee4a9578979d84af48James Smartscsi_netlink_exit(void)
16584314fd4740ad73550c76dee4a9578979d84af48James Smart{
16684314fd4740ad73550c76dee4a9578979d84af48James Smart	if (scsi_nl_sock) {
16784314fd4740ad73550c76dee4a9578979d84af48James Smart		sock_release(scsi_nl_sock->sk_socket);
16884314fd4740ad73550c76dee4a9578979d84af48James Smart		netlink_unregister_notifier(&scsi_netlink_notifier);
16984314fd4740ad73550c76dee4a9578979d84af48James Smart	}
17084314fd4740ad73550c76dee4a9578979d84af48James Smart
17184314fd4740ad73550c76dee4a9578979d84af48James Smart	return;
17284314fd4740ad73550c76dee4a9578979d84af48James Smart}
17384314fd4740ad73550c76dee4a9578979d84af48James Smart
17484314fd4740ad73550c76dee4a9578979d84af48James Smart
175