diff options
Diffstat (limited to 'net/dcb')
-rw-r--r-- | net/dcb/dcbnl.c | 150 |
1 files changed, 148 insertions, 2 deletions
diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c index d5074a567289..3609eacaf4ce 100644 --- a/net/dcb/dcbnl.c +++ b/net/dcb/dcbnl.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2008, Intel Corporation. | 2 | * Copyright (c) 2008-2011, Intel Corporation. |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify it | 4 | * This program is free software; you can redistribute it and/or modify it |
5 | * under the terms and conditions of the GNU General Public License, | 5 | * under the terms and conditions of the GNU General Public License, |
@@ -1193,7 +1193,7 @@ static int dcbnl_ieee_set(struct net_device *netdev, struct nlattr **tb, | |||
1193 | goto err; | 1193 | goto err; |
1194 | } | 1194 | } |
1195 | 1195 | ||
1196 | if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setets) { | 1196 | if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setpfc) { |
1197 | struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]); | 1197 | struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]); |
1198 | err = ops->ieee_setpfc(netdev, pfc); | 1198 | err = ops->ieee_setpfc(netdev, pfc); |
1199 | if (err) | 1199 | if (err) |
@@ -1224,6 +1224,59 @@ err: | |||
1224 | return err; | 1224 | return err; |
1225 | } | 1225 | } |
1226 | 1226 | ||
1227 | static int dcbnl_build_peer_app(struct net_device *netdev, struct sk_buff* skb, | ||
1228 | int app_nested_type, int app_info_type, | ||
1229 | int app_entry_type) | ||
1230 | { | ||
1231 | struct dcb_peer_app_info info; | ||
1232 | struct dcb_app *table = NULL; | ||
1233 | const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; | ||
1234 | u16 app_count; | ||
1235 | int err; | ||
1236 | |||
1237 | |||
1238 | /** | ||
1239 | * retrieve the peer app configuration form the driver. If the driver | ||
1240 | * handlers fail exit without doing anything | ||
1241 | */ | ||
1242 | err = ops->peer_getappinfo(netdev, &info, &app_count); | ||
1243 | if (!err && app_count) { | ||
1244 | table = kmalloc(sizeof(struct dcb_app) * app_count, GFP_KERNEL); | ||
1245 | if (!table) | ||
1246 | return -ENOMEM; | ||
1247 | |||
1248 | err = ops->peer_getapptable(netdev, table); | ||
1249 | } | ||
1250 | |||
1251 | if (!err) { | ||
1252 | u16 i; | ||
1253 | struct nlattr *app; | ||
1254 | |||
1255 | /** | ||
1256 | * build the message, from here on the only possible failure | ||
1257 | * is due to the skb size | ||
1258 | */ | ||
1259 | err = -EMSGSIZE; | ||
1260 | |||
1261 | app = nla_nest_start(skb, app_nested_type); | ||
1262 | if (!app) | ||
1263 | goto nla_put_failure; | ||
1264 | |||
1265 | if (app_info_type) | ||
1266 | NLA_PUT(skb, app_info_type, sizeof(info), &info); | ||
1267 | |||
1268 | for (i = 0; i < app_count; i++) | ||
1269 | NLA_PUT(skb, app_entry_type, sizeof(struct dcb_app), | ||
1270 | &table[i]); | ||
1271 | |||
1272 | nla_nest_end(skb, app); | ||
1273 | } | ||
1274 | err = 0; | ||
1275 | |||
1276 | nla_put_failure: | ||
1277 | kfree(table); | ||
1278 | return err; | ||
1279 | } | ||
1227 | 1280 | ||
1228 | /* Handle IEEE 802.1Qaz GET commands. */ | 1281 | /* Handle IEEE 802.1Qaz GET commands. */ |
1229 | static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb, | 1282 | static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb, |
@@ -1288,6 +1341,30 @@ static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb, | |||
1288 | spin_unlock(&dcb_lock); | 1341 | spin_unlock(&dcb_lock); |
1289 | nla_nest_end(skb, app); | 1342 | nla_nest_end(skb, app); |
1290 | 1343 | ||
1344 | /* get peer info if available */ | ||
1345 | if (ops->ieee_peer_getets) { | ||
1346 | struct ieee_ets ets; | ||
1347 | err = ops->ieee_peer_getets(netdev, &ets); | ||
1348 | if (!err) | ||
1349 | NLA_PUT(skb, DCB_ATTR_IEEE_PEER_ETS, sizeof(ets), &ets); | ||
1350 | } | ||
1351 | |||
1352 | if (ops->ieee_peer_getpfc) { | ||
1353 | struct ieee_pfc pfc; | ||
1354 | err = ops->ieee_peer_getpfc(netdev, &pfc); | ||
1355 | if (!err) | ||
1356 | NLA_PUT(skb, DCB_ATTR_IEEE_PEER_PFC, sizeof(pfc), &pfc); | ||
1357 | } | ||
1358 | |||
1359 | if (ops->peer_getappinfo && ops->peer_getapptable) { | ||
1360 | err = dcbnl_build_peer_app(netdev, skb, | ||
1361 | DCB_ATTR_IEEE_PEER_APP, | ||
1362 | DCB_ATTR_IEEE_APP_UNSPEC, | ||
1363 | DCB_ATTR_IEEE_APP); | ||
1364 | if (err) | ||
1365 | goto nla_put_failure; | ||
1366 | } | ||
1367 | |||
1291 | nla_nest_end(skb, ieee); | 1368 | nla_nest_end(skb, ieee); |
1292 | nlmsg_end(skb, nlh); | 1369 | nlmsg_end(skb, nlh); |
1293 | 1370 | ||
@@ -1441,6 +1518,71 @@ err: | |||
1441 | return ret; | 1518 | return ret; |
1442 | } | 1519 | } |
1443 | 1520 | ||
1521 | /* Handle CEE DCBX GET commands. */ | ||
1522 | static int dcbnl_cee_get(struct net_device *netdev, struct nlattr **tb, | ||
1523 | u32 pid, u32 seq, u16 flags) | ||
1524 | { | ||
1525 | struct sk_buff *skb; | ||
1526 | struct nlmsghdr *nlh; | ||
1527 | struct dcbmsg *dcb; | ||
1528 | struct nlattr *cee; | ||
1529 | const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; | ||
1530 | int err; | ||
1531 | |||
1532 | if (!ops) | ||
1533 | return -EOPNOTSUPP; | ||
1534 | |||
1535 | skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
1536 | if (!skb) | ||
1537 | return -ENOBUFS; | ||
1538 | |||
1539 | nlh = NLMSG_NEW(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); | ||
1540 | |||
1541 | dcb = NLMSG_DATA(nlh); | ||
1542 | dcb->dcb_family = AF_UNSPEC; | ||
1543 | dcb->cmd = DCB_CMD_CEE_GET; | ||
1544 | |||
1545 | NLA_PUT_STRING(skb, DCB_ATTR_IFNAME, netdev->name); | ||
1546 | |||
1547 | cee = nla_nest_start(skb, DCB_ATTR_CEE); | ||
1548 | if (!cee) | ||
1549 | goto nla_put_failure; | ||
1550 | |||
1551 | /* get peer info if available */ | ||
1552 | if (ops->cee_peer_getpg) { | ||
1553 | struct cee_pg pg; | ||
1554 | err = ops->cee_peer_getpg(netdev, &pg); | ||
1555 | if (!err) | ||
1556 | NLA_PUT(skb, DCB_ATTR_CEE_PEER_PG, sizeof(pg), &pg); | ||
1557 | } | ||
1558 | |||
1559 | if (ops->cee_peer_getpfc) { | ||
1560 | struct cee_pfc pfc; | ||
1561 | err = ops->cee_peer_getpfc(netdev, &pfc); | ||
1562 | if (!err) | ||
1563 | NLA_PUT(skb, DCB_ATTR_CEE_PEER_PFC, sizeof(pfc), &pfc); | ||
1564 | } | ||
1565 | |||
1566 | if (ops->peer_getappinfo && ops->peer_getapptable) { | ||
1567 | err = dcbnl_build_peer_app(netdev, skb, | ||
1568 | DCB_ATTR_CEE_PEER_APP_TABLE, | ||
1569 | DCB_ATTR_CEE_PEER_APP_INFO, | ||
1570 | DCB_ATTR_CEE_PEER_APP); | ||
1571 | if (err) | ||
1572 | goto nla_put_failure; | ||
1573 | } | ||
1574 | |||
1575 | nla_nest_end(skb, cee); | ||
1576 | nlmsg_end(skb, nlh); | ||
1577 | |||
1578 | return rtnl_unicast(skb, &init_net, pid); | ||
1579 | nla_put_failure: | ||
1580 | nlmsg_cancel(skb, nlh); | ||
1581 | nlmsg_failure: | ||
1582 | kfree_skb(skb); | ||
1583 | return -1; | ||
1584 | } | ||
1585 | |||
1444 | static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 1586 | static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) |
1445 | { | 1587 | { |
1446 | struct net *net = sock_net(skb->sk); | 1588 | struct net *net = sock_net(skb->sk); |
@@ -1570,6 +1712,10 @@ static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
1570 | ret = dcbnl_setfeatcfg(netdev, tb, pid, nlh->nlmsg_seq, | 1712 | ret = dcbnl_setfeatcfg(netdev, tb, pid, nlh->nlmsg_seq, |
1571 | nlh->nlmsg_flags); | 1713 | nlh->nlmsg_flags); |
1572 | goto out; | 1714 | goto out; |
1715 | case DCB_CMD_CEE_GET: | ||
1716 | ret = dcbnl_cee_get(netdev, tb, pid, nlh->nlmsg_seq, | ||
1717 | nlh->nlmsg_flags); | ||
1718 | goto out; | ||
1573 | default: | 1719 | default: |
1574 | goto errout; | 1720 | goto errout; |
1575 | } | 1721 | } |