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