^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright Samuel Mendoza-Jonas, IBM Corporation 2018.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/if_arp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/rtnetlink.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/etherdevice.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <net/genetlink.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <net/ncsi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/skbuff.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <net/sock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <uapi/linux/ncsi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include "internal.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include "ncsi-pkt.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include "ncsi-netlink.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) static struct genl_family ncsi_genl_family;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) static const struct nla_policy ncsi_genl_policy[NCSI_ATTR_MAX + 1] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) [NCSI_ATTR_IFINDEX] = { .type = NLA_U32 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) [NCSI_ATTR_PACKAGE_LIST] = { .type = NLA_NESTED },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) [NCSI_ATTR_PACKAGE_ID] = { .type = NLA_U32 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) [NCSI_ATTR_CHANNEL_ID] = { .type = NLA_U32 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) [NCSI_ATTR_DATA] = { .type = NLA_BINARY, .len = 2048 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) [NCSI_ATTR_MULTI_FLAG] = { .type = NLA_FLAG },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) [NCSI_ATTR_PACKAGE_MASK] = { .type = NLA_U32 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) [NCSI_ATTR_CHANNEL_MASK] = { .type = NLA_U32 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) static struct ncsi_dev_priv *ndp_from_ifindex(struct net *net, u32 ifindex)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) struct ncsi_dev_priv *ndp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) struct net_device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) struct ncsi_dev *nd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) struct ncsi_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) if (!net)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) dev = dev_get_by_index(net, ifindex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) if (!dev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) pr_err("NCSI netlink: No device for ifindex %u\n", ifindex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) nd = ncsi_find_dev(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) ndp = nd ? TO_NCSI_DEV_PRIV(nd) : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) dev_put(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) return ndp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) static int ncsi_write_channel_info(struct sk_buff *skb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) struct ncsi_dev_priv *ndp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) struct ncsi_channel *nc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) struct ncsi_channel_vlan_filter *ncf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) struct ncsi_channel_mode *m;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) struct nlattr *vid_nest;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) nla_put_u32(skb, NCSI_CHANNEL_ATTR_ID, nc->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) m = &nc->modes[NCSI_MODE_LINK];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) nla_put_u32(skb, NCSI_CHANNEL_ATTR_LINK_STATE, m->data[2]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) if (nc->state == NCSI_CHANNEL_ACTIVE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) nla_put_flag(skb, NCSI_CHANNEL_ATTR_ACTIVE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) if (nc == nc->package->preferred_channel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) nla_put_flag(skb, NCSI_CHANNEL_ATTR_FORCED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) nla_put_u32(skb, NCSI_CHANNEL_ATTR_VERSION_MAJOR, nc->version.version);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) nla_put_u32(skb, NCSI_CHANNEL_ATTR_VERSION_MINOR, nc->version.alpha2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) nla_put_string(skb, NCSI_CHANNEL_ATTR_VERSION_STR, nc->version.fw_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) vid_nest = nla_nest_start_noflag(skb, NCSI_CHANNEL_ATTR_VLAN_LIST);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) if (!vid_nest)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) ncf = &nc->vlan_filter;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) i = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) while ((i = find_next_bit((void *)&ncf->bitmap, ncf->n_vids,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) i + 1)) < ncf->n_vids) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) if (ncf->vids[i])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) nla_put_u16(skb, NCSI_CHANNEL_ATTR_VLAN_ID,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) ncf->vids[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) nla_nest_end(skb, vid_nest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) static int ncsi_write_package_info(struct sk_buff *skb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) struct ncsi_dev_priv *ndp, unsigned int id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) struct nlattr *pnest, *cnest, *nest;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) struct ncsi_package *np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) struct ncsi_channel *nc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) bool found;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) if (id > ndp->package_num - 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) netdev_info(ndp->ndev.dev, "NCSI: No package with id %u\n", id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) found = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) NCSI_FOR_EACH_PACKAGE(ndp, np) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) if (np->id != id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) pnest = nla_nest_start_noflag(skb, NCSI_PKG_ATTR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) if (!pnest)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) rc = nla_put_u32(skb, NCSI_PKG_ATTR_ID, np->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) nla_nest_cancel(skb, pnest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) if ((0x1 << np->id) == ndp->package_whitelist)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) nla_put_flag(skb, NCSI_PKG_ATTR_FORCED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) cnest = nla_nest_start_noflag(skb, NCSI_PKG_ATTR_CHANNEL_LIST);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) if (!cnest) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) nla_nest_cancel(skb, pnest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) NCSI_FOR_EACH_CHANNEL(np, nc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) nest = nla_nest_start_noflag(skb, NCSI_CHANNEL_ATTR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) if (!nest) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) nla_nest_cancel(skb, cnest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) nla_nest_cancel(skb, pnest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) rc = ncsi_write_channel_info(skb, ndp, nc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) nla_nest_cancel(skb, nest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) nla_nest_cancel(skb, cnest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) nla_nest_cancel(skb, pnest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) nla_nest_end(skb, nest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) nla_nest_end(skb, cnest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) nla_nest_end(skb, pnest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) found = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) if (!found)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) static int ncsi_pkg_info_nl(struct sk_buff *msg, struct genl_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) struct ncsi_dev_priv *ndp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) unsigned int package_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) struct sk_buff *skb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) struct nlattr *attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) void *hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) if (!info || !info->attrs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) if (!info->attrs[NCSI_ATTR_IFINDEX])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) if (!info->attrs[NCSI_ATTR_PACKAGE_ID])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) ndp = ndp_from_ifindex(genl_info_net(info),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) if (!ndp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) if (!skb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) &ncsi_genl_family, 0, NCSI_CMD_PKG_INFO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) if (!hdr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) kfree_skb(skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) return -EMSGSIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) package_id = nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_ID]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) attr = nla_nest_start_noflag(skb, NCSI_ATTR_PACKAGE_LIST);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) if (!attr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) kfree_skb(skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) return -EMSGSIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) rc = ncsi_write_package_info(skb, ndp, package_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) nla_nest_cancel(skb, attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) nla_nest_end(skb, attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) genlmsg_end(skb, hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) return genlmsg_reply(skb, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) kfree_skb(skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) static int ncsi_pkg_info_all_nl(struct sk_buff *skb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) struct netlink_callback *cb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) struct nlattr *attrs[NCSI_ATTR_MAX + 1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) struct ncsi_package *np, *package;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) struct ncsi_dev_priv *ndp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) unsigned int package_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) struct nlattr *attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) void *hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) rc = genlmsg_parse_deprecated(cb->nlh, &ncsi_genl_family, attrs, NCSI_ATTR_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) ncsi_genl_policy, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) if (!attrs[NCSI_ATTR_IFINDEX])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) ndp = ndp_from_ifindex(get_net(sock_net(skb->sk)),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) nla_get_u32(attrs[NCSI_ATTR_IFINDEX]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) if (!ndp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) package_id = cb->args[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) package = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) NCSI_FOR_EACH_PACKAGE(ndp, np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) if (np->id == package_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) package = np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) if (!package)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) return 0; /* done */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) &ncsi_genl_family, NLM_F_MULTI, NCSI_CMD_PKG_INFO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) if (!hdr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) rc = -EMSGSIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) attr = nla_nest_start_noflag(skb, NCSI_ATTR_PACKAGE_LIST);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) if (!attr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) rc = -EMSGSIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) rc = ncsi_write_package_info(skb, ndp, package->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) nla_nest_cancel(skb, attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) nla_nest_end(skb, attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) genlmsg_end(skb, hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) cb->args[0] = package_id + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) return skb->len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) genlmsg_cancel(skb, hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) static int ncsi_set_interface_nl(struct sk_buff *msg, struct genl_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) struct ncsi_package *np, *package;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) struct ncsi_channel *nc, *channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) u32 package_id, channel_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) struct ncsi_dev_priv *ndp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) if (!info || !info->attrs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) if (!info->attrs[NCSI_ATTR_IFINDEX])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) if (!info->attrs[NCSI_ATTR_PACKAGE_ID])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) ndp = ndp_from_ifindex(get_net(sock_net(msg->sk)),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) if (!ndp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) package_id = nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_ID]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) package = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) NCSI_FOR_EACH_PACKAGE(ndp, np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) if (np->id == package_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) package = np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) if (!package) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) /* The user has set a package that does not exist */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) return -ERANGE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) channel = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) if (info->attrs[NCSI_ATTR_CHANNEL_ID]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) channel_id = nla_get_u32(info->attrs[NCSI_ATTR_CHANNEL_ID]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) NCSI_FOR_EACH_CHANNEL(package, nc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) if (nc->id == channel_id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) channel = nc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) if (!channel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) netdev_info(ndp->ndev.dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) "NCSI: Channel %u does not exist!\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) channel_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) return -ERANGE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) spin_lock_irqsave(&ndp->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) ndp->package_whitelist = 0x1 << package->id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) ndp->multi_package = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) spin_unlock_irqrestore(&ndp->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) spin_lock_irqsave(&package->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) package->multi_channel = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) if (channel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) package->channel_whitelist = 0x1 << channel->id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) package->preferred_channel = channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) /* Allow any channel */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) package->channel_whitelist = UINT_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) package->preferred_channel = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) spin_unlock_irqrestore(&package->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) if (channel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) netdev_info(ndp->ndev.dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) "Set package 0x%x, channel 0x%x as preferred\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) package_id, channel_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) netdev_info(ndp->ndev.dev, "Set package 0x%x as preferred\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) package_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) /* Update channel configuration */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) if (!(ndp->flags & NCSI_DEV_RESET))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) ncsi_reset_dev(&ndp->ndev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) static int ncsi_clear_interface_nl(struct sk_buff *msg, struct genl_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) struct ncsi_dev_priv *ndp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) struct ncsi_package *np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) if (!info || !info->attrs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) if (!info->attrs[NCSI_ATTR_IFINDEX])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) ndp = ndp_from_ifindex(get_net(sock_net(msg->sk)),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) if (!ndp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) /* Reset any whitelists and disable multi mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) spin_lock_irqsave(&ndp->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) ndp->package_whitelist = UINT_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) ndp->multi_package = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) spin_unlock_irqrestore(&ndp->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) NCSI_FOR_EACH_PACKAGE(ndp, np) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) spin_lock_irqsave(&np->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) np->multi_channel = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) np->channel_whitelist = UINT_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) np->preferred_channel = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) spin_unlock_irqrestore(&np->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) netdev_info(ndp->ndev.dev, "NCSI: Cleared preferred package/channel\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) /* Update channel configuration */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) if (!(ndp->flags & NCSI_DEV_RESET))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) ncsi_reset_dev(&ndp->ndev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) static int ncsi_send_cmd_nl(struct sk_buff *msg, struct genl_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) struct ncsi_dev_priv *ndp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) struct ncsi_pkt_hdr *hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) struct ncsi_cmd_arg nca;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) unsigned char *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) u32 package_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) u32 channel_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) int len, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) if (!info || !info->attrs) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) if (!info->attrs[NCSI_ATTR_IFINDEX]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) if (!info->attrs[NCSI_ATTR_PACKAGE_ID]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) if (!info->attrs[NCSI_ATTR_CHANNEL_ID]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) if (!info->attrs[NCSI_ATTR_DATA]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) ndp = ndp_from_ifindex(get_net(sock_net(msg->sk)),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) if (!ndp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) package_id = nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_ID]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) channel_id = nla_get_u32(info->attrs[NCSI_ATTR_CHANNEL_ID]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) if (package_id >= NCSI_MAX_PACKAGE || channel_id >= NCSI_MAX_CHANNEL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) ret = -ERANGE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) goto out_netlink;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) len = nla_len(info->attrs[NCSI_ATTR_DATA]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) if (len < sizeof(struct ncsi_pkt_hdr)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) netdev_info(ndp->ndev.dev, "NCSI: no command to send %u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) package_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) goto out_netlink;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) data = (unsigned char *)nla_data(info->attrs[NCSI_ATTR_DATA]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) hdr = (struct ncsi_pkt_hdr *)data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) nca.ndp = ndp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) nca.package = (unsigned char)package_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) nca.channel = (unsigned char)channel_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) nca.type = hdr->type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) nca.req_flags = NCSI_REQ_FLAG_NETLINK_DRIVEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) nca.info = info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) nca.payload = ntohs(hdr->length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) nca.data = data + sizeof(*hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) ret = ncsi_xmit_cmd(&nca);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) out_netlink:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) if (ret != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) netdev_err(ndp->ndev.dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) "NCSI: Error %d sending command\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) ncsi_send_netlink_err(ndp->ndev.dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) info->snd_seq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) info->snd_portid,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) info->nlhdr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) int ncsi_send_netlink_rsp(struct ncsi_request *nr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) struct ncsi_package *np,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) struct ncsi_channel *nc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) struct sk_buff *skb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) struct net *net;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) void *hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) net = dev_net(nr->rsp->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) if (!skb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) hdr = genlmsg_put(skb, nr->snd_portid, nr->snd_seq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) &ncsi_genl_family, 0, NCSI_CMD_SEND_CMD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) if (!hdr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) kfree_skb(skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) return -EMSGSIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) nla_put_u32(skb, NCSI_ATTR_IFINDEX, nr->rsp->dev->ifindex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) if (np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) nla_put_u32(skb, NCSI_ATTR_PACKAGE_ID, np->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) if (nc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) nla_put_u32(skb, NCSI_ATTR_CHANNEL_ID, nc->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) nla_put_u32(skb, NCSI_ATTR_CHANNEL_ID, NCSI_RESERVED_CHANNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) rc = nla_put(skb, NCSI_ATTR_DATA, nr->rsp->len, (void *)nr->rsp->data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) genlmsg_end(skb, hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) return genlmsg_unicast(net, skb, nr->snd_portid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) kfree_skb(skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) int ncsi_send_netlink_timeout(struct ncsi_request *nr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) struct ncsi_package *np,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) struct ncsi_channel *nc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) struct sk_buff *skb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) struct net *net;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) void *hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) if (!skb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) hdr = genlmsg_put(skb, nr->snd_portid, nr->snd_seq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) &ncsi_genl_family, 0, NCSI_CMD_SEND_CMD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) if (!hdr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) kfree_skb(skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) return -EMSGSIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) net = dev_net(nr->cmd->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) nla_put_u32(skb, NCSI_ATTR_IFINDEX, nr->cmd->dev->ifindex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) if (np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) nla_put_u32(skb, NCSI_ATTR_PACKAGE_ID, np->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) nla_put_u32(skb, NCSI_ATTR_PACKAGE_ID,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) NCSI_PACKAGE_INDEX((((struct ncsi_pkt_hdr *)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) nr->cmd->data)->channel)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) if (nc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) nla_put_u32(skb, NCSI_ATTR_CHANNEL_ID, nc->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) nla_put_u32(skb, NCSI_ATTR_CHANNEL_ID, NCSI_RESERVED_CHANNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) genlmsg_end(skb, hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) return genlmsg_unicast(net, skb, nr->snd_portid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) int ncsi_send_netlink_err(struct net_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) u32 snd_seq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) u32 snd_portid,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) struct nlmsghdr *nlhdr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) int err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) struct nlmsghdr *nlh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) struct nlmsgerr *nle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) struct sk_buff *skb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) struct net *net;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) if (!skb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) net = dev_net(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) nlh = nlmsg_put(skb, snd_portid, snd_seq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) NLMSG_ERROR, sizeof(*nle), 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) nle = (struct nlmsgerr *)nlmsg_data(nlh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) nle->error = err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) memcpy(&nle->msg, nlhdr, sizeof(*nlh));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) nlmsg_end(skb, nlh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) return nlmsg_unicast(net->genl_sock, skb, snd_portid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) static int ncsi_set_package_mask_nl(struct sk_buff *msg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) struct genl_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) struct ncsi_dev_priv *ndp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) if (!info || !info->attrs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) if (!info->attrs[NCSI_ATTR_IFINDEX])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) if (!info->attrs[NCSI_ATTR_PACKAGE_MASK])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) ndp = ndp_from_ifindex(get_net(sock_net(msg->sk)),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) if (!ndp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) spin_lock_irqsave(&ndp->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) if (nla_get_flag(info->attrs[NCSI_ATTR_MULTI_FLAG])) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) if (ndp->flags & NCSI_DEV_HWA) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) ndp->multi_package = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) rc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) netdev_err(ndp->ndev.dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) "NCSI: Can't use multiple packages without HWA\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) rc = -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) ndp->multi_package = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) rc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) if (!rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) ndp->package_whitelist =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_MASK]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) spin_unlock_irqrestore(&ndp->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) if (!rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) /* Update channel configuration */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) if (!(ndp->flags & NCSI_DEV_RESET))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) ncsi_reset_dev(&ndp->ndev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) static int ncsi_set_channel_mask_nl(struct sk_buff *msg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) struct genl_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) struct ncsi_package *np, *package;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) struct ncsi_channel *nc, *channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) u32 package_id, channel_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) struct ncsi_dev_priv *ndp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) if (!info || !info->attrs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) if (!info->attrs[NCSI_ATTR_IFINDEX])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) if (!info->attrs[NCSI_ATTR_PACKAGE_ID])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) if (!info->attrs[NCSI_ATTR_CHANNEL_MASK])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) ndp = ndp_from_ifindex(get_net(sock_net(msg->sk)),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) if (!ndp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) package_id = nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_ID]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) package = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) NCSI_FOR_EACH_PACKAGE(ndp, np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) if (np->id == package_id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) package = np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) if (!package)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) return -ERANGE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) spin_lock_irqsave(&package->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) channel = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) if (info->attrs[NCSI_ATTR_CHANNEL_ID]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) channel_id = nla_get_u32(info->attrs[NCSI_ATTR_CHANNEL_ID]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) NCSI_FOR_EACH_CHANNEL(np, nc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) if (nc->id == channel_id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) channel = nc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) if (!channel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) spin_unlock_irqrestore(&package->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) return -ERANGE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) netdev_dbg(ndp->ndev.dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) "NCSI: Channel %u set as preferred channel\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) channel->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) package->channel_whitelist =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) nla_get_u32(info->attrs[NCSI_ATTR_CHANNEL_MASK]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) if (package->channel_whitelist == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) netdev_dbg(ndp->ndev.dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) "NCSI: Package %u set to all channels disabled\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) package->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) package->preferred_channel = channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) if (nla_get_flag(info->attrs[NCSI_ATTR_MULTI_FLAG])) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) package->multi_channel = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) netdev_info(ndp->ndev.dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) "NCSI: Multi-channel enabled on package %u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) package_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) package->multi_channel = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) spin_unlock_irqrestore(&package->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) /* Update channel configuration */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) if (!(ndp->flags & NCSI_DEV_RESET))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) ncsi_reset_dev(&ndp->ndev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) static const struct genl_small_ops ncsi_ops[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) .cmd = NCSI_CMD_PKG_INFO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) .doit = ncsi_pkg_info_nl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) .dumpit = ncsi_pkg_info_all_nl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) .flags = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) .cmd = NCSI_CMD_SET_INTERFACE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) .doit = ncsi_set_interface_nl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) .flags = GENL_ADMIN_PERM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) .cmd = NCSI_CMD_CLEAR_INTERFACE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) .doit = ncsi_clear_interface_nl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) .flags = GENL_ADMIN_PERM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) .cmd = NCSI_CMD_SEND_CMD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) .doit = ncsi_send_cmd_nl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) .flags = GENL_ADMIN_PERM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) .cmd = NCSI_CMD_SET_PACKAGE_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) .doit = ncsi_set_package_mask_nl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) .flags = GENL_ADMIN_PERM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) .cmd = NCSI_CMD_SET_CHANNEL_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) .doit = ncsi_set_channel_mask_nl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) .flags = GENL_ADMIN_PERM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) static struct genl_family ncsi_genl_family __ro_after_init = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) .name = "NCSI",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) .version = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) .maxattr = NCSI_ATTR_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) .policy = ncsi_genl_policy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) .module = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) .small_ops = ncsi_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) .n_small_ops = ARRAY_SIZE(ncsi_ops),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) static int __init ncsi_init_netlink(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) return genl_register_family(&ncsi_genl_family);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) subsys_initcall(ncsi_init_netlink);