summaryrefslogtreecommitdiffstats
path: root/net/ncsi
diff options
context:
space:
mode:
authorJustin.Lee1@Dell.com <Justin.Lee1@Dell.com>2018-10-11 14:07:37 -0400
committerDavid S. Miller <davem@davemloft.net>2018-10-16 01:00:59 -0400
commit9771b8ccdfa6dcb1ac5128ca7fe8649f3092d392 (patch)
treec685a032ce049cb71428c0019925aeb7c5f2cda3 /net/ncsi
parent6384e483239fd07a2d4393f888027118fecd4c6e (diff)
net/ncsi: Extend NC-SI Netlink interface to allow user space to send NC-SI command
The new command (NCSI_CMD_SEND_CMD) is added to allow user space application to send NC-SI command to the network card. Also, add a new attribute (NCSI_ATTR_DATA) for transferring request and response. The work flow is as below. Request: User space application -> Netlink interface (msg) -> new Netlink handler - ncsi_send_cmd_nl() -> ncsi_xmit_cmd() Response: Response received - ncsi_rcv_rsp() -> internal response handler - ncsi_rsp_handler_xxx() -> ncsi_rsp_handler_netlink() -> ncsi_send_netlink_rsp () -> Netlink interface (msg) -> user space application Command timeout - ncsi_request_timeout() -> ncsi_send_netlink_timeout () -> Netlink interface (msg with zero data length) -> user space application Error: Error detected -> ncsi_send_netlink_err () -> Netlink interface (err msg) -> user space application Signed-off-by: Justin Lee <justin.lee1@dell.com> Reviewed-by: Samuel Mendoza-Jonas <sam@mendozajonas.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ncsi')
-rw-r--r--net/ncsi/internal.h7
-rw-r--r--net/ncsi/ncsi-cmd.c8
-rw-r--r--net/ncsi/ncsi-manage.c16
-rw-r--r--net/ncsi/ncsi-netlink.c204
-rw-r--r--net/ncsi/ncsi-netlink.h12
-rw-r--r--net/ncsi/ncsi-rsp.c67
6 files changed, 309 insertions, 5 deletions
diff --git a/net/ncsi/internal.h b/net/ncsi/internal.h
index 3d0a33b874f5..13c9b5eeb3b7 100644
--- a/net/ncsi/internal.h
+++ b/net/ncsi/internal.h
@@ -175,6 +175,8 @@ struct ncsi_package;
175#define NCSI_RESERVED_CHANNEL 0x1f 175#define NCSI_RESERVED_CHANNEL 0x1f
176#define NCSI_CHANNEL_INDEX(c) ((c) & ((1 << NCSI_PACKAGE_SHIFT) - 1)) 176#define NCSI_CHANNEL_INDEX(c) ((c) & ((1 << NCSI_PACKAGE_SHIFT) - 1))
177#define NCSI_TO_CHANNEL(p, c) (((p) << NCSI_PACKAGE_SHIFT) | (c)) 177#define NCSI_TO_CHANNEL(p, c) (((p) << NCSI_PACKAGE_SHIFT) | (c))
178#define NCSI_MAX_PACKAGE 8
179#define NCSI_MAX_CHANNEL 32
178 180
179struct ncsi_channel { 181struct ncsi_channel {
180 unsigned char id; 182 unsigned char id;
@@ -220,11 +222,15 @@ struct ncsi_request {
220 bool used; /* Request that has been assigned */ 222 bool used; /* Request that has been assigned */
221 unsigned int flags; /* NCSI request property */ 223 unsigned int flags; /* NCSI request property */
222#define NCSI_REQ_FLAG_EVENT_DRIVEN 1 224#define NCSI_REQ_FLAG_EVENT_DRIVEN 1
225#define NCSI_REQ_FLAG_NETLINK_DRIVEN 2
223 struct ncsi_dev_priv *ndp; /* Associated NCSI device */ 226 struct ncsi_dev_priv *ndp; /* Associated NCSI device */
224 struct sk_buff *cmd; /* Associated NCSI command packet */ 227 struct sk_buff *cmd; /* Associated NCSI command packet */
225 struct sk_buff *rsp; /* Associated NCSI response packet */ 228 struct sk_buff *rsp; /* Associated NCSI response packet */
226 struct timer_list timer; /* Timer on waiting for response */ 229 struct timer_list timer; /* Timer on waiting for response */
227 bool enabled; /* Time has been enabled or not */ 230 bool enabled; /* Time has been enabled or not */
231 u32 snd_seq; /* netlink sending sequence number */
232 u32 snd_portid; /* netlink portid of sender */
233 struct nlmsghdr nlhdr; /* netlink message header */
228}; 234};
229 235
230enum { 236enum {
@@ -310,6 +316,7 @@ struct ncsi_cmd_arg {
310 unsigned int dwords[4]; 316 unsigned int dwords[4];
311 }; 317 };
312 unsigned char *data; /* NCSI OEM data */ 318 unsigned char *data; /* NCSI OEM data */
319 struct genl_info *info; /* Netlink information */
313}; 320};
314 321
315extern struct list_head ncsi_dev_list; 322extern struct list_head ncsi_dev_list;
diff --git a/net/ncsi/ncsi-cmd.c b/net/ncsi/ncsi-cmd.c
index 82b7d9201db8..356af474e43c 100644
--- a/net/ncsi/ncsi-cmd.c
+++ b/net/ncsi/ncsi-cmd.c
@@ -17,6 +17,7 @@
17#include <net/ncsi.h> 17#include <net/ncsi.h>
18#include <net/net_namespace.h> 18#include <net/net_namespace.h>
19#include <net/sock.h> 19#include <net/sock.h>
20#include <net/genetlink.h>
20 21
21#include "internal.h" 22#include "internal.h"
22#include "ncsi-pkt.h" 23#include "ncsi-pkt.h"
@@ -346,6 +347,13 @@ int ncsi_xmit_cmd(struct ncsi_cmd_arg *nca)
346 if (!nr) 347 if (!nr)
347 return -ENOMEM; 348 return -ENOMEM;
348 349
350 /* track netlink information */
351 if (nca->req_flags == NCSI_REQ_FLAG_NETLINK_DRIVEN) {
352 nr->snd_seq = nca->info->snd_seq;
353 nr->snd_portid = nca->info->snd_portid;
354 nr->nlhdr = *nca->info->nlhdr;
355 }
356
349 /* Prepare the packet */ 357 /* Prepare the packet */
350 nca->id = nr->id; 358 nca->id = nr->id;
351 ret = nch->handler(nr->cmd, nca); 359 ret = nch->handler(nr->cmd, nca);
diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c
index 091284760d21..6aa0614d2d28 100644
--- a/net/ncsi/ncsi-manage.c
+++ b/net/ncsi/ncsi-manage.c
@@ -19,6 +19,7 @@
19#include <net/addrconf.h> 19#include <net/addrconf.h>
20#include <net/ipv6.h> 20#include <net/ipv6.h>
21#include <net/if_inet6.h> 21#include <net/if_inet6.h>
22#include <net/genetlink.h>
22 23
23#include "internal.h" 24#include "internal.h"
24#include "ncsi-pkt.h" 25#include "ncsi-pkt.h"
@@ -406,6 +407,9 @@ static void ncsi_request_timeout(struct timer_list *t)
406{ 407{
407 struct ncsi_request *nr = from_timer(nr, t, timer); 408 struct ncsi_request *nr = from_timer(nr, t, timer);
408 struct ncsi_dev_priv *ndp = nr->ndp; 409 struct ncsi_dev_priv *ndp = nr->ndp;
410 struct ncsi_cmd_pkt *cmd;
411 struct ncsi_package *np;
412 struct ncsi_channel *nc;
409 unsigned long flags; 413 unsigned long flags;
410 414
411 /* If the request already had associated response, 415 /* If the request already had associated response,
@@ -419,6 +423,18 @@ static void ncsi_request_timeout(struct timer_list *t)
419 } 423 }
420 spin_unlock_irqrestore(&ndp->lock, flags); 424 spin_unlock_irqrestore(&ndp->lock, flags);
421 425
426 if (nr->flags == NCSI_REQ_FLAG_NETLINK_DRIVEN) {
427 if (nr->cmd) {
428 /* Find the package */
429 cmd = (struct ncsi_cmd_pkt *)
430 skb_network_header(nr->cmd);
431 ncsi_find_package_and_channel(ndp,
432 cmd->cmd.common.channel,
433 &np, &nc);
434 ncsi_send_netlink_timeout(nr, np, nc);
435 }
436 }
437
422 /* Release the request */ 438 /* Release the request */
423 ncsi_free_request(nr); 439 ncsi_free_request(nr);
424} 440}
diff --git a/net/ncsi/ncsi-netlink.c b/net/ncsi/ncsi-netlink.c
index 32cb7751d216..33314381b4f5 100644
--- a/net/ncsi/ncsi-netlink.c
+++ b/net/ncsi/ncsi-netlink.c
@@ -19,6 +19,7 @@
19#include <uapi/linux/ncsi.h> 19#include <uapi/linux/ncsi.h>
20 20
21#include "internal.h" 21#include "internal.h"
22#include "ncsi-pkt.h"
22#include "ncsi-netlink.h" 23#include "ncsi-netlink.h"
23 24
24static struct genl_family ncsi_genl_family; 25static struct genl_family ncsi_genl_family;
@@ -28,6 +29,7 @@ static const struct nla_policy ncsi_genl_policy[NCSI_ATTR_MAX + 1] = {
28 [NCSI_ATTR_PACKAGE_LIST] = { .type = NLA_NESTED }, 29 [NCSI_ATTR_PACKAGE_LIST] = { .type = NLA_NESTED },
29 [NCSI_ATTR_PACKAGE_ID] = { .type = NLA_U32 }, 30 [NCSI_ATTR_PACKAGE_ID] = { .type = NLA_U32 },
30 [NCSI_ATTR_CHANNEL_ID] = { .type = NLA_U32 }, 31 [NCSI_ATTR_CHANNEL_ID] = { .type = NLA_U32 },
32 [NCSI_ATTR_DATA] = { .type = NLA_BINARY, .len = 2048 },
31}; 33};
32 34
33static struct ncsi_dev_priv *ndp_from_ifindex(struct net *net, u32 ifindex) 35static struct ncsi_dev_priv *ndp_from_ifindex(struct net *net, u32 ifindex)
@@ -365,6 +367,202 @@ static int ncsi_clear_interface_nl(struct sk_buff *msg, struct genl_info *info)
365 return 0; 367 return 0;
366} 368}
367 369
370static int ncsi_send_cmd_nl(struct sk_buff *msg, struct genl_info *info)
371{
372 struct ncsi_dev_priv *ndp;
373 struct ncsi_pkt_hdr *hdr;
374 struct ncsi_cmd_arg nca;
375 unsigned char *data;
376 u32 package_id;
377 u32 channel_id;
378 int len, ret;
379
380 if (!info || !info->attrs) {
381 ret = -EINVAL;
382 goto out;
383 }
384
385 if (!info->attrs[NCSI_ATTR_IFINDEX]) {
386 ret = -EINVAL;
387 goto out;
388 }
389
390 if (!info->attrs[NCSI_ATTR_PACKAGE_ID]) {
391 ret = -EINVAL;
392 goto out;
393 }
394
395 if (!info->attrs[NCSI_ATTR_CHANNEL_ID]) {
396 ret = -EINVAL;
397 goto out;
398 }
399
400 if (!info->attrs[NCSI_ATTR_DATA]) {
401 ret = -EINVAL;
402 goto out;
403 }
404
405 ndp = ndp_from_ifindex(get_net(sock_net(msg->sk)),
406 nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX]));
407 if (!ndp) {
408 ret = -ENODEV;
409 goto out;
410 }
411
412 package_id = nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_ID]);
413 channel_id = nla_get_u32(info->attrs[NCSI_ATTR_CHANNEL_ID]);
414
415 if (package_id >= NCSI_MAX_PACKAGE || channel_id >= NCSI_MAX_CHANNEL) {
416 ret = -ERANGE;
417 goto out_netlink;
418 }
419
420 len = nla_len(info->attrs[NCSI_ATTR_DATA]);
421 if (len < sizeof(struct ncsi_pkt_hdr)) {
422 netdev_info(ndp->ndev.dev, "NCSI: no command to send %u\n",
423 package_id);
424 ret = -EINVAL;
425 goto out_netlink;
426 } else {
427 data = (unsigned char *)nla_data(info->attrs[NCSI_ATTR_DATA]);
428 }
429
430 hdr = (struct ncsi_pkt_hdr *)data;
431
432 nca.ndp = ndp;
433 nca.package = (unsigned char)package_id;
434 nca.channel = (unsigned char)channel_id;
435 nca.type = hdr->type;
436 nca.req_flags = NCSI_REQ_FLAG_NETLINK_DRIVEN;
437 nca.info = info;
438 nca.payload = ntohs(hdr->length);
439 nca.data = data + sizeof(*hdr);
440
441 ret = ncsi_xmit_cmd(&nca);
442out_netlink:
443 if (ret != 0) {
444 netdev_err(ndp->ndev.dev,
445 "NCSI: Error %d sending command\n",
446 ret);
447 ncsi_send_netlink_err(ndp->ndev.dev,
448 info->snd_seq,
449 info->snd_portid,
450 info->nlhdr,
451 ret);
452 }
453out:
454 return ret;
455}
456
457int ncsi_send_netlink_rsp(struct ncsi_request *nr,
458 struct ncsi_package *np,
459 struct ncsi_channel *nc)
460{
461 struct sk_buff *skb;
462 struct net *net;
463 void *hdr;
464 int rc;
465
466 net = dev_net(nr->rsp->dev);
467
468 skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
469 if (!skb)
470 return -ENOMEM;
471
472 hdr = genlmsg_put(skb, nr->snd_portid, nr->snd_seq,
473 &ncsi_genl_family, 0, NCSI_CMD_SEND_CMD);
474 if (!hdr) {
475 kfree_skb(skb);
476 return -EMSGSIZE;
477 }
478
479 nla_put_u32(skb, NCSI_ATTR_IFINDEX, nr->rsp->dev->ifindex);
480 if (np)
481 nla_put_u32(skb, NCSI_ATTR_PACKAGE_ID, np->id);
482 if (nc)
483 nla_put_u32(skb, NCSI_ATTR_CHANNEL_ID, nc->id);
484 else
485 nla_put_u32(skb, NCSI_ATTR_CHANNEL_ID, NCSI_RESERVED_CHANNEL);
486
487 rc = nla_put(skb, NCSI_ATTR_DATA, nr->rsp->len, (void *)nr->rsp->data);
488 if (rc)
489 goto err;
490
491 genlmsg_end(skb, hdr);
492 return genlmsg_unicast(net, skb, nr->snd_portid);
493
494err:
495 kfree_skb(skb);
496 return rc;
497}
498
499int ncsi_send_netlink_timeout(struct ncsi_request *nr,
500 struct ncsi_package *np,
501 struct ncsi_channel *nc)
502{
503 struct sk_buff *skb;
504 struct net *net;
505 void *hdr;
506
507 skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
508 if (!skb)
509 return -ENOMEM;
510
511 hdr = genlmsg_put(skb, nr->snd_portid, nr->snd_seq,
512 &ncsi_genl_family, 0, NCSI_CMD_SEND_CMD);
513 if (!hdr) {
514 kfree_skb(skb);
515 return -EMSGSIZE;
516 }
517
518 net = dev_net(nr->cmd->dev);
519
520 nla_put_u32(skb, NCSI_ATTR_IFINDEX, nr->cmd->dev->ifindex);
521
522 if (np)
523 nla_put_u32(skb, NCSI_ATTR_PACKAGE_ID, np->id);
524 else
525 nla_put_u32(skb, NCSI_ATTR_PACKAGE_ID,
526 NCSI_PACKAGE_INDEX((((struct ncsi_pkt_hdr *)
527 nr->cmd->data)->channel)));
528
529 if (nc)
530 nla_put_u32(skb, NCSI_ATTR_CHANNEL_ID, nc->id);
531 else
532 nla_put_u32(skb, NCSI_ATTR_CHANNEL_ID, NCSI_RESERVED_CHANNEL);
533
534 genlmsg_end(skb, hdr);
535 return genlmsg_unicast(net, skb, nr->snd_portid);
536}
537
538int ncsi_send_netlink_err(struct net_device *dev,
539 u32 snd_seq,
540 u32 snd_portid,
541 struct nlmsghdr *nlhdr,
542 int err)
543{
544 struct nlmsghdr *nlh;
545 struct nlmsgerr *nle;
546 struct sk_buff *skb;
547 struct net *net;
548
549 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
550 if (!skb)
551 return -ENOMEM;
552
553 net = dev_net(dev);
554
555 nlh = nlmsg_put(skb, snd_portid, snd_seq,
556 NLMSG_ERROR, sizeof(*nle), 0);
557 nle = (struct nlmsgerr *)nlmsg_data(nlh);
558 nle->error = err;
559 memcpy(&nle->msg, nlhdr, sizeof(*nlh));
560
561 nlmsg_end(skb, nlh);
562
563 return nlmsg_unicast(net->genl_sock, skb, snd_portid);
564}
565
368static const struct genl_ops ncsi_ops[] = { 566static const struct genl_ops ncsi_ops[] = {
369 { 567 {
370 .cmd = NCSI_CMD_PKG_INFO, 568 .cmd = NCSI_CMD_PKG_INFO,
@@ -385,6 +583,12 @@ static const struct genl_ops ncsi_ops[] = {
385 .doit = ncsi_clear_interface_nl, 583 .doit = ncsi_clear_interface_nl,
386 .flags = GENL_ADMIN_PERM, 584 .flags = GENL_ADMIN_PERM,
387 }, 585 },
586 {
587 .cmd = NCSI_CMD_SEND_CMD,
588 .policy = ncsi_genl_policy,
589 .doit = ncsi_send_cmd_nl,
590 .flags = GENL_ADMIN_PERM,
591 },
388}; 592};
389 593
390static struct genl_family ncsi_genl_family __ro_after_init = { 594static struct genl_family ncsi_genl_family __ro_after_init = {
diff --git a/net/ncsi/ncsi-netlink.h b/net/ncsi/ncsi-netlink.h
index 91a5c256f8c4..c4a46887a932 100644
--- a/net/ncsi/ncsi-netlink.h
+++ b/net/ncsi/ncsi-netlink.h
@@ -14,6 +14,18 @@
14 14
15#include "internal.h" 15#include "internal.h"
16 16
17int ncsi_send_netlink_rsp(struct ncsi_request *nr,
18 struct ncsi_package *np,
19 struct ncsi_channel *nc);
20int ncsi_send_netlink_timeout(struct ncsi_request *nr,
21 struct ncsi_package *np,
22 struct ncsi_channel *nc);
23int ncsi_send_netlink_err(struct net_device *dev,
24 u32 snd_seq,
25 u32 snd_portid,
26 struct nlmsghdr *nlhdr,
27 int err);
28
17int ncsi_init_netlink(struct net_device *dev); 29int ncsi_init_netlink(struct net_device *dev);
18int ncsi_unregister_netlink(struct net_device *dev); 30int ncsi_unregister_netlink(struct net_device *dev);
19 31
diff --git a/net/ncsi/ncsi-rsp.c b/net/ncsi/ncsi-rsp.c
index d66b34749027..85fa59afae34 100644
--- a/net/ncsi/ncsi-rsp.c
+++ b/net/ncsi/ncsi-rsp.c
@@ -16,9 +16,11 @@
16#include <net/ncsi.h> 16#include <net/ncsi.h>
17#include <net/net_namespace.h> 17#include <net/net_namespace.h>
18#include <net/sock.h> 18#include <net/sock.h>
19#include <net/genetlink.h>
19 20
20#include "internal.h" 21#include "internal.h"
21#include "ncsi-pkt.h" 22#include "ncsi-pkt.h"
23#include "ncsi-netlink.h"
22 24
23static int ncsi_validate_rsp_pkt(struct ncsi_request *nr, 25static int ncsi_validate_rsp_pkt(struct ncsi_request *nr,
24 unsigned short payload) 26 unsigned short payload)
@@ -32,15 +34,25 @@ static int ncsi_validate_rsp_pkt(struct ncsi_request *nr,
32 * before calling this function. 34 * before calling this function.
33 */ 35 */
34 h = (struct ncsi_rsp_pkt_hdr *)skb_network_header(nr->rsp); 36 h = (struct ncsi_rsp_pkt_hdr *)skb_network_header(nr->rsp);
35 if (h->common.revision != NCSI_PKT_REVISION) 37
38 if (h->common.revision != NCSI_PKT_REVISION) {
39 netdev_dbg(nr->ndp->ndev.dev,
40 "NCSI: unsupported header revision\n");
36 return -EINVAL; 41 return -EINVAL;
37 if (ntohs(h->common.length) != payload) 42 }
43 if (ntohs(h->common.length) != payload) {
44 netdev_dbg(nr->ndp->ndev.dev,
45 "NCSI: payload length mismatched\n");
38 return -EINVAL; 46 return -EINVAL;
47 }
39 48
40 /* Check on code and reason */ 49 /* Check on code and reason */
41 if (ntohs(h->code) != NCSI_PKT_RSP_C_COMPLETED || 50 if (ntohs(h->code) != NCSI_PKT_RSP_C_COMPLETED ||
42 ntohs(h->reason) != NCSI_PKT_RSP_R_NO_ERROR) 51 ntohs(h->reason) != NCSI_PKT_RSP_R_NO_ERROR) {
43 return -EINVAL; 52 netdev_dbg(nr->ndp->ndev.dev,
53 "NCSI: non zero response/reason code\n");
54 return -EPERM;
55 }
44 56
45 /* Validate checksum, which might be zeroes if the 57 /* Validate checksum, which might be zeroes if the
46 * sender doesn't support checksum according to NCSI 58 * sender doesn't support checksum according to NCSI
@@ -52,8 +64,11 @@ static int ncsi_validate_rsp_pkt(struct ncsi_request *nr,
52 64
53 checksum = ncsi_calculate_checksum((unsigned char *)h, 65 checksum = ncsi_calculate_checksum((unsigned char *)h,
54 sizeof(*h) + payload - 4); 66 sizeof(*h) + payload - 4);
55 if (*pchecksum != htonl(checksum)) 67
68 if (*pchecksum != htonl(checksum)) {
69 netdev_dbg(nr->ndp->ndev.dev, "NCSI: checksum mismatched\n");
56 return -EINVAL; 70 return -EINVAL;
71 }
57 72
58 return 0; 73 return 0;
59} 74}
@@ -941,6 +956,26 @@ static int ncsi_rsp_handler_gpuuid(struct ncsi_request *nr)
941 return 0; 956 return 0;
942} 957}
943 958
959static int ncsi_rsp_handler_netlink(struct ncsi_request *nr)
960{
961 struct ncsi_dev_priv *ndp = nr->ndp;
962 struct ncsi_rsp_pkt *rsp;
963 struct ncsi_package *np;
964 struct ncsi_channel *nc;
965 int ret;
966
967 /* Find the package */
968 rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
969 ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
970 &np, &nc);
971 if (!np)
972 return -ENODEV;
973
974 ret = ncsi_send_netlink_rsp(nr, np, nc);
975
976 return ret;
977}
978
944static struct ncsi_rsp_handler { 979static struct ncsi_rsp_handler {
945 unsigned char type; 980 unsigned char type;
946 int payload; 981 int payload;
@@ -1043,6 +1078,17 @@ int ncsi_rcv_rsp(struct sk_buff *skb, struct net_device *dev,
1043 netdev_warn(ndp->ndev.dev, 1078 netdev_warn(ndp->ndev.dev,
1044 "NCSI: 'bad' packet ignored for type 0x%x\n", 1079 "NCSI: 'bad' packet ignored for type 0x%x\n",
1045 hdr->type); 1080 hdr->type);
1081
1082 if (nr->flags == NCSI_REQ_FLAG_NETLINK_DRIVEN) {
1083 if (ret == -EPERM)
1084 goto out_netlink;
1085 else
1086 ncsi_send_netlink_err(ndp->ndev.dev,
1087 nr->snd_seq,
1088 nr->snd_portid,
1089 &nr->nlhdr,
1090 ret);
1091 }
1046 goto out; 1092 goto out;
1047 } 1093 }
1048 1094
@@ -1052,6 +1098,17 @@ int ncsi_rcv_rsp(struct sk_buff *skb, struct net_device *dev,
1052 netdev_err(ndp->ndev.dev, 1098 netdev_err(ndp->ndev.dev,
1053 "NCSI: Handler for packet type 0x%x returned %d\n", 1099 "NCSI: Handler for packet type 0x%x returned %d\n",
1054 hdr->type, ret); 1100 hdr->type, ret);
1101
1102out_netlink:
1103 if (nr->flags == NCSI_REQ_FLAG_NETLINK_DRIVEN) {
1104 ret = ncsi_rsp_handler_netlink(nr);
1105 if (ret) {
1106 netdev_err(ndp->ndev.dev,
1107 "NCSI: Netlink handler for packet type 0x%x returned %d\n",
1108 hdr->type, ret);
1109 }
1110 }
1111
1055out: 1112out:
1056 ncsi_free_request(nr); 1113 ncsi_free_request(nr);
1057 return ret; 1114 return ret;