Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  scsi_netlink.c  - SCSI Transport Netlink Interface
0004  *
0005  *  Copyright (C) 2006   James Smart, Emulex Corporation
0006  */
0007 #include <linux/time.h>
0008 #include <linux/jiffies.h>
0009 #include <linux/security.h>
0010 #include <linux/delay.h>
0011 #include <linux/slab.h>
0012 #include <linux/export.h>
0013 #include <net/sock.h>
0014 #include <net/netlink.h>
0015 
0016 #include <scsi/scsi_netlink.h>
0017 #include "scsi_priv.h"
0018 
0019 struct sock *scsi_nl_sock = NULL;
0020 EXPORT_SYMBOL_GPL(scsi_nl_sock);
0021 
0022 /**
0023  * scsi_nl_rcv_msg - Receive message handler.
0024  * @skb:        socket receive buffer
0025  *
0026  * Description: Extracts message from a receive buffer.
0027  *    Validates message header and calls appropriate transport message handler
0028  *
0029  *
0030  **/
0031 static void
0032 scsi_nl_rcv_msg(struct sk_buff *skb)
0033 {
0034     struct nlmsghdr *nlh;
0035     struct scsi_nl_hdr *hdr;
0036     u32 rlen;
0037     int err, tport;
0038 
0039     while (skb->len >= NLMSG_HDRLEN) {
0040         err = 0;
0041 
0042         nlh = nlmsg_hdr(skb);
0043         if ((nlh->nlmsg_len < (sizeof(*nlh) + sizeof(*hdr))) ||
0044             (skb->len < nlh->nlmsg_len)) {
0045             printk(KERN_WARNING "%s: discarding partial skb\n",
0046                  __func__);
0047             return;
0048         }
0049 
0050         rlen = NLMSG_ALIGN(nlh->nlmsg_len);
0051         if (rlen > skb->len)
0052             rlen = skb->len;
0053 
0054         if (nlh->nlmsg_type != SCSI_TRANSPORT_MSG) {
0055             err = -EBADMSG;
0056             goto next_msg;
0057         }
0058 
0059         hdr = nlmsg_data(nlh);
0060         if ((hdr->version != SCSI_NL_VERSION) ||
0061             (hdr->magic != SCSI_NL_MAGIC)) {
0062             err = -EPROTOTYPE;
0063             goto next_msg;
0064         }
0065 
0066         if (!netlink_capable(skb, CAP_SYS_ADMIN)) {
0067             err = -EPERM;
0068             goto next_msg;
0069         }
0070 
0071         if (nlh->nlmsg_len < (sizeof(*nlh) + hdr->msglen)) {
0072             printk(KERN_WARNING "%s: discarding partial message\n",
0073                  __func__);
0074             goto next_msg;
0075         }
0076 
0077         /*
0078          * Deliver message to the appropriate transport
0079          */
0080         tport = hdr->transport;
0081         if (tport == SCSI_NL_TRANSPORT) {
0082             switch (hdr->msgtype) {
0083             case SCSI_NL_SHOST_VENDOR:
0084                 /* Locate the driver that corresponds to the message */
0085                 err = -ESRCH;
0086                 break;
0087             default:
0088                 err = -EBADR;
0089                 break;
0090             }
0091             if (err)
0092                 printk(KERN_WARNING "%s: Msgtype %d failed - err %d\n",
0093                        __func__, hdr->msgtype, err);
0094         }
0095         else
0096             err = -ENOENT;
0097 
0098 next_msg:
0099         if ((err) || (nlh->nlmsg_flags & NLM_F_ACK))
0100             netlink_ack(skb, nlh, err, NULL);
0101 
0102         skb_pull(skb, rlen);
0103     }
0104 }
0105 
0106 /**
0107  * scsi_netlink_init - Called by SCSI subsystem to initialize
0108  *  the SCSI transport netlink interface
0109  *
0110  **/
0111 void
0112 scsi_netlink_init(void)
0113 {
0114     struct netlink_kernel_cfg cfg = {
0115         .input  = scsi_nl_rcv_msg,
0116         .groups = SCSI_NL_GRP_CNT,
0117     };
0118 
0119     scsi_nl_sock = netlink_kernel_create(&init_net, NETLINK_SCSITRANSPORT,
0120                          &cfg);
0121     if (!scsi_nl_sock) {
0122         printk(KERN_ERR "%s: register of receive handler failed\n",
0123                 __func__);
0124         return;
0125     }
0126 
0127     return;
0128 }
0129 
0130 
0131 /**
0132  * scsi_netlink_exit - Called by SCSI subsystem to disable the SCSI transport netlink interface
0133  *
0134  **/
0135 void
0136 scsi_netlink_exit(void)
0137 {
0138     if (scsi_nl_sock) {
0139         netlink_kernel_release(scsi_nl_sock);
0140     }
0141 
0142     return;
0143 }
0144