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> 2422447be7d15aefcfab84e9bec4859a28198b0c62James Smart#include <linux/delay.h> 255a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 2609703660edf83b8b6d175440bf745f30580d85abPaul Gortmaker#include <linux/export.h> 2784314fd4740ad73550c76dee4a9578979d84af48James Smart#include <net/sock.h> 2884314fd4740ad73550c76dee4a9578979d84af48James Smart#include <net/netlink.h> 2984314fd4740ad73550c76dee4a9578979d84af48James Smart 3084314fd4740ad73550c76dee4a9578979d84af48James Smart#include <scsi/scsi_netlink.h> 3184314fd4740ad73550c76dee4a9578979d84af48James Smart#include "scsi_priv.h" 3284314fd4740ad73550c76dee4a9578979d84af48James Smart 3384314fd4740ad73550c76dee4a9578979d84af48James Smartstruct sock *scsi_nl_sock = NULL; 3484314fd4740ad73550c76dee4a9578979d84af48James SmartEXPORT_SYMBOL_GPL(scsi_nl_sock); 3584314fd4740ad73550c76dee4a9578979d84af48James Smart 3684314fd4740ad73550c76dee4a9578979d84af48James Smart/** 37eb44820c28bc9a042e1157b41c677018a8fdfc74Rob Landley * scsi_nl_rcv_msg - Receive message handler. 38eb44820c28bc9a042e1157b41c677018a8fdfc74Rob Landley * @skb: socket receive buffer 39eb44820c28bc9a042e1157b41c677018a8fdfc74Rob Landley * 40eb44820c28bc9a042e1157b41c677018a8fdfc74Rob Landley * Description: Extracts message from a receive buffer. 4184314fd4740ad73550c76dee4a9578979d84af48James Smart * Validates message header and calls appropriate transport message handler 4284314fd4740ad73550c76dee4a9578979d84af48James Smart * 4384314fd4740ad73550c76dee4a9578979d84af48James Smart * 4484314fd4740ad73550c76dee4a9578979d84af48James Smart **/ 4584314fd4740ad73550c76dee4a9578979d84af48James Smartstatic void 4684314fd4740ad73550c76dee4a9578979d84af48James Smartscsi_nl_rcv_msg(struct sk_buff *skb) 4784314fd4740ad73550c76dee4a9578979d84af48James Smart{ 4884314fd4740ad73550c76dee4a9578979d84af48James Smart struct nlmsghdr *nlh; 4984314fd4740ad73550c76dee4a9578979d84af48James Smart struct scsi_nl_hdr *hdr; 5022447be7d15aefcfab84e9bec4859a28198b0c62James Smart u32 rlen; 5122447be7d15aefcfab84e9bec4859a28198b0c62James Smart int err, tport; 5284314fd4740ad73550c76dee4a9578979d84af48James Smart 53e07ebea0ccfaf627464460eb57d7f2fdbcccf8ecHong zhi guo while (skb->len >= NLMSG_HDRLEN) { 5484314fd4740ad73550c76dee4a9578979d84af48James Smart err = 0; 5584314fd4740ad73550c76dee4a9578979d84af48James Smart 56b529ccf2799c14346d1518e9bdf1f88f03643e99Arnaldo Carvalho de Melo nlh = nlmsg_hdr(skb); 5784314fd4740ad73550c76dee4a9578979d84af48James Smart if ((nlh->nlmsg_len < (sizeof(*nlh) + sizeof(*hdr))) || 5884314fd4740ad73550c76dee4a9578979d84af48James Smart (skb->len < nlh->nlmsg_len)) { 5984314fd4740ad73550c76dee4a9578979d84af48James Smart printk(KERN_WARNING "%s: discarding partial skb\n", 60cadbd4a5e36dde7e6c49b587b2c419103c0b7218Harvey Harrison __func__); 6184314fd4740ad73550c76dee4a9578979d84af48James Smart return; 6284314fd4740ad73550c76dee4a9578979d84af48James Smart } 6384314fd4740ad73550c76dee4a9578979d84af48James Smart 6484314fd4740ad73550c76dee4a9578979d84af48James Smart rlen = NLMSG_ALIGN(nlh->nlmsg_len); 6584314fd4740ad73550c76dee4a9578979d84af48James Smart if (rlen > skb->len) 6684314fd4740ad73550c76dee4a9578979d84af48James Smart rlen = skb->len; 6784314fd4740ad73550c76dee4a9578979d84af48James Smart 6884314fd4740ad73550c76dee4a9578979d84af48James Smart if (nlh->nlmsg_type != SCSI_TRANSPORT_MSG) { 6984314fd4740ad73550c76dee4a9578979d84af48James Smart err = -EBADMSG; 7022447be7d15aefcfab84e9bec4859a28198b0c62James Smart goto next_msg; 7184314fd4740ad73550c76dee4a9578979d84af48James Smart } 7284314fd4740ad73550c76dee4a9578979d84af48James Smart 73e07ebea0ccfaf627464460eb57d7f2fdbcccf8ecHong zhi guo hdr = nlmsg_data(nlh); 7484314fd4740ad73550c76dee4a9578979d84af48James Smart if ((hdr->version != SCSI_NL_VERSION) || 7584314fd4740ad73550c76dee4a9578979d84af48James Smart (hdr->magic != SCSI_NL_MAGIC)) { 7684314fd4740ad73550c76dee4a9578979d84af48James Smart err = -EPROTOTYPE; 7784314fd4740ad73550c76dee4a9578979d84af48James Smart goto next_msg; 7884314fd4740ad73550c76dee4a9578979d84af48James Smart } 7984314fd4740ad73550c76dee4a9578979d84af48James Smart 8090f62cf30a78721641e08737bda787552428061eEric W. Biederman if (!netlink_capable(skb, CAP_SYS_ADMIN)) { 8184314fd4740ad73550c76dee4a9578979d84af48James Smart err = -EPERM; 8284314fd4740ad73550c76dee4a9578979d84af48James Smart goto next_msg; 8384314fd4740ad73550c76dee4a9578979d84af48James Smart } 8484314fd4740ad73550c76dee4a9578979d84af48James Smart 8584314fd4740ad73550c76dee4a9578979d84af48James Smart if (nlh->nlmsg_len < (sizeof(*nlh) + hdr->msglen)) { 8684314fd4740ad73550c76dee4a9578979d84af48James Smart printk(KERN_WARNING "%s: discarding partial message\n", 87cadbd4a5e36dde7e6c49b587b2c419103c0b7218Harvey Harrison __func__); 8822447be7d15aefcfab84e9bec4859a28198b0c62James Smart goto next_msg; 8984314fd4740ad73550c76dee4a9578979d84af48James Smart } 9084314fd4740ad73550c76dee4a9578979d84af48James Smart 9184314fd4740ad73550c76dee4a9578979d84af48James Smart /* 9222447be7d15aefcfab84e9bec4859a28198b0c62James Smart * Deliver message to the appropriate transport 9384314fd4740ad73550c76dee4a9578979d84af48James Smart */ 9422447be7d15aefcfab84e9bec4859a28198b0c62James Smart tport = hdr->transport; 958289bab1daf9768c20114051a99c1bd5f48d4420Eric W. Biederman if (tport == SCSI_NL_TRANSPORT) { 968289bab1daf9768c20114051a99c1bd5f48d4420Eric W. Biederman switch (hdr->msgtype) { 978289bab1daf9768c20114051a99c1bd5f48d4420Eric W. Biederman case SCSI_NL_SHOST_VENDOR: 988289bab1daf9768c20114051a99c1bd5f48d4420Eric W. Biederman /* Locate the driver that corresponds to the message */ 998289bab1daf9768c20114051a99c1bd5f48d4420Eric W. Biederman err = -ESRCH; 1008289bab1daf9768c20114051a99c1bd5f48d4420Eric W. Biederman break; 1018289bab1daf9768c20114051a99c1bd5f48d4420Eric W. Biederman default: 1028289bab1daf9768c20114051a99c1bd5f48d4420Eric W. Biederman err = -EBADR; 1038289bab1daf9768c20114051a99c1bd5f48d4420Eric W. Biederman break; 1048289bab1daf9768c20114051a99c1bd5f48d4420Eric W. Biederman } 1058289bab1daf9768c20114051a99c1bd5f48d4420Eric W. Biederman if (err) 1068289bab1daf9768c20114051a99c1bd5f48d4420Eric W. Biederman printk(KERN_WARNING "%s: Msgtype %d failed - err %d\n", 1078289bab1daf9768c20114051a99c1bd5f48d4420Eric W. Biederman __func__, hdr->msgtype, err); 1088289bab1daf9768c20114051a99c1bd5f48d4420Eric W. Biederman } 1098289bab1daf9768c20114051a99c1bd5f48d4420Eric W. Biederman else 11022447be7d15aefcfab84e9bec4859a28198b0c62James Smart err = -ENOENT; 11122447be7d15aefcfab84e9bec4859a28198b0c62James Smart 11284314fd4740ad73550c76dee4a9578979d84af48James Smartnext_msg: 11384314fd4740ad73550c76dee4a9578979d84af48James Smart if ((err) || (nlh->nlmsg_flags & NLM_F_ACK)) 11484314fd4740ad73550c76dee4a9578979d84af48James Smart netlink_ack(skb, nlh, err); 11584314fd4740ad73550c76dee4a9578979d84af48James Smart 11684314fd4740ad73550c76dee4a9578979d84af48James Smart skb_pull(skb, rlen); 11784314fd4740ad73550c76dee4a9578979d84af48James Smart } 11884314fd4740ad73550c76dee4a9578979d84af48James Smart} 11984314fd4740ad73550c76dee4a9578979d84af48James Smart 12022447be7d15aefcfab84e9bec4859a28198b0c62James Smart/** 121b595076a180a56d1bb170e6eceda6eb9d76f4cd3Uwe Kleine-König * scsi_netlink_init - Called by SCSI subsystem to initialize 12222447be7d15aefcfab84e9bec4859a28198b0c62James Smart * the SCSI transport netlink interface 12384314fd4740ad73550c76dee4a9578979d84af48James Smart * 12484314fd4740ad73550c76dee4a9578979d84af48James Smart **/ 12584314fd4740ad73550c76dee4a9578979d84af48James Smartvoid 12684314fd4740ad73550c76dee4a9578979d84af48James Smartscsi_netlink_init(void) 12784314fd4740ad73550c76dee4a9578979d84af48James Smart{ 128a31f2d17b331db970259e875b7223d3aba7e3821Pablo Neira Ayuso struct netlink_kernel_cfg cfg = { 129a31f2d17b331db970259e875b7223d3aba7e3821Pablo Neira Ayuso .input = scsi_nl_rcv_msg, 130a31f2d17b331db970259e875b7223d3aba7e3821Pablo Neira Ayuso .groups = SCSI_NL_GRP_CNT, 131a31f2d17b331db970259e875b7223d3aba7e3821Pablo Neira Ayuso }; 13284314fd4740ad73550c76dee4a9578979d84af48James Smart 133b4b510290b056b86611757ce1175a230f1080f53Eric W. Biederman scsi_nl_sock = netlink_kernel_create(&init_net, NETLINK_SCSITRANSPORT, 1349f00d9776bc5beb92e8bfc884a7e96ddc5589e2ePablo Neira Ayuso &cfg); 13584314fd4740ad73550c76dee4a9578979d84af48James Smart if (!scsi_nl_sock) { 13625985edcedea6396277003854657b5f3cb31a628Lucas De Marchi printk(KERN_ERR "%s: register of receive handler failed\n", 137cadbd4a5e36dde7e6c49b587b2c419103c0b7218Harvey Harrison __func__); 13822447be7d15aefcfab84e9bec4859a28198b0c62James Smart return; 13984314fd4740ad73550c76dee4a9578979d84af48James Smart } 14084314fd4740ad73550c76dee4a9578979d84af48James Smart 14184314fd4740ad73550c76dee4a9578979d84af48James Smart return; 14284314fd4740ad73550c76dee4a9578979d84af48James Smart} 14384314fd4740ad73550c76dee4a9578979d84af48James Smart 14484314fd4740ad73550c76dee4a9578979d84af48James Smart 14584314fd4740ad73550c76dee4a9578979d84af48James Smart/** 146eb44820c28bc9a042e1157b41c677018a8fdfc74Rob Landley * scsi_netlink_exit - Called by SCSI subsystem to disable the SCSI transport netlink interface 14784314fd4740ad73550c76dee4a9578979d84af48James Smart * 14884314fd4740ad73550c76dee4a9578979d84af48James Smart **/ 14984314fd4740ad73550c76dee4a9578979d84af48James Smartvoid 15084314fd4740ad73550c76dee4a9578979d84af48James Smartscsi_netlink_exit(void) 15184314fd4740ad73550c76dee4a9578979d84af48James Smart{ 15284314fd4740ad73550c76dee4a9578979d84af48James Smart if (scsi_nl_sock) { 153b7c6ba6eb1234e35a74fb8ba8123232a7b1ba9e4Denis V. Lunev netlink_kernel_release(scsi_nl_sock); 15484314fd4740ad73550c76dee4a9578979d84af48James Smart } 15584314fd4740ad73550c76dee4a9578979d84af48James Smart 15684314fd4740ad73550c76dee4a9578979d84af48James Smart return; 15784314fd4740ad73550c76dee4a9578979d84af48James Smart} 15884314fd4740ad73550c76dee4a9578979d84af48James Smart 159