Guest User

Untitled

a guest
Oct 20th, 2018
102
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 31.25 KB | None | 0 0
  1. diff --git a/include/uapi/linux/ncsi.h b/include/uapi/linux/ncsi.h
  2. index 4c292ecbb748..0a26a5576645 100644
  3. --- a/include/uapi/linux/ncsi.h
  4. +++ b/include/uapi/linux/ncsi.h
  5. @@ -23,6 +23,9 @@
  6. * optionally the preferred NCSI_ATTR_CHANNEL_ID.
  7. * @NCSI_CMD_CLEAR_INTERFACE: clear any preferred package/channel combination.
  8. * Requires NCSI_ATTR_IFINDEX.
  9. + * @NCSI_CMD_SEND_CMD: send NC-SI command to network card.
  10. + * Requires NCSI_ATTR_IFINDEX, NCSI_ATTR_PACKAGE_ID
  11. + * and NCSI_ATTR_CHANNEL_ID.
  12. * @NCSI_CMD_MAX: highest command number
  13. */
  14. enum ncsi_nl_commands {
  15. @@ -30,6 +33,7 @@ enum ncsi_nl_commands {
  16. NCSI_CMD_PKG_INFO,
  17. NCSI_CMD_SET_INTERFACE,
  18. NCSI_CMD_CLEAR_INTERFACE,
  19. + NCSI_CMD_SEND_CMD,
  20.  
  21. __NCSI_CMD_AFTER_LAST,
  22. NCSI_CMD_MAX = __NCSI_CMD_AFTER_LAST - 1
  23. @@ -43,6 +47,7 @@ enum ncsi_nl_commands {
  24. * @NCSI_ATTR_PACKAGE_LIST: nested array of NCSI_PKG_ATTR attributes
  25. * @NCSI_ATTR_PACKAGE_ID: package ID
  26. * @NCSI_ATTR_CHANNEL_ID: channel ID
  27. + * @NCSI_ATTR_DATA: command payload
  28. * @NCSI_ATTR_MAX: highest attribute number
  29. */
  30. enum ncsi_nl_attrs {
  31. @@ -51,6 +56,7 @@ enum ncsi_nl_attrs {
  32. NCSI_ATTR_PACKAGE_LIST,
  33. NCSI_ATTR_PACKAGE_ID,
  34. NCSI_ATTR_CHANNEL_ID,
  35. + NCSI_ATTR_DATA,
  36.  
  37. __NCSI_ATTR_AFTER_LAST,
  38. NCSI_ATTR_MAX = __NCSI_ATTR_AFTER_LAST - 1
  39. diff --git a/net/ncsi/Kconfig b/net/ncsi/Kconfig
  40. index 08a8a6031fd7..7f2b46108a24 100644
  41. --- a/net/ncsi/Kconfig
  42. +++ b/net/ncsi/Kconfig
  43. @@ -10,3 +10,9 @@ config NET_NCSI
  44. support. Enable this only if your system connects to a network
  45. device via NCSI and the ethernet driver you're using supports
  46. the protocol explicitly.
  47. +config NCSI_OEM_CMD_GET_MAC
  48. + bool "Get NCSI OEM MAC Address"
  49. + depends on NET_NCSI
  50. + ---help---
  51. + This allows to get MAC address from NCSI firmware and set them back to
  52. + controller.
  53. diff --git a/net/ncsi/internal.h b/net/ncsi/internal.h
  54. index 8055e3965cef..71670d3270f3 100644
  55. --- a/net/ncsi/internal.h
  56. +++ b/net/ncsi/internal.h
  57. @@ -68,6 +68,22 @@ enum {
  58. NCSI_MODE_MAX
  59. };
  60.  
  61. +/* OEM Vendor Manufacture ID */
  62. +#define NCSI_OEM_MFR_MLX_ID 0x8119
  63. +#define NCSI_OEM_MFR_BCM_ID 0x113d
  64. +/* Broadcom specific OEM Command */
  65. +#define NCSI_OEM_BCM_CMD_GMA 0x01 /* CMD ID for Get MAC */
  66. +/* Mellanox specific OEM Command */
  67. +#define NCSI_OEM_MLX_CMD_GMA 0x00 /* CMD ID for Get MAC */
  68. +#define NCSI_OEM_MLX_CMD_GMA_PARAM 0x1b /* Parameter for GMA */
  69. +/* OEM Command payload lengths*/
  70. +#define NCSI_OEM_BCM_CMD_GMA_LEN 12
  71. +#define NCSI_OEM_MLX_CMD_GMA_LEN 8
  72. +/* Mac address offset in OEM response */
  73. +#define BCM_MAC_ADDR_OFFSET 28
  74. +#define MLX_MAC_ADDR_OFFSET 8
  75. +
  76. +
  77. struct ncsi_channel_version {
  78. u32 version; /* Supported BCD encoded NCSI version */
  79. u32 alpha2; /* Supported BCD encoded NCSI version */
  80. @@ -171,6 +187,8 @@ struct ncsi_package;
  81. #define NCSI_RESERVED_CHANNEL 0x1f
  82. #define NCSI_CHANNEL_INDEX(c) ((c) & ((1 << NCSI_PACKAGE_SHIFT) - 1))
  83. #define NCSI_TO_CHANNEL(p, c) (((p) << NCSI_PACKAGE_SHIFT) | (c))
  84. +#define NCSI_MAX_PACKAGE 8
  85. +#define NCSI_MAX_CHANNEL 32
  86.  
  87. struct ncsi_channel {
  88. unsigned char id;
  89. @@ -216,11 +234,15 @@ struct ncsi_request {
  90. bool used; /* Request that has been assigned */
  91. unsigned int flags; /* NCSI request property */
  92. #define NCSI_REQ_FLAG_EVENT_DRIVEN 1
  93. +#define NCSI_REQ_FLAG_NETLINK_DRIVEN 2
  94. struct ncsi_dev_priv *ndp; /* Associated NCSI device */
  95. struct sk_buff *cmd; /* Associated NCSI command packet */
  96. struct sk_buff *rsp; /* Associated NCSI response packet */
  97. struct timer_list timer; /* Timer on waiting for response */
  98. bool enabled; /* Time has been enabled or not */
  99. + u32 snd_seq; /* netlink sending sequence number */
  100. + u32 snd_portid; /* netlink portid of sender */
  101. + struct nlmsghdr nlhdr; /* netlink message header */
  102. };
  103.  
  104. enum {
  105. @@ -236,6 +258,7 @@ enum {
  106. ncsi_dev_state_probe_dp,
  107. ncsi_dev_state_config_sp = 0x0301,
  108. ncsi_dev_state_config_cis,
  109. + ncsi_dev_state_config_oem_gma,
  110. ncsi_dev_state_config_clear_vids,
  111. ncsi_dev_state_config_svf,
  112. ncsi_dev_state_config_ev,
  113. @@ -305,6 +328,8 @@ struct ncsi_cmd_arg {
  114. unsigned short words[8];
  115. unsigned int dwords[4];
  116. };
  117. + unsigned char *data; /* NCSI OEM data */
  118. + struct genl_info *info; /* Netlink information */
  119. };
  120.  
  121. extern struct list_head ncsi_dev_list;
  122. diff --git a/net/ncsi/ncsi-cmd.c b/net/ncsi/ncsi-cmd.c
  123. index 7567ca63aae2..356af474e43c 100644
  124. --- a/net/ncsi/ncsi-cmd.c
  125. +++ b/net/ncsi/ncsi-cmd.c
  126. @@ -17,6 +17,7 @@
  127. #include <net/ncsi.h>
  128. #include <net/net_namespace.h>
  129. #include <net/sock.h>
  130. +#include <net/genetlink.h>
  131.  
  132. #include "internal.h"
  133. #include "ncsi-pkt.h"
  134. @@ -211,6 +212,25 @@ static int ncsi_cmd_handler_snfc(struct sk_buff *skb,
  135. return 0;
  136. }
  137.  
  138. +static int ncsi_cmd_handler_oem(struct sk_buff *skb,
  139. + struct ncsi_cmd_arg *nca)
  140. +{
  141. + struct ncsi_cmd_oem_pkt *cmd;
  142. + unsigned int len;
  143. +
  144. + len = sizeof(struct ncsi_cmd_pkt_hdr) + 4;
  145. + if (nca->payload < 26)
  146. + len += 26;
  147. + else
  148. + len += nca->payload;
  149. +
  150. + cmd = skb_put_zero(skb, len);
  151. + memcpy(&cmd->mfr_id, nca->data, nca->payload);
  152. + ncsi_cmd_build_header(&cmd->cmd.common, nca);
  153. +
  154. + return 0;
  155. +}
  156. +
  157. static struct ncsi_cmd_handler {
  158. unsigned char type;
  159. int payload;
  160. @@ -244,7 +264,7 @@ static struct ncsi_cmd_handler {
  161. { NCSI_PKT_CMD_GNS, 0, ncsi_cmd_handler_default },
  162. { NCSI_PKT_CMD_GNPTS, 0, ncsi_cmd_handler_default },
  163. { NCSI_PKT_CMD_GPS, 0, ncsi_cmd_handler_default },
  164. - { NCSI_PKT_CMD_OEM, 0, NULL },
  165. + { NCSI_PKT_CMD_OEM, -1, ncsi_cmd_handler_oem },
  166. { NCSI_PKT_CMD_PLDM, 0, NULL },
  167. { NCSI_PKT_CMD_GPUUID, 0, ncsi_cmd_handler_default }
  168. };
  169. @@ -316,12 +336,24 @@ int ncsi_xmit_cmd(struct ncsi_cmd_arg *nca)
  170. return -ENOENT;
  171. }
  172.  
  173. - /* Get packet payload length and allocate the request */
  174. - nca->payload = nch->payload;
  175. + /* Get packet payload length and allocate the request
  176. + * It is expected that if length set as negative in
  177. + * handler structure means caller is initializing it
  178. + * and setting length in nca before calling xmit function
  179. + */
  180. + if (nch->payload >= 0)
  181. + nca->payload = nch->payload;
  182. nr = ncsi_alloc_command(nca);
  183. if (!nr)
  184. return -ENOMEM;
  185.  
  186. + /* track netlink information */
  187. + if (nca->req_flags == NCSI_REQ_FLAG_NETLINK_DRIVEN) {
  188. + nr->snd_seq = nca->info->snd_seq;
  189. + nr->snd_portid = nca->info->snd_portid;
  190. + nr->nlhdr = *nca->info->nlhdr;
  191. + }
  192. +
  193. /* Prepare the packet */
  194. nca->id = nr->id;
  195. ret = nch->handler(nr->cmd, nca);
  196. diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c
  197. index 091284760d21..961ff26dfd4c 100644
  198. --- a/net/ncsi/ncsi-manage.c
  199. +++ b/net/ncsi/ncsi-manage.c
  200. @@ -19,6 +19,7 @@
  201. #include <net/addrconf.h>
  202. #include <net/ipv6.h>
  203. #include <net/if_inet6.h>
  204. +#include <net/genetlink.h>
  205.  
  206. #include "internal.h"
  207. #include "ncsi-pkt.h"
  208. @@ -406,6 +407,9 @@ static void ncsi_request_timeout(struct timer_list *t)
  209. {
  210. struct ncsi_request *nr = from_timer(nr, t, timer);
  211. struct ncsi_dev_priv *ndp = nr->ndp;
  212. + struct ncsi_cmd_pkt *cmd;
  213. + struct ncsi_package *np;
  214. + struct ncsi_channel *nc;
  215. unsigned long flags;
  216.  
  217. /* If the request already had associated response,
  218. @@ -419,6 +423,18 @@ static void ncsi_request_timeout(struct timer_list *t)
  219. }
  220. spin_unlock_irqrestore(&ndp->lock, flags);
  221.  
  222. + if (nr->flags == NCSI_REQ_FLAG_NETLINK_DRIVEN) {
  223. + if (nr->cmd) {
  224. + /* Find the package */
  225. + cmd = (struct ncsi_cmd_pkt *)
  226. + skb_network_header(nr->cmd);
  227. + ncsi_find_package_and_channel(ndp,
  228. + cmd->cmd.common.channel,
  229. + &np, &nc);
  230. + ncsi_send_netlink_timeout(nr, np, nc);
  231. + }
  232. + }
  233. +
  234. /* Release the request */
  235. ncsi_free_request(nr);
  236. }
  237. @@ -635,6 +651,61 @@ static int set_one_vid(struct ncsi_dev_priv *ndp, struct ncsi_channel *nc,
  238. return 0;
  239. }
  240.  
  241. +#if IS_ENABLED(CONFIG_NCSI_OEM_CMD_GET_MAC)
  242. +
  243. +/* NCSI OEM Command APIs */
  244. +static void ncsi_oem_gma_handler_bcm(struct ncsi_cmd_arg *nca)
  245. +{
  246. + int ret = 0;
  247. + unsigned char data[NCSI_OEM_BCM_CMD_GMA_LEN];
  248. +
  249. + nca->payload = NCSI_OEM_BCM_CMD_GMA_LEN;
  250. +
  251. + memset(data, 0, NCSI_OEM_BCM_CMD_GMA_LEN);
  252. + *(unsigned int *)data = ntohl(NCSI_OEM_MFR_BCM_ID);
  253. + data[5] = NCSI_OEM_BCM_CMD_GMA;
  254. +
  255. + nca->data = data;
  256. +
  257. + ret = ncsi_xmit_cmd(nca);
  258. + if (ret)
  259. + netdev_err(nca->ndp->ndev.dev,
  260. + "NCSI: Failed to transmit cmd 0x%x during configure\n",
  261. + nca->type);
  262. +}
  263. +
  264. +static void ncsi_oem_gma_handler_mlx(struct ncsi_cmd_arg *nca)
  265. +{
  266. + int ret = 0;
  267. + unsigned char data[NCSI_OEM_MLX_CMD_GMA_LEN];
  268. +
  269. + nca->payload = NCSI_OEM_MLX_CMD_GMA_LEN;
  270. +
  271. + memset(data, 0, NCSI_OEM_MLX_CMD_GMA_LEN);
  272. + *(unsigned int *)data = ntohl(NCSI_OEM_MFR_MLX_ID);
  273. + data[5] = NCSI_OEM_MLX_CMD_GMA;
  274. + data[6] = NCSI_OEM_MLX_CMD_GMA_PARAM;
  275. +
  276. + nca->data = data;
  277. +
  278. + ret = ncsi_xmit_cmd(nca);
  279. + if (ret)
  280. + netdev_err(nca->ndp->ndev.dev,
  281. + "NCSI: Failed to transmit cmd 0x%x during configure\n",
  282. + nca->type);
  283. +}
  284. +
  285. +/* OEM Command handlers initialization */
  286. +static struct ncsi_oem_gma_handler {
  287. + unsigned int mfr_id;
  288. + void (*handler)(struct ncsi_cmd_arg *nca);
  289. +} ncsi_oem_gma_handlers[] = {
  290. + { NCSI_OEM_MFR_BCM_ID, ncsi_oem_gma_handler_bcm },
  291. + { NCSI_OEM_MFR_MLX_ID, ncsi_oem_gma_handler_mlx }
  292. +};
  293. +
  294. +#endif /* CONFIG_NCSI_OEM_CMD_GET_MAC */
  295. +
  296. static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
  297. {
  298. struct ncsi_dev *nd = &ndp->ndev;
  299. @@ -643,9 +714,10 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
  300. struct ncsi_channel *nc = ndp->active_channel;
  301. struct ncsi_channel *hot_nc = NULL;
  302. struct ncsi_cmd_arg nca;
  303. + struct ncsi_oem_gma_handler *nch = NULL;
  304. unsigned char index;
  305. unsigned long flags;
  306. - int ret;
  307. + int ret, i;
  308.  
  309. nca.ndp = ndp;
  310. nca.req_flags = NCSI_REQ_FLAG_EVENT_DRIVEN;
  311. @@ -685,6 +757,40 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
  312. goto error;
  313. }
  314.  
  315. +#if IS_ENABLED(CONFIG_NCSI_OEM_CMD_GET_MAC)
  316. + nd->state = ncsi_dev_state_config_oem_gma;
  317. + break;
  318. + case ncsi_dev_state_config_oem_gma:
  319. + nca.type = NCSI_PKT_CMD_OEM;
  320. + nca.package = np->id;
  321. + nca.channel = nc->id;
  322. + ndp->pending_req_num = 1;
  323. +
  324. + /* Check for manufacturer id and Find the handler */
  325. + for (i = 0; i < ARRAY_SIZE(ncsi_oem_gma_handlers); i++) {
  326. + if (ncsi_oem_gma_handlers[i].mfr_id ==
  327. + nc->version.mf_id) {
  328. + if (ncsi_oem_gma_handlers[i].handler)
  329. + nch = &ncsi_oem_gma_handlers[i];
  330. + else
  331. + nch = NULL;
  332. +
  333. + break;
  334. + }
  335. + }
  336. +
  337. + if (!nch) {
  338. + netdev_err(ndp->ndev.dev, "No handler available for GMA with MFR-ID (0x%x)\n",
  339. + nc->version.mf_id);
  340. + nd->state = ncsi_dev_state_config_clear_vids;
  341. + schedule_work(&ndp->work);
  342. + break;
  343. + }
  344. +
  345. + /* Get Mac address from NCSI device */
  346. + nch->handler(&nca);
  347. +#endif /* CONFIG_NCSI_OEM_CMD_GET_MAC */
  348. +
  349. nd->state = ncsi_dev_state_config_clear_vids;
  350. break;
  351. case ncsi_dev_state_config_clear_vids:
  352. diff --git a/net/ncsi/ncsi-netlink.c b/net/ncsi/ncsi-netlink.c
  353. index 45f33d6dedf7..9b48b9fd31f3 100644
  354. --- a/net/ncsi/ncsi-netlink.c
  355. +++ b/net/ncsi/ncsi-netlink.c
  356. @@ -20,6 +20,7 @@
  357. #include <uapi/linux/ncsi.h>
  358.  
  359. #include "internal.h"
  360. +#include "ncsi-pkt.h"
  361. #include "ncsi-netlink.h"
  362.  
  363. static struct genl_family ncsi_genl_family;
  364. @@ -29,6 +30,7 @@ static const struct nla_policy ncsi_genl_policy[NCSI_ATTR_MAX + 1] = {
  365. [NCSI_ATTR_PACKAGE_LIST] = { .type = NLA_NESTED },
  366. [NCSI_ATTR_PACKAGE_ID] = { .type = NLA_U32 },
  367. [NCSI_ATTR_CHANNEL_ID] = { .type = NLA_U32 },
  368. + [NCSI_ATTR_DATA] = { .type = NLA_BINARY, .len = 2048 },
  369. };
  370.  
  371. static struct ncsi_dev_priv *ndp_from_ifindex(struct net *net, u32 ifindex)
  372. @@ -366,6 +368,202 @@ static int ncsi_clear_interface_nl(struct sk_buff *msg, struct genl_info *info)
  373. return 0;
  374. }
  375.  
  376. +static int ncsi_send_cmd_nl(struct sk_buff *msg, struct genl_info *info)
  377. +{
  378. + struct ncsi_dev_priv *ndp;
  379. + struct ncsi_pkt_hdr *hdr;
  380. + struct ncsi_cmd_arg nca;
  381. + unsigned char *data;
  382. + u32 package_id;
  383. + u32 channel_id;
  384. + int len, ret;
  385. +
  386. + if (!info || !info->attrs) {
  387. + ret = -EINVAL;
  388. + goto out;
  389. + }
  390. +
  391. + if (!info->attrs[NCSI_ATTR_IFINDEX]) {
  392. + ret = -EINVAL;
  393. + goto out;
  394. + }
  395. +
  396. + if (!info->attrs[NCSI_ATTR_PACKAGE_ID]) {
  397. + ret = -EINVAL;
  398. + goto out;
  399. + }
  400. +
  401. + if (!info->attrs[NCSI_ATTR_CHANNEL_ID]) {
  402. + ret = -EINVAL;
  403. + goto out;
  404. + }
  405. +
  406. + if (!info->attrs[NCSI_ATTR_DATA]) {
  407. + ret = -EINVAL;
  408. + goto out;
  409. + }
  410. +
  411. + ndp = ndp_from_ifindex(get_net(sock_net(msg->sk)),
  412. + nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX]));
  413. + if (!ndp) {
  414. + ret = -ENODEV;
  415. + goto out;
  416. + }
  417. +
  418. + package_id = nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_ID]);
  419. + channel_id = nla_get_u32(info->attrs[NCSI_ATTR_CHANNEL_ID]);
  420. +
  421. + if (package_id >= NCSI_MAX_PACKAGE || channel_id >= NCSI_MAX_CHANNEL) {
  422. + ret = -ERANGE;
  423. + goto out_netlink;
  424. + }
  425. +
  426. + len = nla_len(info->attrs[NCSI_ATTR_DATA]);
  427. + if (len < sizeof(struct ncsi_pkt_hdr)) {
  428. + netdev_info(ndp->ndev.dev, "NCSI: no command to send %u\n",
  429. + package_id);
  430. + ret = -EINVAL;
  431. + goto out_netlink;
  432. + } else {
  433. + data = (unsigned char *)nla_data(info->attrs[NCSI_ATTR_DATA]);
  434. + }
  435. +
  436. + hdr = (struct ncsi_pkt_hdr *)data;
  437. +
  438. + nca.ndp = ndp;
  439. + nca.package = (unsigned char)package_id;
  440. + nca.channel = (unsigned char)channel_id;
  441. + nca.type = hdr->type;
  442. + nca.req_flags = NCSI_REQ_FLAG_NETLINK_DRIVEN;
  443. + nca.info = info;
  444. + nca.payload = ntohs(hdr->length);
  445. + nca.data = data + sizeof(*hdr);
  446. +
  447. + ret = ncsi_xmit_cmd(&nca);
  448. +out_netlink:
  449. + if (ret != 0) {
  450. + netdev_err(ndp->ndev.dev,
  451. + "NCSI: Error %d sending command\n",
  452. + ret);
  453. + ncsi_send_netlink_err(ndp->ndev.dev,
  454. + info->snd_seq,
  455. + info->snd_portid,
  456. + info->nlhdr,
  457. + ret);
  458. + }
  459. +out:
  460. + return ret;
  461. +}
  462. +
  463. +int ncsi_send_netlink_rsp(struct ncsi_request *nr,
  464. + struct ncsi_package *np,
  465. + struct ncsi_channel *nc)
  466. +{
  467. + struct sk_buff *skb;
  468. + struct net *net;
  469. + void *hdr;
  470. + int rc;
  471. +
  472. + net = dev_net(nr->rsp->dev);
  473. +
  474. + skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
  475. + if (!skb)
  476. + return -ENOMEM;
  477. +
  478. + hdr = genlmsg_put(skb, nr->snd_portid, nr->snd_seq,
  479. + &ncsi_genl_family, 0, NCSI_CMD_SEND_CMD);
  480. + if (!hdr) {
  481. + kfree_skb(skb);
  482. + return -EMSGSIZE;
  483. + }
  484. +
  485. + nla_put_u32(skb, NCSI_ATTR_IFINDEX, nr->rsp->dev->ifindex);
  486. + if (np)
  487. + nla_put_u32(skb, NCSI_ATTR_PACKAGE_ID, np->id);
  488. + if (nc)
  489. + nla_put_u32(skb, NCSI_ATTR_CHANNEL_ID, nc->id);
  490. + else
  491. + nla_put_u32(skb, NCSI_ATTR_CHANNEL_ID, NCSI_RESERVED_CHANNEL);
  492. +
  493. + rc = nla_put(skb, NCSI_ATTR_DATA, nr->rsp->len, (void *)nr->rsp->data);
  494. + if (rc)
  495. + goto err;
  496. +
  497. + genlmsg_end(skb, hdr);
  498. + return genlmsg_unicast(net, skb, nr->snd_portid);
  499. +
  500. +err:
  501. + kfree_skb(skb);
  502. + return rc;
  503. +}
  504. +
  505. +int ncsi_send_netlink_timeout(struct ncsi_request *nr,
  506. + struct ncsi_package *np,
  507. + struct ncsi_channel *nc)
  508. +{
  509. + struct sk_buff *skb;
  510. + struct net *net;
  511. + void *hdr;
  512. +
  513. + skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
  514. + if (!skb)
  515. + return -ENOMEM;
  516. +
  517. + hdr = genlmsg_put(skb, nr->snd_portid, nr->snd_seq,
  518. + &ncsi_genl_family, 0, NCSI_CMD_SEND_CMD);
  519. + if (!hdr) {
  520. + kfree_skb(skb);
  521. + return -EMSGSIZE;
  522. + }
  523. +
  524. + net = dev_net(nr->cmd->dev);
  525. +
  526. + nla_put_u32(skb, NCSI_ATTR_IFINDEX, nr->cmd->dev->ifindex);
  527. +
  528. + if (np)
  529. + nla_put_u32(skb, NCSI_ATTR_PACKAGE_ID, np->id);
  530. + else
  531. + nla_put_u32(skb, NCSI_ATTR_PACKAGE_ID,
  532. + NCSI_PACKAGE_INDEX((((struct ncsi_pkt_hdr *)
  533. + nr->cmd->data)->channel)));
  534. +
  535. + if (nc)
  536. + nla_put_u32(skb, NCSI_ATTR_CHANNEL_ID, nc->id);
  537. + else
  538. + nla_put_u32(skb, NCSI_ATTR_CHANNEL_ID, NCSI_RESERVED_CHANNEL);
  539. +
  540. + genlmsg_end(skb, hdr);
  541. + return genlmsg_unicast(net, skb, nr->snd_portid);
  542. +}
  543. +
  544. +int ncsi_send_netlink_err(struct net_device *dev,
  545. + u32 snd_seq,
  546. + u32 snd_portid,
  547. + struct nlmsghdr *nlhdr,
  548. + int err)
  549. +{
  550. + struct nlmsghdr *nlh;
  551. + struct nlmsgerr *nle;
  552. + struct sk_buff *skb;
  553. + struct net *net;
  554. +
  555. + skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
  556. + if (!skb)
  557. + return -ENOMEM;
  558. +
  559. + net = dev_net(dev);
  560. +
  561. + nlh = nlmsg_put(skb, snd_portid, snd_seq,
  562. + NLMSG_ERROR, sizeof(*nle), 0);
  563. + nle = (struct nlmsgerr *)nlmsg_data(nlh);
  564. + nle->error = err;
  565. + memcpy(&nle->msg, nlhdr, sizeof(*nlh));
  566. +
  567. + nlmsg_end(skb, nlh);
  568. +
  569. + return nlmsg_unicast(net->genl_sock, skb, snd_portid);
  570. +}
  571. +
  572. static const struct genl_ops ncsi_ops[] = {
  573. {
  574. .cmd = NCSI_CMD_PKG_INFO,
  575. @@ -386,6 +584,12 @@ static const struct genl_ops ncsi_ops[] = {
  576. .doit = ncsi_clear_interface_nl,
  577. .flags = GENL_ADMIN_PERM,
  578. },
  579. + {
  580. + .cmd = NCSI_CMD_SEND_CMD,
  581. + .policy = ncsi_genl_policy,
  582. + .doit = ncsi_send_cmd_nl,
  583. + .flags = GENL_ADMIN_PERM,
  584. + },
  585. };
  586.  
  587. static struct genl_family ncsi_genl_family __ro_after_init = {
  588. diff --git a/net/ncsi/ncsi-netlink.h b/net/ncsi/ncsi-netlink.h
  589. index 91a5c256f8c4..c4a46887a932 100644
  590. --- a/net/ncsi/ncsi-netlink.h
  591. +++ b/net/ncsi/ncsi-netlink.h
  592. @@ -14,6 +14,18 @@
  593.  
  594. #include "internal.h"
  595.  
  596. +int ncsi_send_netlink_rsp(struct ncsi_request *nr,
  597. + struct ncsi_package *np,
  598. + struct ncsi_channel *nc);
  599. +int ncsi_send_netlink_timeout(struct ncsi_request *nr,
  600. + struct ncsi_package *np,
  601. + struct ncsi_channel *nc);
  602. +int ncsi_send_netlink_err(struct net_device *dev,
  603. + u32 snd_seq,
  604. + u32 snd_portid,
  605. + struct nlmsghdr *nlhdr,
  606. + int err);
  607. +
  608. int ncsi_init_netlink(struct net_device *dev);
  609. int ncsi_unregister_netlink(struct net_device *dev);
  610.  
  611. diff --git a/net/ncsi/ncsi-pkt.h b/net/ncsi/ncsi-pkt.h
  612. index 91b4b66438df..2a6d83a596c9 100644
  613. --- a/net/ncsi/ncsi-pkt.h
  614. +++ b/net/ncsi/ncsi-pkt.h
  615. @@ -151,6 +151,37 @@ struct ncsi_cmd_snfc_pkt {
  616. unsigned char pad[22];
  617. };
  618.  
  619. +/* OEM Request Command as per NCSI Specification */
  620. +struct ncsi_cmd_oem_pkt {
  621. + struct ncsi_cmd_pkt_hdr cmd; /* Command header */
  622. + __be32 mfr_id; /* Manufacture ID */
  623. + unsigned char data[]; /* OEM Payload Data */
  624. +};
  625. +
  626. +/* OEM Response Packet as per NCSI Specification */
  627. +struct ncsi_rsp_oem_pkt {
  628. + struct ncsi_rsp_pkt_hdr rsp; /* Command header */
  629. + __be32 mfr_id; /* Manufacture ID */
  630. + unsigned char data[]; /* Payload data */
  631. +};
  632. +
  633. +/* Mellanox Response Data */
  634. +struct ncsi_rsp_oem_mlx_pkt {
  635. + unsigned char cmd_rev; /* Command Revision */
  636. + unsigned char cmd; /* Command ID */
  637. + unsigned char param; /* Parameter */
  638. + unsigned char optional; /* Optional data */
  639. + unsigned char data[]; /* Data */
  640. +};
  641. +
  642. +/* Broadcom Response Data */
  643. +struct ncsi_rsp_oem_bcm_pkt {
  644. + unsigned char ver; /* Payload Version */
  645. + unsigned char type; /* OEM Command type */
  646. + __be16 len; /* Payload Length */
  647. + unsigned char data[]; /* Cmd specific Data */
  648. +};
  649. +
  650. /* Get Link Status */
  651. struct ncsi_rsp_gls_pkt {
  652. struct ncsi_rsp_pkt_hdr rsp; /* Response header */
  653. diff --git a/net/ncsi/ncsi-rsp.c b/net/ncsi/ncsi-rsp.c
  654. index 930c1d3796f0..56145f9fc92d 100644
  655. --- a/net/ncsi/ncsi-rsp.c
  656. +++ b/net/ncsi/ncsi-rsp.c
  657. @@ -16,9 +16,11 @@
  658. #include <net/ncsi.h>
  659. #include <net/net_namespace.h>
  660. #include <net/sock.h>
  661. +#include <net/genetlink.h>
  662.  
  663. #include "internal.h"
  664. #include "ncsi-pkt.h"
  665. +#include "ncsi-netlink.h"
  666.  
  667. static int ncsi_validate_rsp_pkt(struct ncsi_request *nr,
  668. unsigned short payload)
  669. @@ -32,15 +34,25 @@ static int ncsi_validate_rsp_pkt(struct ncsi_request *nr,
  670. * before calling this function.
  671. */
  672. h = (struct ncsi_rsp_pkt_hdr *)skb_network_header(nr->rsp);
  673. - if (h->common.revision != NCSI_PKT_REVISION)
  674. +
  675. + if (h->common.revision != NCSI_PKT_REVISION) {
  676. + netdev_dbg(nr->ndp->ndev.dev,
  677. + "NCSI: unsupported header revision\n");
  678. return -EINVAL;
  679. - if (ntohs(h->common.length) != payload)
  680. + }
  681. + if (ntohs(h->common.length) != payload) {
  682. + netdev_dbg(nr->ndp->ndev.dev,
  683. + "NCSI: payload length mismatched\n");
  684. return -EINVAL;
  685. + }
  686.  
  687. /* Check on code and reason */
  688. if (ntohs(h->code) != NCSI_PKT_RSP_C_COMPLETED ||
  689. - ntohs(h->reason) != NCSI_PKT_RSP_R_NO_ERROR)
  690. - return -EINVAL;
  691. + ntohs(h->reason) != NCSI_PKT_RSP_R_NO_ERROR) {
  692. + netdev_dbg(nr->ndp->ndev.dev,
  693. + "NCSI: non zero response/reason code\n");
  694. + return -EPERM;
  695. + }
  696.  
  697. /* Validate checksum, which might be zeroes if the
  698. * sender doesn't support checksum according to NCSI
  699. @@ -52,8 +64,11 @@ static int ncsi_validate_rsp_pkt(struct ncsi_request *nr,
  700.  
  701. checksum = ncsi_calculate_checksum((unsigned char *)h,
  702. sizeof(*h) + payload - 4);
  703. - if (*pchecksum != htonl(checksum))
  704. +
  705. + if (*pchecksum != htonl(checksum)) {
  706. + netdev_dbg(nr->ndp->ndev.dev, "NCSI: checksum mismatched\n");
  707. return -EINVAL;
  708. + }
  709.  
  710. return 0;
  711. }
  712. @@ -596,6 +611,124 @@ static int ncsi_rsp_handler_snfc(struct ncsi_request *nr)
  713. return 0;
  714. }
  715.  
  716. +/* Response handler for Mellanox command Get Mac Address */
  717. +static int ncsi_rsp_handler_oem_mlx_gma(struct ncsi_request *nr)
  718. +{
  719. + struct ncsi_rsp_oem_pkt *rsp;
  720. + struct ncsi_dev_priv *ndp = nr->ndp;
  721. + struct net_device *ndev = ndp->ndev.dev;
  722. + int ret = 0;
  723. + const struct net_device_ops *ops = ndev->netdev_ops;
  724. + struct sockaddr saddr;
  725. +
  726. + /* Get the response header */
  727. + rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp);
  728. +
  729. + saddr.sa_family = ndev->type;
  730. + ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
  731. + memcpy(saddr.sa_data, &rsp->data[MLX_MAC_ADDR_OFFSET], ETH_ALEN);
  732. + ret = ops->ndo_set_mac_address(ndev, &saddr);
  733. + if (ret < 0)
  734. + netdev_warn(ndev, "NCSI: Writing mac address to device failed\n");
  735. +
  736. + return ret;
  737. +}
  738. +
  739. +/* Response handler for Mellanox card */
  740. +static int ncsi_rsp_handler_oem_mlx(struct ncsi_request *nr)
  741. +{
  742. + struct ncsi_rsp_oem_pkt *rsp;
  743. + struct ncsi_rsp_oem_mlx_pkt *mlx;
  744. +
  745. + /* Get the response header */
  746. + rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp);
  747. + mlx = (struct ncsi_rsp_oem_mlx_pkt *)(rsp->data);
  748. +
  749. + if (mlx->cmd == NCSI_OEM_MLX_CMD_GMA &&
  750. + mlx->param == NCSI_OEM_MLX_CMD_GMA_PARAM)
  751. + return ncsi_rsp_handler_oem_mlx_gma(nr);
  752. + return 0;
  753. +}
  754. +
  755. +/* Response handler for Broadcom command Get Mac Address */
  756. +static int ncsi_rsp_handler_oem_bcm_gma(struct ncsi_request *nr)
  757. +{
  758. + struct ncsi_rsp_oem_pkt *rsp;
  759. + struct ncsi_dev_priv *ndp = nr->ndp;
  760. + struct net_device *ndev = ndp->ndev.dev;
  761. + int ret = 0;
  762. + const struct net_device_ops *ops = ndev->netdev_ops;
  763. + struct sockaddr saddr;
  764. +
  765. + /* Get the response header */
  766. + rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp);
  767. +
  768. + saddr.sa_family = ndev->type;
  769. + ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
  770. + memcpy(saddr.sa_data, &rsp->data[BCM_MAC_ADDR_OFFSET], ETH_ALEN);
  771. + ret = ops->ndo_set_mac_address(ndev, &saddr);
  772. + if (ret < 0)
  773. + netdev_warn(ndev, "NCSI: Writing mac address to device failed\n");
  774. +
  775. + return ret;
  776. +}
  777. +
  778. +/* Response handler for Broadcom card */
  779. +static int ncsi_rsp_handler_oem_bcm(struct ncsi_request *nr)
  780. +{
  781. + struct ncsi_rsp_oem_pkt *rsp;
  782. + struct ncsi_rsp_oem_bcm_pkt *bcm;
  783. +
  784. + /* Get the response header */
  785. + rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp);
  786. + bcm = (struct ncsi_rsp_oem_bcm_pkt *)(rsp->data);
  787. +
  788. + if (bcm->type == NCSI_OEM_BCM_CMD_GMA)
  789. + return ncsi_rsp_handler_oem_bcm_gma(nr);
  790. + return 0;
  791. +}
  792. +
  793. +static struct ncsi_rsp_oem_handler {
  794. + unsigned int mfr_id;
  795. + int (*handler)(struct ncsi_request *nr);
  796. +} ncsi_rsp_oem_handlers[] = {
  797. + { NCSI_OEM_MFR_MLX_ID, ncsi_rsp_handler_oem_mlx },
  798. + { NCSI_OEM_MFR_BCM_ID, ncsi_rsp_handler_oem_bcm }
  799. +};
  800. +
  801. +/* Response handler for OEM command */
  802. +static int ncsi_rsp_handler_oem(struct ncsi_request *nr)
  803. +{
  804. + struct ncsi_rsp_oem_pkt *rsp;
  805. + struct ncsi_rsp_oem_handler *nrh = NULL;
  806. + unsigned int mfr_id, i;
  807. +
  808. + /* Get the response header */
  809. + rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp);
  810. + mfr_id = ntohl(rsp->mfr_id);
  811. +
  812. + /* Check for manufacturer id and Find the handler */
  813. + for (i = 0; i < ARRAY_SIZE(ncsi_rsp_oem_handlers); i++) {
  814. + if (ncsi_rsp_oem_handlers[i].mfr_id == mfr_id) {
  815. + if (ncsi_rsp_oem_handlers[i].handler)
  816. + nrh = &ncsi_rsp_oem_handlers[i];
  817. + else
  818. + nrh = NULL;
  819. +
  820. + break;
  821. + }
  822. + }
  823. +
  824. + if (!nrh) {
  825. + netdev_err(nr->ndp->ndev.dev, "Received unrecognized OEM packet with MFR-ID (0x%x)\n",
  826. + mfr_id);
  827. + return -ENOENT;
  828. + }
  829. +
  830. + /* Process the packet */
  831. + return nrh->handler(nr);
  832. +}
  833. +
  834. static int ncsi_rsp_handler_gvi(struct ncsi_request *nr)
  835. {
  836. struct ncsi_rsp_gvi_pkt *rsp;
  837. @@ -900,6 +1033,26 @@ static int ncsi_rsp_handler_gpuuid(struct ncsi_request *nr)
  838. return 0;
  839. }
  840.  
  841. +static int ncsi_rsp_handler_netlink(struct ncsi_request *nr)
  842. +{
  843. + struct ncsi_dev_priv *ndp = nr->ndp;
  844. + struct ncsi_rsp_pkt *rsp;
  845. + struct ncsi_package *np;
  846. + struct ncsi_channel *nc;
  847. + int ret;
  848. +
  849. + /* Find the package */
  850. + rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
  851. + ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
  852. + &np, &nc);
  853. + if (!np)
  854. + return -ENODEV;
  855. +
  856. + ret = ncsi_send_netlink_rsp(nr, np, nc);
  857. +
  858. + return ret;
  859. +}
  860. +
  861. static struct ncsi_rsp_handler {
  862. unsigned char type;
  863. int payload;
  864. @@ -932,7 +1085,7 @@ static struct ncsi_rsp_handler {
  865. { NCSI_PKT_RSP_GNS, 172, ncsi_rsp_handler_gns },
  866. { NCSI_PKT_RSP_GNPTS, 172, ncsi_rsp_handler_gnpts },
  867. { NCSI_PKT_RSP_GPS, 8, ncsi_rsp_handler_gps },
  868. - { NCSI_PKT_RSP_OEM, 0, NULL },
  869. + { NCSI_PKT_RSP_OEM, -1, ncsi_rsp_handler_oem },
  870. { NCSI_PKT_RSP_PLDM, 0, NULL },
  871. { NCSI_PKT_RSP_GPUUID, 20, ncsi_rsp_handler_gpuuid }
  872. };
  873. @@ -1002,6 +1155,17 @@ int ncsi_rcv_rsp(struct sk_buff *skb, struct net_device *dev,
  874. netdev_warn(ndp->ndev.dev,
  875. "NCSI: 'bad' packet ignored for type 0x%x\n",
  876. hdr->type);
  877. +
  878. + if (nr->flags == NCSI_REQ_FLAG_NETLINK_DRIVEN) {
  879. + if (ret == -EPERM)
  880. + goto out_netlink;
  881. + else
  882. + ncsi_send_netlink_err(ndp->ndev.dev,
  883. + nr->snd_seq,
  884. + nr->snd_portid,
  885. + &nr->nlhdr,
  886. + ret);
  887. + }
  888. goto out;
  889. }
  890.  
  891. @@ -1011,6 +1175,17 @@ int ncsi_rcv_rsp(struct sk_buff *skb, struct net_device *dev,
  892. netdev_err(ndp->ndev.dev,
  893. "NCSI: Handler for packet type 0x%x returned %d\n",
  894. hdr->type, ret);
  895. +
  896. +out_netlink:
  897. + if (nr->flags == NCSI_REQ_FLAG_NETLINK_DRIVEN) {
  898. + ret = ncsi_rsp_handler_netlink(nr);
  899. + if (ret) {
  900. + netdev_err(ndp->ndev.dev,
  901. + "NCSI: Netlink handler for packet type 0x%x returned %d\n",
  902. + hdr->type, ret);
  903. + }
  904. + }
  905. +
  906. out:
  907. ncsi_free_request(nr);
  908. return ret;
Add Comment
Please, Sign In to add comment