aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/dcb/dcbnl.c82
1 files changed, 82 insertions, 0 deletions
diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c
index 516e8be83d72..de61d64d102d 100644
--- a/net/dcb/dcbnl.c
+++ b/net/dcb/dcbnl.c
@@ -61,6 +61,7 @@ static struct nla_policy dcbnl_rtnl_policy[DCB_ATTR_MAX + 1] = {
61 [DCB_ATTR_PG_CFG] = {.type = NLA_NESTED}, 61 [DCB_ATTR_PG_CFG] = {.type = NLA_NESTED},
62 [DCB_ATTR_SET_ALL] = {.type = NLA_U8}, 62 [DCB_ATTR_SET_ALL] = {.type = NLA_U8},
63 [DCB_ATTR_PERM_HWADDR] = {.type = NLA_FLAG}, 63 [DCB_ATTR_PERM_HWADDR] = {.type = NLA_FLAG},
64 [DCB_ATTR_CAP] = {.type = NLA_NESTED},
64}; 65};
65 66
66/* DCB priority flow control to User Priority nested attributes */ 67/* DCB priority flow control to User Priority nested attributes */
@@ -107,6 +108,17 @@ static struct nla_policy dcbnl_tc_param_nest[DCB_TC_ATTR_PARAM_MAX + 1] = {
107 [DCB_TC_ATTR_PARAM_ALL] = {.type = NLA_FLAG}, 108 [DCB_TC_ATTR_PARAM_ALL] = {.type = NLA_FLAG},
108}; 109};
109 110
111/* DCB capabilities nested attributes. */
112static struct nla_policy dcbnl_cap_nest[DCB_CAP_ATTR_MAX + 1] = {
113 [DCB_CAP_ATTR_ALL] = {.type = NLA_FLAG},
114 [DCB_CAP_ATTR_PG] = {.type = NLA_U8},
115 [DCB_CAP_ATTR_PFC] = {.type = NLA_U8},
116 [DCB_CAP_ATTR_UP2TC] = {.type = NLA_U8},
117 [DCB_CAP_ATTR_PG_TCS] = {.type = NLA_U8},
118 [DCB_CAP_ATTR_PFC_TCS] = {.type = NLA_U8},
119 [DCB_CAP_ATTR_GSP] = {.type = NLA_U8},
120 [DCB_CAP_ATTR_BCN] = {.type = NLA_U8},
121};
110 122
111/* standard netlink reply call */ 123/* standard netlink reply call */
112static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid, 124static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid,
@@ -269,6 +281,72 @@ err_out:
269 return -EINVAL; 281 return -EINVAL;
270} 282}
271 283
284static int dcbnl_getcap(struct net_device *netdev, struct nlattr **tb,
285 u32 pid, u32 seq, u16 flags)
286{
287 struct sk_buff *dcbnl_skb;
288 struct nlmsghdr *nlh;
289 struct dcbmsg *dcb;
290 struct nlattr *data[DCB_CAP_ATTR_MAX + 1], *nest;
291 u8 value;
292 int ret = -EINVAL;
293 int i;
294 int getall = 0;
295
296 if (!tb[DCB_ATTR_CAP] || !netdev->dcbnl_ops->getcap)
297 return ret;
298
299 ret = nla_parse_nested(data, DCB_CAP_ATTR_MAX, tb[DCB_ATTR_CAP],
300 dcbnl_cap_nest);
301 if (ret)
302 goto err_out;
303
304 dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
305 if (!dcbnl_skb)
306 goto err_out;
307
308 nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
309
310 dcb = NLMSG_DATA(nlh);
311 dcb->dcb_family = AF_UNSPEC;
312 dcb->cmd = DCB_CMD_GCAP;
313
314 nest = nla_nest_start(dcbnl_skb, DCB_ATTR_CAP);
315 if (!nest)
316 goto err;
317
318 if (data[DCB_CAP_ATTR_ALL])
319 getall = 1;
320
321 for (i = DCB_CAP_ATTR_ALL+1; i <= DCB_CAP_ATTR_MAX; i++) {
322 if (!getall && !data[i])
323 continue;
324
325 if (!netdev->dcbnl_ops->getcap(netdev, i, &value)) {
326 ret = nla_put_u8(dcbnl_skb, i, value);
327
328 if (ret) {
329 nla_nest_cancel(dcbnl_skb, nest);
330 goto err;
331 }
332 }
333 }
334 nla_nest_end(dcbnl_skb, nest);
335
336 nlmsg_end(dcbnl_skb, nlh);
337
338 ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
339 if (ret)
340 goto err;
341
342 return 0;
343nlmsg_failure:
344err:
345 kfree(dcbnl_skb);
346err_out:
347 return -EINVAL;
348}
349
272static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlattr **tb, 350static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlattr **tb,
273 u32 pid, u32 seq, u16 flags, int dir) 351 u32 pid, u32 seq, u16 flags, int dir)
274{ 352{
@@ -675,6 +753,10 @@ static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
675 ret = dcbnl_pgrx_setcfg(netdev, tb, pid, nlh->nlmsg_seq, 753 ret = dcbnl_pgrx_setcfg(netdev, tb, pid, nlh->nlmsg_seq,
676 nlh->nlmsg_flags); 754 nlh->nlmsg_flags);
677 goto out; 755 goto out;
756 case DCB_CMD_GCAP:
757 ret = dcbnl_getcap(netdev, tb, pid, nlh->nlmsg_seq,
758 nlh->nlmsg_flags);
759 goto out;
678 default: 760 default:
679 goto errout; 761 goto errout;
680 } 762 }