Commit 9771b8cc authored by Justin.Lee1@Dell.com's avatar Justin.Lee1@Dell.com Committed by David S. Miller

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: default avatarJustin Lee <justin.lee1@dell.com>
Reviewed-by: default avatarSamuel Mendoza-Jonas <sam@mendozajonas.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6384e483
...@@ -23,6 +23,9 @@ ...@@ -23,6 +23,9 @@
* optionally the preferred NCSI_ATTR_CHANNEL_ID. * optionally the preferred NCSI_ATTR_CHANNEL_ID.
* @NCSI_CMD_CLEAR_INTERFACE: clear any preferred package/channel combination. * @NCSI_CMD_CLEAR_INTERFACE: clear any preferred package/channel combination.
* Requires NCSI_ATTR_IFINDEX. * Requires NCSI_ATTR_IFINDEX.
* @NCSI_CMD_SEND_CMD: send NC-SI command to network card.
* Requires NCSI_ATTR_IFINDEX, NCSI_ATTR_PACKAGE_ID
* and NCSI_ATTR_CHANNEL_ID.
* @NCSI_CMD_MAX: highest command number * @NCSI_CMD_MAX: highest command number
*/ */
enum ncsi_nl_commands { enum ncsi_nl_commands {
...@@ -30,6 +33,7 @@ enum ncsi_nl_commands { ...@@ -30,6 +33,7 @@ enum ncsi_nl_commands {
NCSI_CMD_PKG_INFO, NCSI_CMD_PKG_INFO,
NCSI_CMD_SET_INTERFACE, NCSI_CMD_SET_INTERFACE,
NCSI_CMD_CLEAR_INTERFACE, NCSI_CMD_CLEAR_INTERFACE,
NCSI_CMD_SEND_CMD,
__NCSI_CMD_AFTER_LAST, __NCSI_CMD_AFTER_LAST,
NCSI_CMD_MAX = __NCSI_CMD_AFTER_LAST - 1 NCSI_CMD_MAX = __NCSI_CMD_AFTER_LAST - 1
...@@ -43,6 +47,7 @@ enum ncsi_nl_commands { ...@@ -43,6 +47,7 @@ enum ncsi_nl_commands {
* @NCSI_ATTR_PACKAGE_LIST: nested array of NCSI_PKG_ATTR attributes * @NCSI_ATTR_PACKAGE_LIST: nested array of NCSI_PKG_ATTR attributes
* @NCSI_ATTR_PACKAGE_ID: package ID * @NCSI_ATTR_PACKAGE_ID: package ID
* @NCSI_ATTR_CHANNEL_ID: channel ID * @NCSI_ATTR_CHANNEL_ID: channel ID
* @NCSI_ATTR_DATA: command payload
* @NCSI_ATTR_MAX: highest attribute number * @NCSI_ATTR_MAX: highest attribute number
*/ */
enum ncsi_nl_attrs { enum ncsi_nl_attrs {
...@@ -51,6 +56,7 @@ enum ncsi_nl_attrs { ...@@ -51,6 +56,7 @@ enum ncsi_nl_attrs {
NCSI_ATTR_PACKAGE_LIST, NCSI_ATTR_PACKAGE_LIST,
NCSI_ATTR_PACKAGE_ID, NCSI_ATTR_PACKAGE_ID,
NCSI_ATTR_CHANNEL_ID, NCSI_ATTR_CHANNEL_ID,
NCSI_ATTR_DATA,
__NCSI_ATTR_AFTER_LAST, __NCSI_ATTR_AFTER_LAST,
NCSI_ATTR_MAX = __NCSI_ATTR_AFTER_LAST - 1 NCSI_ATTR_MAX = __NCSI_ATTR_AFTER_LAST - 1
......
...@@ -175,6 +175,8 @@ struct ncsi_package; ...@@ -175,6 +175,8 @@ struct ncsi_package;
#define NCSI_RESERVED_CHANNEL 0x1f #define NCSI_RESERVED_CHANNEL 0x1f
#define NCSI_CHANNEL_INDEX(c) ((c) & ((1 << NCSI_PACKAGE_SHIFT) - 1)) #define NCSI_CHANNEL_INDEX(c) ((c) & ((1 << NCSI_PACKAGE_SHIFT) - 1))
#define NCSI_TO_CHANNEL(p, c) (((p) << NCSI_PACKAGE_SHIFT) | (c)) #define NCSI_TO_CHANNEL(p, c) (((p) << NCSI_PACKAGE_SHIFT) | (c))
#define NCSI_MAX_PACKAGE 8
#define NCSI_MAX_CHANNEL 32
struct ncsi_channel { struct ncsi_channel {
unsigned char id; unsigned char id;
...@@ -220,11 +222,15 @@ struct ncsi_request { ...@@ -220,11 +222,15 @@ struct ncsi_request {
bool used; /* Request that has been assigned */ bool used; /* Request that has been assigned */
unsigned int flags; /* NCSI request property */ unsigned int flags; /* NCSI request property */
#define NCSI_REQ_FLAG_EVENT_DRIVEN 1 #define NCSI_REQ_FLAG_EVENT_DRIVEN 1
#define NCSI_REQ_FLAG_NETLINK_DRIVEN 2
struct ncsi_dev_priv *ndp; /* Associated NCSI device */ struct ncsi_dev_priv *ndp; /* Associated NCSI device */
struct sk_buff *cmd; /* Associated NCSI command packet */ struct sk_buff *cmd; /* Associated NCSI command packet */
struct sk_buff *rsp; /* Associated NCSI response packet */ struct sk_buff *rsp; /* Associated NCSI response packet */
struct timer_list timer; /* Timer on waiting for response */ struct timer_list timer; /* Timer on waiting for response */
bool enabled; /* Time has been enabled or not */ bool enabled; /* Time has been enabled or not */
u32 snd_seq; /* netlink sending sequence number */
u32 snd_portid; /* netlink portid of sender */
struct nlmsghdr nlhdr; /* netlink message header */
}; };
enum { enum {
...@@ -310,6 +316,7 @@ struct ncsi_cmd_arg { ...@@ -310,6 +316,7 @@ struct ncsi_cmd_arg {
unsigned int dwords[4]; unsigned int dwords[4];
}; };
unsigned char *data; /* NCSI OEM data */ unsigned char *data; /* NCSI OEM data */
struct genl_info *info; /* Netlink information */
}; };
extern struct list_head ncsi_dev_list; extern struct list_head ncsi_dev_list;
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <net/ncsi.h> #include <net/ncsi.h>
#include <net/net_namespace.h> #include <net/net_namespace.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/genetlink.h>
#include "internal.h" #include "internal.h"
#include "ncsi-pkt.h" #include "ncsi-pkt.h"
...@@ -346,6 +347,13 @@ int ncsi_xmit_cmd(struct ncsi_cmd_arg *nca) ...@@ -346,6 +347,13 @@ int ncsi_xmit_cmd(struct ncsi_cmd_arg *nca)
if (!nr) if (!nr)
return -ENOMEM; return -ENOMEM;
/* track netlink information */
if (nca->req_flags == NCSI_REQ_FLAG_NETLINK_DRIVEN) {
nr->snd_seq = nca->info->snd_seq;
nr->snd_portid = nca->info->snd_portid;
nr->nlhdr = *nca->info->nlhdr;
}
/* Prepare the packet */ /* Prepare the packet */
nca->id = nr->id; nca->id = nr->id;
ret = nch->handler(nr->cmd, nca); ret = nch->handler(nr->cmd, nca);
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <net/addrconf.h> #include <net/addrconf.h>
#include <net/ipv6.h> #include <net/ipv6.h>
#include <net/if_inet6.h> #include <net/if_inet6.h>
#include <net/genetlink.h>
#include "internal.h" #include "internal.h"
#include "ncsi-pkt.h" #include "ncsi-pkt.h"
...@@ -406,6 +407,9 @@ static void ncsi_request_timeout(struct timer_list *t) ...@@ -406,6 +407,9 @@ static void ncsi_request_timeout(struct timer_list *t)
{ {
struct ncsi_request *nr = from_timer(nr, t, timer); struct ncsi_request *nr = from_timer(nr, t, timer);
struct ncsi_dev_priv *ndp = nr->ndp; struct ncsi_dev_priv *ndp = nr->ndp;
struct ncsi_cmd_pkt *cmd;
struct ncsi_package *np;
struct ncsi_channel *nc;
unsigned long flags; unsigned long flags;
/* If the request already had associated response, /* If the request already had associated response,
...@@ -419,6 +423,18 @@ static void ncsi_request_timeout(struct timer_list *t) ...@@ -419,6 +423,18 @@ static void ncsi_request_timeout(struct timer_list *t)
} }
spin_unlock_irqrestore(&ndp->lock, flags); spin_unlock_irqrestore(&ndp->lock, flags);
if (nr->flags == NCSI_REQ_FLAG_NETLINK_DRIVEN) {
if (nr->cmd) {
/* Find the package */
cmd = (struct ncsi_cmd_pkt *)
skb_network_header(nr->cmd);
ncsi_find_package_and_channel(ndp,
cmd->cmd.common.channel,
&np, &nc);
ncsi_send_netlink_timeout(nr, np, nc);
}
}
/* Release the request */ /* Release the request */
ncsi_free_request(nr); ncsi_free_request(nr);
} }
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <uapi/linux/ncsi.h> #include <uapi/linux/ncsi.h>
#include "internal.h" #include "internal.h"
#include "ncsi-pkt.h"
#include "ncsi-netlink.h" #include "ncsi-netlink.h"
static struct genl_family ncsi_genl_family; static struct genl_family ncsi_genl_family;
...@@ -28,6 +29,7 @@ static const struct nla_policy ncsi_genl_policy[NCSI_ATTR_MAX + 1] = { ...@@ -28,6 +29,7 @@ static const struct nla_policy ncsi_genl_policy[NCSI_ATTR_MAX + 1] = {
[NCSI_ATTR_PACKAGE_LIST] = { .type = NLA_NESTED }, [NCSI_ATTR_PACKAGE_LIST] = { .type = NLA_NESTED },
[NCSI_ATTR_PACKAGE_ID] = { .type = NLA_U32 }, [NCSI_ATTR_PACKAGE_ID] = { .type = NLA_U32 },
[NCSI_ATTR_CHANNEL_ID] = { .type = NLA_U32 }, [NCSI_ATTR_CHANNEL_ID] = { .type = NLA_U32 },
[NCSI_ATTR_DATA] = { .type = NLA_BINARY, .len = 2048 },
}; };
static struct ncsi_dev_priv *ndp_from_ifindex(struct net *net, u32 ifindex) 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,6 +367,202 @@ static int ncsi_clear_interface_nl(struct sk_buff *msg, struct genl_info *info)
return 0; return 0;
} }
static int ncsi_send_cmd_nl(struct sk_buff *msg, struct genl_info *info)
{
struct ncsi_dev_priv *ndp;
struct ncsi_pkt_hdr *hdr;
struct ncsi_cmd_arg nca;
unsigned char *data;
u32 package_id;
u32 channel_id;
int len, ret;
if (!info || !info->attrs) {
ret = -EINVAL;
goto out;
}
if (!info->attrs[NCSI_ATTR_IFINDEX]) {
ret = -EINVAL;
goto out;
}
if (!info->attrs[NCSI_ATTR_PACKAGE_ID]) {
ret = -EINVAL;
goto out;
}
if (!info->attrs[NCSI_ATTR_CHANNEL_ID]) {
ret = -EINVAL;
goto out;
}
if (!info->attrs[NCSI_ATTR_DATA]) {
ret = -EINVAL;
goto out;
}
ndp = ndp_from_ifindex(get_net(sock_net(msg->sk)),
nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX]));
if (!ndp) {
ret = -ENODEV;
goto out;
}
package_id = nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_ID]);
channel_id = nla_get_u32(info->attrs[NCSI_ATTR_CHANNEL_ID]);
if (package_id >= NCSI_MAX_PACKAGE || channel_id >= NCSI_MAX_CHANNEL) {
ret = -ERANGE;
goto out_netlink;
}
len = nla_len(info->attrs[NCSI_ATTR_DATA]);
if (len < sizeof(struct ncsi_pkt_hdr)) {
netdev_info(ndp->ndev.dev, "NCSI: no command to send %u\n",
package_id);
ret = -EINVAL;
goto out_netlink;
} else {
data = (unsigned char *)nla_data(info->attrs[NCSI_ATTR_DATA]);
}
hdr = (struct ncsi_pkt_hdr *)data;
nca.ndp = ndp;
nca.package = (unsigned char)package_id;
nca.channel = (unsigned char)channel_id;
nca.type = hdr->type;
nca.req_flags = NCSI_REQ_FLAG_NETLINK_DRIVEN;
nca.info = info;
nca.payload = ntohs(hdr->length);
nca.data = data + sizeof(*hdr);
ret = ncsi_xmit_cmd(&nca);
out_netlink:
if (ret != 0) {
netdev_err(ndp->ndev.dev,
"NCSI: Error %d sending command\n",
ret);
ncsi_send_netlink_err(ndp->ndev.dev,
info->snd_seq,
info->snd_portid,
info->nlhdr,
ret);
}
out:
return ret;
}
int ncsi_send_netlink_rsp(struct ncsi_request *nr,
struct ncsi_package *np,
struct ncsi_channel *nc)
{
struct sk_buff *skb;
struct net *net;
void *hdr;
int rc;
net = dev_net(nr->rsp->dev);
skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
if (!skb)
return -ENOMEM;
hdr = genlmsg_put(skb, nr->snd_portid, nr->snd_seq,
&ncsi_genl_family, 0, NCSI_CMD_SEND_CMD);
if (!hdr) {
kfree_skb(skb);
return -EMSGSIZE;
}
nla_put_u32(skb, NCSI_ATTR_IFINDEX, nr->rsp->dev->ifindex);
if (np)
nla_put_u32(skb, NCSI_ATTR_PACKAGE_ID, np->id);
if (nc)
nla_put_u32(skb, NCSI_ATTR_CHANNEL_ID, nc->id);
else
nla_put_u32(skb, NCSI_ATTR_CHANNEL_ID, NCSI_RESERVED_CHANNEL);
rc = nla_put(skb, NCSI_ATTR_DATA, nr->rsp->len, (void *)nr->rsp->data);
if (rc)
goto err;
genlmsg_end(skb, hdr);
return genlmsg_unicast(net, skb, nr->snd_portid);
err:
kfree_skb(skb);
return rc;
}
int ncsi_send_netlink_timeout(struct ncsi_request *nr,
struct ncsi_package *np,
struct ncsi_channel *nc)
{
struct sk_buff *skb;
struct net *net;
void *hdr;
skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
if (!skb)
return -ENOMEM;
hdr = genlmsg_put(skb, nr->snd_portid, nr->snd_seq,
&ncsi_genl_family, 0, NCSI_CMD_SEND_CMD);
if (!hdr) {
kfree_skb(skb);
return -EMSGSIZE;
}
net = dev_net(nr->cmd->dev);
nla_put_u32(skb, NCSI_ATTR_IFINDEX, nr->cmd->dev->ifindex);
if (np)
nla_put_u32(skb, NCSI_ATTR_PACKAGE_ID, np->id);
else
nla_put_u32(skb, NCSI_ATTR_PACKAGE_ID,
NCSI_PACKAGE_INDEX((((struct ncsi_pkt_hdr *)
nr->cmd->data)->channel)));
if (nc)
nla_put_u32(skb, NCSI_ATTR_CHANNEL_ID, nc->id);
else
nla_put_u32(skb, NCSI_ATTR_CHANNEL_ID, NCSI_RESERVED_CHANNEL);
genlmsg_end(skb, hdr);
return genlmsg_unicast(net, skb, nr->snd_portid);
}
int ncsi_send_netlink_err(struct net_device *dev,
u32 snd_seq,
u32 snd_portid,
struct nlmsghdr *nlhdr,
int err)
{
struct nlmsghdr *nlh;
struct nlmsgerr *nle;
struct sk_buff *skb;
struct net *net;
skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
if (!skb)
return -ENOMEM;
net = dev_net(dev);
nlh = nlmsg_put(skb, snd_portid, snd_seq,
NLMSG_ERROR, sizeof(*nle), 0);
nle = (struct nlmsgerr *)nlmsg_data(nlh);
nle->error = err;
memcpy(&nle->msg, nlhdr, sizeof(*nlh));
nlmsg_end(skb, nlh);
return nlmsg_unicast(net->genl_sock, skb, snd_portid);
}
static const struct genl_ops ncsi_ops[] = { static const struct genl_ops ncsi_ops[] = {
{ {
.cmd = NCSI_CMD_PKG_INFO, .cmd = NCSI_CMD_PKG_INFO,
...@@ -385,6 +583,12 @@ static const struct genl_ops ncsi_ops[] = { ...@@ -385,6 +583,12 @@ static const struct genl_ops ncsi_ops[] = {
.doit = ncsi_clear_interface_nl, .doit = ncsi_clear_interface_nl,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
}, },
{
.cmd = NCSI_CMD_SEND_CMD,
.policy = ncsi_genl_policy,
.doit = ncsi_send_cmd_nl,
.flags = GENL_ADMIN_PERM,
},
}; };
static struct genl_family ncsi_genl_family __ro_after_init = { static struct genl_family ncsi_genl_family __ro_after_init = {
......
...@@ -14,6 +14,18 @@ ...@@ -14,6 +14,18 @@
#include "internal.h" #include "internal.h"
int ncsi_send_netlink_rsp(struct ncsi_request *nr,
struct ncsi_package *np,
struct ncsi_channel *nc);
int ncsi_send_netlink_timeout(struct ncsi_request *nr,
struct ncsi_package *np,
struct ncsi_channel *nc);
int ncsi_send_netlink_err(struct net_device *dev,
u32 snd_seq,
u32 snd_portid,
struct nlmsghdr *nlhdr,
int err);
int ncsi_init_netlink(struct net_device *dev); int ncsi_init_netlink(struct net_device *dev);
int ncsi_unregister_netlink(struct net_device *dev); int ncsi_unregister_netlink(struct net_device *dev);
......
...@@ -16,9 +16,11 @@ ...@@ -16,9 +16,11 @@
#include <net/ncsi.h> #include <net/ncsi.h>
#include <net/net_namespace.h> #include <net/net_namespace.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/genetlink.h>
#include "internal.h" #include "internal.h"
#include "ncsi-pkt.h" #include "ncsi-pkt.h"
#include "ncsi-netlink.h"
static int ncsi_validate_rsp_pkt(struct ncsi_request *nr, static int ncsi_validate_rsp_pkt(struct ncsi_request *nr,
unsigned short payload) unsigned short payload)
...@@ -32,15 +34,25 @@ static int ncsi_validate_rsp_pkt(struct ncsi_request *nr, ...@@ -32,15 +34,25 @@ static int ncsi_validate_rsp_pkt(struct ncsi_request *nr,
* before calling this function. * before calling this function.
*/ */
h = (struct ncsi_rsp_pkt_hdr *)skb_network_header(nr->rsp); h = (struct ncsi_rsp_pkt_hdr *)skb_network_header(nr->rsp);
if (h->common.revision != NCSI_PKT_REVISION)
if (h->common.revision != NCSI_PKT_REVISION) {
netdev_dbg(nr->ndp->ndev.dev,
"NCSI: unsupported header revision\n");
return -EINVAL; return -EINVAL;
if (ntohs(h->common.length) != payload) }
if (ntohs(h->common.length) != payload) {
netdev_dbg(nr->ndp->ndev.dev,
"NCSI: payload length mismatched\n");
return -EINVAL; return -EINVAL;
}
/* Check on code and reason */ /* Check on code and reason */
if (ntohs(h->code) != NCSI_PKT_RSP_C_COMPLETED || if (ntohs(h->code) != NCSI_PKT_RSP_C_COMPLETED ||
ntohs(h->reason) != NCSI_PKT_RSP_R_NO_ERROR) ntohs(h->reason) != NCSI_PKT_RSP_R_NO_ERROR) {
return -EINVAL; netdev_dbg(nr->ndp->ndev.dev,
"NCSI: non zero response/reason code\n");
return -EPERM;
}
/* Validate checksum, which might be zeroes if the /* Validate checksum, which might be zeroes if the
* sender doesn't support checksum according to NCSI * sender doesn't support checksum according to NCSI
...@@ -52,8 +64,11 @@ static int ncsi_validate_rsp_pkt(struct ncsi_request *nr, ...@@ -52,8 +64,11 @@ static int ncsi_validate_rsp_pkt(struct ncsi_request *nr,
checksum = ncsi_calculate_checksum((unsigned char *)h, checksum = ncsi_calculate_checksum((unsigned char *)h,
sizeof(*h) + payload - 4); sizeof(*h) + payload - 4);
if (*pchecksum != htonl(checksum))
if (*pchecksum != htonl(checksum)) {
netdev_dbg(nr->ndp->ndev.dev, "NCSI: checksum mismatched\n");
return -EINVAL; return -EINVAL;
}
return 0; return 0;
} }
...@@ -941,6 +956,26 @@ static int ncsi_rsp_handler_gpuuid(struct ncsi_request *nr) ...@@ -941,6 +956,26 @@ static int ncsi_rsp_handler_gpuuid(struct ncsi_request *nr)
return 0; return 0;
} }
static int ncsi_rsp_handler_netlink(struct ncsi_request *nr)
{
struct ncsi_dev_priv *ndp = nr->ndp;
struct ncsi_rsp_pkt *rsp;
struct ncsi_package *np;
struct ncsi_channel *nc;
int ret;
/* Find the package */
rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
&np, &nc);
if (!np)
return -ENODEV;
ret = ncsi_send_netlink_rsp(nr, np, nc);
return ret;
}
static struct ncsi_rsp_handler { static struct ncsi_rsp_handler {
unsigned char type; unsigned char type;
int payload; int payload;
...@@ -1043,6 +1078,17 @@ int ncsi_rcv_rsp(struct sk_buff *skb, struct net_device *dev, ...@@ -1043,6 +1078,17 @@ int ncsi_rcv_rsp(struct sk_buff *skb, struct net_device *dev,
netdev_warn(ndp->ndev.dev, netdev_warn(ndp->ndev.dev,
"NCSI: 'bad' packet ignored for type 0x%x\n", "NCSI: 'bad' packet ignored for type 0x%x\n",
hdr->type); hdr->type);
if (nr->flags == NCSI_REQ_FLAG_NETLINK_DRIVEN) {
if (ret == -EPERM)
goto out_netlink;
else
ncsi_send_netlink_err(ndp->ndev.dev,
nr->snd_seq,
nr->snd_portid,
&nr->nlhdr,
ret);
}
goto out; goto out;
} }
...@@ -1052,6 +1098,17 @@ int ncsi_rcv_rsp(struct sk_buff *skb, struct net_device *dev, ...@@ -1052,6 +1098,17 @@ int ncsi_rcv_rsp(struct sk_buff *skb, struct net_device *dev,
netdev_err(ndp->ndev.dev, netdev_err(ndp->ndev.dev,
"NCSI: Handler for packet type 0x%x returned %d\n", "NCSI: Handler for packet type 0x%x returned %d\n",
hdr->type, ret); hdr->type, ret);
out_netlink:
if (nr->flags == NCSI_REQ_FLAG_NETLINK_DRIVEN) {
ret = ncsi_rsp_handler_netlink(nr);
if (ret) {
netdev_err(ndp->ndev.dev,
"NCSI: Netlink handler for packet type 0x%x returned %d\n",
hdr->type, ret);
}
}
out: out:
ncsi_free_request(nr); ncsi_free_request(nr);
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment