ncsi-netlink.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. /*
  2. * Copyright Samuel Mendoza-Jonas, IBM Corporation 2018.
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. */
  9. #include <linux/module.h>
  10. #include <linux/kernel.h>
  11. #include <linux/if_arp.h>
  12. #include <linux/rtnetlink.h>
  13. #include <linux/etherdevice.h>
  14. #include <linux/module.h>
  15. #include <net/genetlink.h>
  16. #include <net/ncsi.h>
  17. #include <linux/skbuff.h>
  18. #include <net/sock.h>
  19. #include <uapi/linux/ncsi.h>
  20. #include "internal.h"
  21. #include "ncsi-netlink.h"
  22. static struct genl_family ncsi_genl_family;
  23. static const struct nla_policy ncsi_genl_policy[NCSI_ATTR_MAX + 1] = {
  24. [NCSI_ATTR_IFINDEX] = { .type = NLA_U32 },
  25. [NCSI_ATTR_PACKAGE_LIST] = { .type = NLA_NESTED },
  26. [NCSI_ATTR_PACKAGE_ID] = { .type = NLA_U32 },
  27. [NCSI_ATTR_CHANNEL_ID] = { .type = NLA_U32 },
  28. };
  29. static struct ncsi_dev_priv *ndp_from_ifindex(struct net *net, u32 ifindex)
  30. {
  31. struct ncsi_dev_priv *ndp;
  32. struct net_device *dev;
  33. struct ncsi_dev *nd;
  34. struct ncsi_dev;
  35. if (!net)
  36. return NULL;
  37. dev = dev_get_by_index(net, ifindex);
  38. if (!dev) {
  39. pr_err("NCSI netlink: No device for ifindex %u\n", ifindex);
  40. return NULL;
  41. }
  42. nd = ncsi_find_dev(dev);
  43. ndp = nd ? TO_NCSI_DEV_PRIV(nd) : NULL;
  44. dev_put(dev);
  45. return ndp;
  46. }
  47. static int ncsi_write_channel_info(struct sk_buff *skb,
  48. struct ncsi_dev_priv *ndp,
  49. struct ncsi_channel *nc)
  50. {
  51. struct ncsi_channel_vlan_filter *ncf;
  52. struct ncsi_channel_mode *m;
  53. struct nlattr *vid_nest;
  54. int i;
  55. nla_put_u32(skb, NCSI_CHANNEL_ATTR_ID, nc->id);
  56. m = &nc->modes[NCSI_MODE_LINK];
  57. nla_put_u32(skb, NCSI_CHANNEL_ATTR_LINK_STATE, m->data[2]);
  58. if (nc->state == NCSI_CHANNEL_ACTIVE)
  59. nla_put_flag(skb, NCSI_CHANNEL_ATTR_ACTIVE);
  60. if (ndp->force_channel == nc)
  61. nla_put_flag(skb, NCSI_CHANNEL_ATTR_FORCED);
  62. nla_put_u32(skb, NCSI_CHANNEL_ATTR_VERSION_MAJOR, nc->version.version);
  63. nla_put_u32(skb, NCSI_CHANNEL_ATTR_VERSION_MINOR, nc->version.alpha2);
  64. nla_put_string(skb, NCSI_CHANNEL_ATTR_VERSION_STR, nc->version.fw_name);
  65. vid_nest = nla_nest_start(skb, NCSI_CHANNEL_ATTR_VLAN_LIST);
  66. if (!vid_nest)
  67. return -ENOMEM;
  68. ncf = &nc->vlan_filter;
  69. i = -1;
  70. while ((i = find_next_bit((void *)&ncf->bitmap, ncf->n_vids,
  71. i + 1)) < ncf->n_vids) {
  72. if (ncf->vids[i])
  73. nla_put_u16(skb, NCSI_CHANNEL_ATTR_VLAN_ID,
  74. ncf->vids[i]);
  75. }
  76. nla_nest_end(skb, vid_nest);
  77. return 0;
  78. }
  79. static int ncsi_write_package_info(struct sk_buff *skb,
  80. struct ncsi_dev_priv *ndp, unsigned int id)
  81. {
  82. struct nlattr *pnest, *cnest, *nest;
  83. struct ncsi_package *np;
  84. struct ncsi_channel *nc;
  85. bool found;
  86. int rc;
  87. if (id > ndp->package_num - 1) {
  88. netdev_info(ndp->ndev.dev, "NCSI: No package with id %u\n", id);
  89. return -ENODEV;
  90. }
  91. found = false;
  92. NCSI_FOR_EACH_PACKAGE(ndp, np) {
  93. if (np->id != id)
  94. continue;
  95. pnest = nla_nest_start(skb, NCSI_PKG_ATTR);
  96. if (!pnest)
  97. return -ENOMEM;
  98. nla_put_u32(skb, NCSI_PKG_ATTR_ID, np->id);
  99. if (ndp->force_package == np)
  100. nla_put_flag(skb, NCSI_PKG_ATTR_FORCED);
  101. cnest = nla_nest_start(skb, NCSI_PKG_ATTR_CHANNEL_LIST);
  102. if (!cnest) {
  103. nla_nest_cancel(skb, pnest);
  104. return -ENOMEM;
  105. }
  106. NCSI_FOR_EACH_CHANNEL(np, nc) {
  107. nest = nla_nest_start(skb, NCSI_CHANNEL_ATTR);
  108. if (!nest) {
  109. nla_nest_cancel(skb, cnest);
  110. nla_nest_cancel(skb, pnest);
  111. return -ENOMEM;
  112. }
  113. rc = ncsi_write_channel_info(skb, ndp, nc);
  114. if (rc) {
  115. nla_nest_cancel(skb, nest);
  116. nla_nest_cancel(skb, cnest);
  117. nla_nest_cancel(skb, pnest);
  118. return rc;
  119. }
  120. nla_nest_end(skb, nest);
  121. }
  122. nla_nest_end(skb, cnest);
  123. nla_nest_end(skb, pnest);
  124. found = true;
  125. }
  126. if (!found)
  127. return -ENODEV;
  128. return 0;
  129. }
  130. static int ncsi_pkg_info_nl(struct sk_buff *msg, struct genl_info *info)
  131. {
  132. struct ncsi_dev_priv *ndp;
  133. unsigned int package_id;
  134. struct sk_buff *skb;
  135. struct nlattr *attr;
  136. void *hdr;
  137. int rc;
  138. if (!info || !info->attrs)
  139. return -EINVAL;
  140. if (!info->attrs[NCSI_ATTR_IFINDEX])
  141. return -EINVAL;
  142. if (!info->attrs[NCSI_ATTR_PACKAGE_ID])
  143. return -EINVAL;
  144. ndp = ndp_from_ifindex(genl_info_net(info),
  145. nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX]));
  146. if (!ndp)
  147. return -ENODEV;
  148. skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  149. if (!skb)
  150. return -ENOMEM;
  151. hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
  152. &ncsi_genl_family, 0, NCSI_CMD_PKG_INFO);
  153. if (!hdr) {
  154. kfree_skb(skb);
  155. return -EMSGSIZE;
  156. }
  157. package_id = nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_ID]);
  158. attr = nla_nest_start(skb, NCSI_ATTR_PACKAGE_LIST);
  159. if (!attr) {
  160. kfree_skb(skb);
  161. return -EMSGSIZE;
  162. }
  163. rc = ncsi_write_package_info(skb, ndp, package_id);
  164. if (rc) {
  165. nla_nest_cancel(skb, attr);
  166. goto err;
  167. }
  168. nla_nest_end(skb, attr);
  169. genlmsg_end(skb, hdr);
  170. return genlmsg_reply(skb, info);
  171. err:
  172. kfree_skb(skb);
  173. return rc;
  174. }
  175. static int ncsi_pkg_info_all_nl(struct sk_buff *skb,
  176. struct netlink_callback *cb)
  177. {
  178. struct nlattr *attrs[NCSI_ATTR_MAX + 1];
  179. struct ncsi_package *np, *package;
  180. struct ncsi_dev_priv *ndp;
  181. unsigned int package_id;
  182. struct nlattr *attr;
  183. void *hdr;
  184. int rc;
  185. rc = genlmsg_parse(cb->nlh, &ncsi_genl_family, attrs, NCSI_ATTR_MAX,
  186. ncsi_genl_policy, NULL);
  187. if (rc)
  188. return rc;
  189. if (!attrs[NCSI_ATTR_IFINDEX])
  190. return -EINVAL;
  191. ndp = ndp_from_ifindex(get_net(sock_net(skb->sk)),
  192. nla_get_u32(attrs[NCSI_ATTR_IFINDEX]));
  193. if (!ndp)
  194. return -ENODEV;
  195. package_id = cb->args[0];
  196. package = NULL;
  197. NCSI_FOR_EACH_PACKAGE(ndp, np)
  198. if (np->id == package_id)
  199. package = np;
  200. if (!package)
  201. return 0; /* done */
  202. hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
  203. &ncsi_genl_family, NLM_F_MULTI, NCSI_CMD_PKG_INFO);
  204. if (!hdr) {
  205. rc = -EMSGSIZE;
  206. goto err;
  207. }
  208. attr = nla_nest_start(skb, NCSI_ATTR_PACKAGE_LIST);
  209. rc = ncsi_write_package_info(skb, ndp, package->id);
  210. if (rc) {
  211. nla_nest_cancel(skb, attr);
  212. goto err;
  213. }
  214. nla_nest_end(skb, attr);
  215. genlmsg_end(skb, hdr);
  216. cb->args[0] = package_id + 1;
  217. return skb->len;
  218. err:
  219. genlmsg_cancel(skb, hdr);
  220. return rc;
  221. }
  222. static int ncsi_set_interface_nl(struct sk_buff *msg, struct genl_info *info)
  223. {
  224. struct ncsi_package *np, *package;
  225. struct ncsi_channel *nc, *channel;
  226. u32 package_id, channel_id;
  227. struct ncsi_dev_priv *ndp;
  228. unsigned long flags;
  229. if (!info || !info->attrs)
  230. return -EINVAL;
  231. if (!info->attrs[NCSI_ATTR_IFINDEX])
  232. return -EINVAL;
  233. if (!info->attrs[NCSI_ATTR_PACKAGE_ID])
  234. return -EINVAL;
  235. ndp = ndp_from_ifindex(get_net(sock_net(msg->sk)),
  236. nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX]));
  237. if (!ndp)
  238. return -ENODEV;
  239. package_id = nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_ID]);
  240. package = NULL;
  241. spin_lock_irqsave(&ndp->lock, flags);
  242. NCSI_FOR_EACH_PACKAGE(ndp, np)
  243. if (np->id == package_id)
  244. package = np;
  245. if (!package) {
  246. /* The user has set a package that does not exist */
  247. spin_unlock_irqrestore(&ndp->lock, flags);
  248. return -ERANGE;
  249. }
  250. channel = NULL;
  251. if (!info->attrs[NCSI_ATTR_CHANNEL_ID]) {
  252. /* Allow any channel */
  253. channel_id = NCSI_RESERVED_CHANNEL;
  254. } else {
  255. channel_id = nla_get_u32(info->attrs[NCSI_ATTR_CHANNEL_ID]);
  256. NCSI_FOR_EACH_CHANNEL(package, nc)
  257. if (nc->id == channel_id)
  258. channel = nc;
  259. }
  260. if (channel_id != NCSI_RESERVED_CHANNEL && !channel) {
  261. /* The user has set a channel that does not exist on this
  262. * package
  263. */
  264. spin_unlock_irqrestore(&ndp->lock, flags);
  265. netdev_info(ndp->ndev.dev, "NCSI: Channel %u does not exist!\n",
  266. channel_id);
  267. return -ERANGE;
  268. }
  269. ndp->force_package = package;
  270. ndp->force_channel = channel;
  271. spin_unlock_irqrestore(&ndp->lock, flags);
  272. netdev_info(ndp->ndev.dev, "Set package 0x%x, channel 0x%x%s as preferred\n",
  273. package_id, channel_id,
  274. channel_id == NCSI_RESERVED_CHANNEL ? " (any)" : "");
  275. /* Bounce the NCSI channel to set changes */
  276. ncsi_stop_dev(&ndp->ndev);
  277. ncsi_start_dev(&ndp->ndev);
  278. return 0;
  279. }
  280. static int ncsi_clear_interface_nl(struct sk_buff *msg, struct genl_info *info)
  281. {
  282. struct ncsi_dev_priv *ndp;
  283. unsigned long flags;
  284. if (!info || !info->attrs)
  285. return -EINVAL;
  286. if (!info->attrs[NCSI_ATTR_IFINDEX])
  287. return -EINVAL;
  288. ndp = ndp_from_ifindex(get_net(sock_net(msg->sk)),
  289. nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX]));
  290. if (!ndp)
  291. return -ENODEV;
  292. /* Clear any override */
  293. spin_lock_irqsave(&ndp->lock, flags);
  294. ndp->force_package = NULL;
  295. ndp->force_channel = NULL;
  296. spin_unlock_irqrestore(&ndp->lock, flags);
  297. netdev_info(ndp->ndev.dev, "NCSI: Cleared preferred package/channel\n");
  298. /* Bounce the NCSI channel to set changes */
  299. ncsi_stop_dev(&ndp->ndev);
  300. ncsi_start_dev(&ndp->ndev);
  301. return 0;
  302. }
  303. static const struct genl_ops ncsi_ops[] = {
  304. {
  305. .cmd = NCSI_CMD_PKG_INFO,
  306. .policy = ncsi_genl_policy,
  307. .doit = ncsi_pkg_info_nl,
  308. .dumpit = ncsi_pkg_info_all_nl,
  309. .flags = 0,
  310. },
  311. {
  312. .cmd = NCSI_CMD_SET_INTERFACE,
  313. .policy = ncsi_genl_policy,
  314. .doit = ncsi_set_interface_nl,
  315. .flags = GENL_ADMIN_PERM,
  316. },
  317. {
  318. .cmd = NCSI_CMD_CLEAR_INTERFACE,
  319. .policy = ncsi_genl_policy,
  320. .doit = ncsi_clear_interface_nl,
  321. .flags = GENL_ADMIN_PERM,
  322. },
  323. };
  324. static struct genl_family ncsi_genl_family __ro_after_init = {
  325. .name = "NCSI",
  326. .version = 0,
  327. .maxattr = NCSI_ATTR_MAX,
  328. .module = THIS_MODULE,
  329. .ops = ncsi_ops,
  330. .n_ops = ARRAY_SIZE(ncsi_ops),
  331. };
  332. int ncsi_init_netlink(struct net_device *dev)
  333. {
  334. int rc;
  335. rc = genl_register_family(&ncsi_genl_family);
  336. if (rc)
  337. netdev_err(dev, "ncsi: failed to register netlink family\n");
  338. return rc;
  339. }
  340. int ncsi_unregister_netlink(struct net_device *dev)
  341. {
  342. int rc;
  343. rc = genl_unregister_family(&ncsi_genl_family);
  344. if (rc)
  345. netdev_err(dev, "ncsi: failed to unregister netlink family\n");
  346. return rc;
  347. }