diff options
author | Justin.Lee1@Dell.com <Justin.Lee1@Dell.com> | 2018-10-11 14:07:37 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-10-16 01:00:59 -0400 |
commit | 9771b8ccdfa6dcb1ac5128ca7fe8649f3092d392 (patch) | |
tree | c685a032ce049cb71428c0019925aeb7c5f2cda3 /net/ncsi | |
parent | 6384e483239fd07a2d4393f888027118fecd4c6e (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.h | 7 | ||||
-rw-r--r-- | net/ncsi/ncsi-cmd.c | 8 | ||||
-rw-r--r-- | net/ncsi/ncsi-manage.c | 16 | ||||
-rw-r--r-- | net/ncsi/ncsi-netlink.c | 204 | ||||
-rw-r--r-- | net/ncsi/ncsi-netlink.h | 12 | ||||
-rw-r--r-- | net/ncsi/ncsi-rsp.c | 67 |
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 | ||
179 | struct ncsi_channel { | 181 | struct 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 | ||
230 | enum { | 236 | enum { |
@@ -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 | ||
315 | extern struct list_head ncsi_dev_list; | 322 | extern 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 | ||
24 | static struct genl_family ncsi_genl_family; | 25 | static 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 | ||
33 | static struct ncsi_dev_priv *ndp_from_ifindex(struct net *net, u32 ifindex) | 35 | static 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 | ||
370 | static 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); | ||
442 | out_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 | } | ||
453 | out: | ||
454 | return ret; | ||
455 | } | ||
456 | |||
457 | int 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 | |||
494 | err: | ||
495 | kfree_skb(skb); | ||
496 | return rc; | ||
497 | } | ||
498 | |||
499 | int 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 | |||
538 | int 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 | |||
368 | static const struct genl_ops ncsi_ops[] = { | 566 | static 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 | ||
390 | static struct genl_family ncsi_genl_family __ro_after_init = { | 594 | static 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 | ||
17 | int ncsi_send_netlink_rsp(struct ncsi_request *nr, | ||
18 | struct ncsi_package *np, | ||
19 | struct ncsi_channel *nc); | ||
20 | int ncsi_send_netlink_timeout(struct ncsi_request *nr, | ||
21 | struct ncsi_package *np, | ||
22 | struct ncsi_channel *nc); | ||
23 | int ncsi_send_netlink_err(struct net_device *dev, | ||
24 | u32 snd_seq, | ||
25 | u32 snd_portid, | ||
26 | struct nlmsghdr *nlhdr, | ||
27 | int err); | ||
28 | |||
17 | int ncsi_init_netlink(struct net_device *dev); | 29 | int ncsi_init_netlink(struct net_device *dev); |
18 | int ncsi_unregister_netlink(struct net_device *dev); | 30 | int 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 | ||
23 | static int ncsi_validate_rsp_pkt(struct ncsi_request *nr, | 25 | static 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 | ||
959 | static 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 | |||
944 | static struct ncsi_rsp_handler { | 979 | static 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 | |||
1102 | out_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 | |||
1055 | out: | 1112 | out: |
1056 | ncsi_free_request(nr); | 1113 | ncsi_free_request(nr); |
1057 | return ret; | 1114 | return ret; |