1/* 2 * Copyright (c) 2008-2011, Intel Corporation. 3 * 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, 6 * version 2, as published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope it will be useful, but WITHOUT 9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 * more details. 12 * 13 * You should have received a copy of the GNU General Public License along with 14 * this program; if not, see <http://www.gnu.org/licenses/>. 15 * 16 * Author: Lucy Liu <lucy.liu@intel.com> 17 */ 18 19#include <linux/netdevice.h> 20#include <linux/netlink.h> 21#include <linux/slab.h> 22#include <net/netlink.h> 23#include <net/rtnetlink.h> 24#include <linux/dcbnl.h> 25#include <net/dcbevent.h> 26#include <linux/rtnetlink.h> 27#include <linux/module.h> 28#include <net/sock.h> 29 30/* Data Center Bridging (DCB) is a collection of Ethernet enhancements 31 * intended to allow network traffic with differing requirements 32 * (highly reliable, no drops vs. best effort vs. low latency) to operate 33 * and co-exist on Ethernet. Current DCB features are: 34 * 35 * Enhanced Transmission Selection (aka Priority Grouping [PG]) - provides a 36 * framework for assigning bandwidth guarantees to traffic classes. 37 * 38 * Priority-based Flow Control (PFC) - provides a flow control mechanism which 39 * can work independently for each 802.1p priority. 40 * 41 * Congestion Notification - provides a mechanism for end-to-end congestion 42 * control for protocols which do not have built-in congestion management. 43 * 44 * More information about the emerging standards for these Ethernet features 45 * can be found at: http://www.ieee802.org/1/pages/dcbridges.html 46 * 47 * This file implements an rtnetlink interface to allow configuration of DCB 48 * features for capable devices. 49 */ 50 51MODULE_AUTHOR("Lucy Liu, <lucy.liu@intel.com>"); 52MODULE_DESCRIPTION("Data Center Bridging netlink interface"); 53MODULE_LICENSE("GPL"); 54 55/**************** DCB attribute policies *************************************/ 56 57/* DCB netlink attributes policy */ 58static const struct nla_policy dcbnl_rtnl_policy[DCB_ATTR_MAX + 1] = { 59 [DCB_ATTR_IFNAME] = {.type = NLA_NUL_STRING, .len = IFNAMSIZ - 1}, 60 [DCB_ATTR_STATE] = {.type = NLA_U8}, 61 [DCB_ATTR_PFC_CFG] = {.type = NLA_NESTED}, 62 [DCB_ATTR_PG_CFG] = {.type = NLA_NESTED}, 63 [DCB_ATTR_SET_ALL] = {.type = NLA_U8}, 64 [DCB_ATTR_PERM_HWADDR] = {.type = NLA_FLAG}, 65 [DCB_ATTR_CAP] = {.type = NLA_NESTED}, 66 [DCB_ATTR_PFC_STATE] = {.type = NLA_U8}, 67 [DCB_ATTR_BCN] = {.type = NLA_NESTED}, 68 [DCB_ATTR_APP] = {.type = NLA_NESTED}, 69 [DCB_ATTR_IEEE] = {.type = NLA_NESTED}, 70 [DCB_ATTR_DCBX] = {.type = NLA_U8}, 71 [DCB_ATTR_FEATCFG] = {.type = NLA_NESTED}, 72}; 73 74/* DCB priority flow control to User Priority nested attributes */ 75static const struct nla_policy dcbnl_pfc_up_nest[DCB_PFC_UP_ATTR_MAX + 1] = { 76 [DCB_PFC_UP_ATTR_0] = {.type = NLA_U8}, 77 [DCB_PFC_UP_ATTR_1] = {.type = NLA_U8}, 78 [DCB_PFC_UP_ATTR_2] = {.type = NLA_U8}, 79 [DCB_PFC_UP_ATTR_3] = {.type = NLA_U8}, 80 [DCB_PFC_UP_ATTR_4] = {.type = NLA_U8}, 81 [DCB_PFC_UP_ATTR_5] = {.type = NLA_U8}, 82 [DCB_PFC_UP_ATTR_6] = {.type = NLA_U8}, 83 [DCB_PFC_UP_ATTR_7] = {.type = NLA_U8}, 84 [DCB_PFC_UP_ATTR_ALL] = {.type = NLA_FLAG}, 85}; 86 87/* DCB priority grouping nested attributes */ 88static const struct nla_policy dcbnl_pg_nest[DCB_PG_ATTR_MAX + 1] = { 89 [DCB_PG_ATTR_TC_0] = {.type = NLA_NESTED}, 90 [DCB_PG_ATTR_TC_1] = {.type = NLA_NESTED}, 91 [DCB_PG_ATTR_TC_2] = {.type = NLA_NESTED}, 92 [DCB_PG_ATTR_TC_3] = {.type = NLA_NESTED}, 93 [DCB_PG_ATTR_TC_4] = {.type = NLA_NESTED}, 94 [DCB_PG_ATTR_TC_5] = {.type = NLA_NESTED}, 95 [DCB_PG_ATTR_TC_6] = {.type = NLA_NESTED}, 96 [DCB_PG_ATTR_TC_7] = {.type = NLA_NESTED}, 97 [DCB_PG_ATTR_TC_ALL] = {.type = NLA_NESTED}, 98 [DCB_PG_ATTR_BW_ID_0] = {.type = NLA_U8}, 99 [DCB_PG_ATTR_BW_ID_1] = {.type = NLA_U8}, 100 [DCB_PG_ATTR_BW_ID_2] = {.type = NLA_U8}, 101 [DCB_PG_ATTR_BW_ID_3] = {.type = NLA_U8}, 102 [DCB_PG_ATTR_BW_ID_4] = {.type = NLA_U8}, 103 [DCB_PG_ATTR_BW_ID_5] = {.type = NLA_U8}, 104 [DCB_PG_ATTR_BW_ID_6] = {.type = NLA_U8}, 105 [DCB_PG_ATTR_BW_ID_7] = {.type = NLA_U8}, 106 [DCB_PG_ATTR_BW_ID_ALL] = {.type = NLA_FLAG}, 107}; 108 109/* DCB traffic class nested attributes. */ 110static const struct nla_policy dcbnl_tc_param_nest[DCB_TC_ATTR_PARAM_MAX + 1] = { 111 [DCB_TC_ATTR_PARAM_PGID] = {.type = NLA_U8}, 112 [DCB_TC_ATTR_PARAM_UP_MAPPING] = {.type = NLA_U8}, 113 [DCB_TC_ATTR_PARAM_STRICT_PRIO] = {.type = NLA_U8}, 114 [DCB_TC_ATTR_PARAM_BW_PCT] = {.type = NLA_U8}, 115 [DCB_TC_ATTR_PARAM_ALL] = {.type = NLA_FLAG}, 116}; 117 118/* DCB capabilities nested attributes. */ 119static const struct nla_policy dcbnl_cap_nest[DCB_CAP_ATTR_MAX + 1] = { 120 [DCB_CAP_ATTR_ALL] = {.type = NLA_FLAG}, 121 [DCB_CAP_ATTR_PG] = {.type = NLA_U8}, 122 [DCB_CAP_ATTR_PFC] = {.type = NLA_U8}, 123 [DCB_CAP_ATTR_UP2TC] = {.type = NLA_U8}, 124 [DCB_CAP_ATTR_PG_TCS] = {.type = NLA_U8}, 125 [DCB_CAP_ATTR_PFC_TCS] = {.type = NLA_U8}, 126 [DCB_CAP_ATTR_GSP] = {.type = NLA_U8}, 127 [DCB_CAP_ATTR_BCN] = {.type = NLA_U8}, 128 [DCB_CAP_ATTR_DCBX] = {.type = NLA_U8}, 129}; 130 131/* DCB capabilities nested attributes. */ 132static const struct nla_policy dcbnl_numtcs_nest[DCB_NUMTCS_ATTR_MAX + 1] = { 133 [DCB_NUMTCS_ATTR_ALL] = {.type = NLA_FLAG}, 134 [DCB_NUMTCS_ATTR_PG] = {.type = NLA_U8}, 135 [DCB_NUMTCS_ATTR_PFC] = {.type = NLA_U8}, 136}; 137 138/* DCB BCN nested attributes. */ 139static const struct nla_policy dcbnl_bcn_nest[DCB_BCN_ATTR_MAX + 1] = { 140 [DCB_BCN_ATTR_RP_0] = {.type = NLA_U8}, 141 [DCB_BCN_ATTR_RP_1] = {.type = NLA_U8}, 142 [DCB_BCN_ATTR_RP_2] = {.type = NLA_U8}, 143 [DCB_BCN_ATTR_RP_3] = {.type = NLA_U8}, 144 [DCB_BCN_ATTR_RP_4] = {.type = NLA_U8}, 145 [DCB_BCN_ATTR_RP_5] = {.type = NLA_U8}, 146 [DCB_BCN_ATTR_RP_6] = {.type = NLA_U8}, 147 [DCB_BCN_ATTR_RP_7] = {.type = NLA_U8}, 148 [DCB_BCN_ATTR_RP_ALL] = {.type = NLA_FLAG}, 149 [DCB_BCN_ATTR_BCNA_0] = {.type = NLA_U32}, 150 [DCB_BCN_ATTR_BCNA_1] = {.type = NLA_U32}, 151 [DCB_BCN_ATTR_ALPHA] = {.type = NLA_U32}, 152 [DCB_BCN_ATTR_BETA] = {.type = NLA_U32}, 153 [DCB_BCN_ATTR_GD] = {.type = NLA_U32}, 154 [DCB_BCN_ATTR_GI] = {.type = NLA_U32}, 155 [DCB_BCN_ATTR_TMAX] = {.type = NLA_U32}, 156 [DCB_BCN_ATTR_TD] = {.type = NLA_U32}, 157 [DCB_BCN_ATTR_RMIN] = {.type = NLA_U32}, 158 [DCB_BCN_ATTR_W] = {.type = NLA_U32}, 159 [DCB_BCN_ATTR_RD] = {.type = NLA_U32}, 160 [DCB_BCN_ATTR_RU] = {.type = NLA_U32}, 161 [DCB_BCN_ATTR_WRTT] = {.type = NLA_U32}, 162 [DCB_BCN_ATTR_RI] = {.type = NLA_U32}, 163 [DCB_BCN_ATTR_C] = {.type = NLA_U32}, 164 [DCB_BCN_ATTR_ALL] = {.type = NLA_FLAG}, 165}; 166 167/* DCB APP nested attributes. */ 168static const struct nla_policy dcbnl_app_nest[DCB_APP_ATTR_MAX + 1] = { 169 [DCB_APP_ATTR_IDTYPE] = {.type = NLA_U8}, 170 [DCB_APP_ATTR_ID] = {.type = NLA_U16}, 171 [DCB_APP_ATTR_PRIORITY] = {.type = NLA_U8}, 172}; 173 174/* IEEE 802.1Qaz nested attributes. */ 175static const struct nla_policy dcbnl_ieee_policy[DCB_ATTR_IEEE_MAX + 1] = { 176 [DCB_ATTR_IEEE_ETS] = {.len = sizeof(struct ieee_ets)}, 177 [DCB_ATTR_IEEE_PFC] = {.len = sizeof(struct ieee_pfc)}, 178 [DCB_ATTR_IEEE_APP_TABLE] = {.type = NLA_NESTED}, 179 [DCB_ATTR_IEEE_MAXRATE] = {.len = sizeof(struct ieee_maxrate)}, 180 [DCB_ATTR_IEEE_QCN] = {.len = sizeof(struct ieee_qcn)}, 181 [DCB_ATTR_IEEE_QCN_STATS] = {.len = sizeof(struct ieee_qcn_stats)}, 182}; 183 184static const struct nla_policy dcbnl_ieee_app[DCB_ATTR_IEEE_APP_MAX + 1] = { 185 [DCB_ATTR_IEEE_APP] = {.len = sizeof(struct dcb_app)}, 186}; 187 188/* DCB number of traffic classes nested attributes. */ 189static const struct nla_policy dcbnl_featcfg_nest[DCB_FEATCFG_ATTR_MAX + 1] = { 190 [DCB_FEATCFG_ATTR_ALL] = {.type = NLA_FLAG}, 191 [DCB_FEATCFG_ATTR_PG] = {.type = NLA_U8}, 192 [DCB_FEATCFG_ATTR_PFC] = {.type = NLA_U8}, 193 [DCB_FEATCFG_ATTR_APP] = {.type = NLA_U8}, 194}; 195 196static LIST_HEAD(dcb_app_list); 197static DEFINE_SPINLOCK(dcb_lock); 198 199static struct sk_buff *dcbnl_newmsg(int type, u8 cmd, u32 port, u32 seq, 200 u32 flags, struct nlmsghdr **nlhp) 201{ 202 struct sk_buff *skb; 203 struct dcbmsg *dcb; 204 struct nlmsghdr *nlh; 205 206 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 207 if (!skb) 208 return NULL; 209 210 nlh = nlmsg_put(skb, port, seq, type, sizeof(*dcb), flags); 211 BUG_ON(!nlh); 212 213 dcb = nlmsg_data(nlh); 214 dcb->dcb_family = AF_UNSPEC; 215 dcb->cmd = cmd; 216 dcb->dcb_pad = 0; 217 218 if (nlhp) 219 *nlhp = nlh; 220 221 return skb; 222} 223 224static int dcbnl_getstate(struct net_device *netdev, struct nlmsghdr *nlh, 225 u32 seq, struct nlattr **tb, struct sk_buff *skb) 226{ 227 /* if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->getstate) */ 228 if (!netdev->dcbnl_ops->getstate) 229 return -EOPNOTSUPP; 230 231 return nla_put_u8(skb, DCB_ATTR_STATE, 232 netdev->dcbnl_ops->getstate(netdev)); 233} 234 235static int dcbnl_getpfccfg(struct net_device *netdev, struct nlmsghdr *nlh, 236 u32 seq, struct nlattr **tb, struct sk_buff *skb) 237{ 238 struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1], *nest; 239 u8 value; 240 int ret; 241 int i; 242 int getall = 0; 243 244 if (!tb[DCB_ATTR_PFC_CFG]) 245 return -EINVAL; 246 247 if (!netdev->dcbnl_ops->getpfccfg) 248 return -EOPNOTSUPP; 249 250 ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX, 251 tb[DCB_ATTR_PFC_CFG], 252 dcbnl_pfc_up_nest); 253 if (ret) 254 return ret; 255 256 nest = nla_nest_start(skb, DCB_ATTR_PFC_CFG); 257 if (!nest) 258 return -EMSGSIZE; 259 260 if (data[DCB_PFC_UP_ATTR_ALL]) 261 getall = 1; 262 263 for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) { 264 if (!getall && !data[i]) 265 continue; 266 267 netdev->dcbnl_ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0, 268 &value); 269 ret = nla_put_u8(skb, i, value); 270 if (ret) { 271 nla_nest_cancel(skb, nest); 272 return ret; 273 } 274 } 275 nla_nest_end(skb, nest); 276 277 return 0; 278} 279 280static int dcbnl_getperm_hwaddr(struct net_device *netdev, struct nlmsghdr *nlh, 281 u32 seq, struct nlattr **tb, struct sk_buff *skb) 282{ 283 u8 perm_addr[MAX_ADDR_LEN]; 284 285 if (!netdev->dcbnl_ops->getpermhwaddr) 286 return -EOPNOTSUPP; 287 288 memset(perm_addr, 0, sizeof(perm_addr)); 289 netdev->dcbnl_ops->getpermhwaddr(netdev, perm_addr); 290 291 return nla_put(skb, DCB_ATTR_PERM_HWADDR, sizeof(perm_addr), perm_addr); 292} 293 294static int dcbnl_getcap(struct net_device *netdev, struct nlmsghdr *nlh, 295 u32 seq, struct nlattr **tb, struct sk_buff *skb) 296{ 297 struct nlattr *data[DCB_CAP_ATTR_MAX + 1], *nest; 298 u8 value; 299 int ret; 300 int i; 301 int getall = 0; 302 303 if (!tb[DCB_ATTR_CAP]) 304 return -EINVAL; 305 306 if (!netdev->dcbnl_ops->getcap) 307 return -EOPNOTSUPP; 308 309 ret = nla_parse_nested(data, DCB_CAP_ATTR_MAX, tb[DCB_ATTR_CAP], 310 dcbnl_cap_nest); 311 if (ret) 312 return ret; 313 314 nest = nla_nest_start(skb, DCB_ATTR_CAP); 315 if (!nest) 316 return -EMSGSIZE; 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(skb, i, value); 327 if (ret) { 328 nla_nest_cancel(skb, nest); 329 return ret; 330 } 331 } 332 } 333 nla_nest_end(skb, nest); 334 335 return 0; 336} 337 338static int dcbnl_getnumtcs(struct net_device *netdev, struct nlmsghdr *nlh, 339 u32 seq, struct nlattr **tb, struct sk_buff *skb) 340{ 341 struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1], *nest; 342 u8 value; 343 int ret; 344 int i; 345 int getall = 0; 346 347 if (!tb[DCB_ATTR_NUMTCS]) 348 return -EINVAL; 349 350 if (!netdev->dcbnl_ops->getnumtcs) 351 return -EOPNOTSUPP; 352 353 ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS], 354 dcbnl_numtcs_nest); 355 if (ret) 356 return ret; 357 358 nest = nla_nest_start(skb, DCB_ATTR_NUMTCS); 359 if (!nest) 360 return -EMSGSIZE; 361 362 if (data[DCB_NUMTCS_ATTR_ALL]) 363 getall = 1; 364 365 for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) { 366 if (!getall && !data[i]) 367 continue; 368 369 ret = netdev->dcbnl_ops->getnumtcs(netdev, i, &value); 370 if (!ret) { 371 ret = nla_put_u8(skb, i, value); 372 if (ret) { 373 nla_nest_cancel(skb, nest); 374 return ret; 375 } 376 } else 377 return -EINVAL; 378 } 379 nla_nest_end(skb, nest); 380 381 return 0; 382} 383 384static int dcbnl_setnumtcs(struct net_device *netdev, struct nlmsghdr *nlh, 385 u32 seq, struct nlattr **tb, struct sk_buff *skb) 386{ 387 struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1]; 388 int ret; 389 u8 value; 390 int i; 391 392 if (!tb[DCB_ATTR_NUMTCS]) 393 return -EINVAL; 394 395 if (!netdev->dcbnl_ops->setnumtcs) 396 return -EOPNOTSUPP; 397 398 ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS], 399 dcbnl_numtcs_nest); 400 if (ret) 401 return ret; 402 403 for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) { 404 if (data[i] == NULL) 405 continue; 406 407 value = nla_get_u8(data[i]); 408 409 ret = netdev->dcbnl_ops->setnumtcs(netdev, i, value); 410 if (ret) 411 break; 412 } 413 414 return nla_put_u8(skb, DCB_ATTR_NUMTCS, !!ret); 415} 416 417static int dcbnl_getpfcstate(struct net_device *netdev, struct nlmsghdr *nlh, 418 u32 seq, struct nlattr **tb, struct sk_buff *skb) 419{ 420 if (!netdev->dcbnl_ops->getpfcstate) 421 return -EOPNOTSUPP; 422 423 return nla_put_u8(skb, DCB_ATTR_PFC_STATE, 424 netdev->dcbnl_ops->getpfcstate(netdev)); 425} 426 427static int dcbnl_setpfcstate(struct net_device *netdev, struct nlmsghdr *nlh, 428 u32 seq, struct nlattr **tb, struct sk_buff *skb) 429{ 430 u8 value; 431 432 if (!tb[DCB_ATTR_PFC_STATE]) 433 return -EINVAL; 434 435 if (!netdev->dcbnl_ops->setpfcstate) 436 return -EOPNOTSUPP; 437 438 value = nla_get_u8(tb[DCB_ATTR_PFC_STATE]); 439 440 netdev->dcbnl_ops->setpfcstate(netdev, value); 441 442 return nla_put_u8(skb, DCB_ATTR_PFC_STATE, 0); 443} 444 445static int dcbnl_getapp(struct net_device *netdev, struct nlmsghdr *nlh, 446 u32 seq, struct nlattr **tb, struct sk_buff *skb) 447{ 448 struct nlattr *app_nest; 449 struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1]; 450 u16 id; 451 u8 up, idtype; 452 int ret; 453 454 if (!tb[DCB_ATTR_APP]) 455 return -EINVAL; 456 457 ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP], 458 dcbnl_app_nest); 459 if (ret) 460 return ret; 461 462 /* all must be non-null */ 463 if ((!app_tb[DCB_APP_ATTR_IDTYPE]) || 464 (!app_tb[DCB_APP_ATTR_ID])) 465 return -EINVAL; 466 467 /* either by eth type or by socket number */ 468 idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]); 469 if ((idtype != DCB_APP_IDTYPE_ETHTYPE) && 470 (idtype != DCB_APP_IDTYPE_PORTNUM)) 471 return -EINVAL; 472 473 id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]); 474 475 if (netdev->dcbnl_ops->getapp) { 476 ret = netdev->dcbnl_ops->getapp(netdev, idtype, id); 477 if (ret < 0) 478 return ret; 479 else 480 up = ret; 481 } else { 482 struct dcb_app app = { 483 .selector = idtype, 484 .protocol = id, 485 }; 486 up = dcb_getapp(netdev, &app); 487 } 488 489 app_nest = nla_nest_start(skb, DCB_ATTR_APP); 490 if (!app_nest) 491 return -EMSGSIZE; 492 493 ret = nla_put_u8(skb, DCB_APP_ATTR_IDTYPE, idtype); 494 if (ret) 495 goto out_cancel; 496 497 ret = nla_put_u16(skb, DCB_APP_ATTR_ID, id); 498 if (ret) 499 goto out_cancel; 500 501 ret = nla_put_u8(skb, DCB_APP_ATTR_PRIORITY, up); 502 if (ret) 503 goto out_cancel; 504 505 nla_nest_end(skb, app_nest); 506 507 return 0; 508 509out_cancel: 510 nla_nest_cancel(skb, app_nest); 511 return ret; 512} 513 514static int dcbnl_setapp(struct net_device *netdev, struct nlmsghdr *nlh, 515 u32 seq, struct nlattr **tb, struct sk_buff *skb) 516{ 517 int ret; 518 u16 id; 519 u8 up, idtype; 520 struct nlattr *app_tb[DCB_APP_ATTR_MAX + 1]; 521 522 if (!tb[DCB_ATTR_APP]) 523 return -EINVAL; 524 525 ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP], 526 dcbnl_app_nest); 527 if (ret) 528 return ret; 529 530 /* all must be non-null */ 531 if ((!app_tb[DCB_APP_ATTR_IDTYPE]) || 532 (!app_tb[DCB_APP_ATTR_ID]) || 533 (!app_tb[DCB_APP_ATTR_PRIORITY])) 534 return -EINVAL; 535 536 /* either by eth type or by socket number */ 537 idtype = nla_get_u8(app_tb[DCB_APP_ATTR_IDTYPE]); 538 if ((idtype != DCB_APP_IDTYPE_ETHTYPE) && 539 (idtype != DCB_APP_IDTYPE_PORTNUM)) 540 return -EINVAL; 541 542 id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]); 543 up = nla_get_u8(app_tb[DCB_APP_ATTR_PRIORITY]); 544 545 if (netdev->dcbnl_ops->setapp) { 546 ret = netdev->dcbnl_ops->setapp(netdev, idtype, id, up); 547 if (ret < 0) 548 return ret; 549 } else { 550 struct dcb_app app; 551 app.selector = idtype; 552 app.protocol = id; 553 app.priority = up; 554 ret = dcb_setapp(netdev, &app); 555 } 556 557 ret = nla_put_u8(skb, DCB_ATTR_APP, ret); 558 dcbnl_cee_notify(netdev, RTM_SETDCB, DCB_CMD_SAPP, seq, 0); 559 560 return ret; 561} 562 563static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlmsghdr *nlh, 564 struct nlattr **tb, struct sk_buff *skb, int dir) 565{ 566 struct nlattr *pg_nest, *param_nest, *data; 567 struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1]; 568 struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1]; 569 u8 prio, pgid, tc_pct, up_map; 570 int ret; 571 int getall = 0; 572 int i; 573 574 if (!tb[DCB_ATTR_PG_CFG]) 575 return -EINVAL; 576 577 if (!netdev->dcbnl_ops->getpgtccfgtx || 578 !netdev->dcbnl_ops->getpgtccfgrx || 579 !netdev->dcbnl_ops->getpgbwgcfgtx || 580 !netdev->dcbnl_ops->getpgbwgcfgrx) 581 return -EOPNOTSUPP; 582 583 ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX, 584 tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest); 585 if (ret) 586 return ret; 587 588 pg_nest = nla_nest_start(skb, DCB_ATTR_PG_CFG); 589 if (!pg_nest) 590 return -EMSGSIZE; 591 592 if (pg_tb[DCB_PG_ATTR_TC_ALL]) 593 getall = 1; 594 595 for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) { 596 if (!getall && !pg_tb[i]) 597 continue; 598 599 if (pg_tb[DCB_PG_ATTR_TC_ALL]) 600 data = pg_tb[DCB_PG_ATTR_TC_ALL]; 601 else 602 data = pg_tb[i]; 603 ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX, 604 data, dcbnl_tc_param_nest); 605 if (ret) 606 goto err_pg; 607 608 param_nest = nla_nest_start(skb, i); 609 if (!param_nest) 610 goto err_pg; 611 612 pgid = DCB_ATTR_VALUE_UNDEFINED; 613 prio = DCB_ATTR_VALUE_UNDEFINED; 614 tc_pct = DCB_ATTR_VALUE_UNDEFINED; 615 up_map = DCB_ATTR_VALUE_UNDEFINED; 616 617 if (dir) { 618 /* Rx */ 619 netdev->dcbnl_ops->getpgtccfgrx(netdev, 620 i - DCB_PG_ATTR_TC_0, &prio, 621 &pgid, &tc_pct, &up_map); 622 } else { 623 /* Tx */ 624 netdev->dcbnl_ops->getpgtccfgtx(netdev, 625 i - DCB_PG_ATTR_TC_0, &prio, 626 &pgid, &tc_pct, &up_map); 627 } 628 629 if (param_tb[DCB_TC_ATTR_PARAM_PGID] || 630 param_tb[DCB_TC_ATTR_PARAM_ALL]) { 631 ret = nla_put_u8(skb, 632 DCB_TC_ATTR_PARAM_PGID, pgid); 633 if (ret) 634 goto err_param; 635 } 636 if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING] || 637 param_tb[DCB_TC_ATTR_PARAM_ALL]) { 638 ret = nla_put_u8(skb, 639 DCB_TC_ATTR_PARAM_UP_MAPPING, up_map); 640 if (ret) 641 goto err_param; 642 } 643 if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO] || 644 param_tb[DCB_TC_ATTR_PARAM_ALL]) { 645 ret = nla_put_u8(skb, 646 DCB_TC_ATTR_PARAM_STRICT_PRIO, prio); 647 if (ret) 648 goto err_param; 649 } 650 if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT] || 651 param_tb[DCB_TC_ATTR_PARAM_ALL]) { 652 ret = nla_put_u8(skb, DCB_TC_ATTR_PARAM_BW_PCT, 653 tc_pct); 654 if (ret) 655 goto err_param; 656 } 657 nla_nest_end(skb, param_nest); 658 } 659 660 if (pg_tb[DCB_PG_ATTR_BW_ID_ALL]) 661 getall = 1; 662 else 663 getall = 0; 664 665 for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) { 666 if (!getall && !pg_tb[i]) 667 continue; 668 669 tc_pct = DCB_ATTR_VALUE_UNDEFINED; 670 671 if (dir) { 672 /* Rx */ 673 netdev->dcbnl_ops->getpgbwgcfgrx(netdev, 674 i - DCB_PG_ATTR_BW_ID_0, &tc_pct); 675 } else { 676 /* Tx */ 677 netdev->dcbnl_ops->getpgbwgcfgtx(netdev, 678 i - DCB_PG_ATTR_BW_ID_0, &tc_pct); 679 } 680 ret = nla_put_u8(skb, i, tc_pct); 681 if (ret) 682 goto err_pg; 683 } 684 685 nla_nest_end(skb, pg_nest); 686 687 return 0; 688 689err_param: 690 nla_nest_cancel(skb, param_nest); 691err_pg: 692 nla_nest_cancel(skb, pg_nest); 693 694 return -EMSGSIZE; 695} 696 697static int dcbnl_pgtx_getcfg(struct net_device *netdev, struct nlmsghdr *nlh, 698 u32 seq, struct nlattr **tb, struct sk_buff *skb) 699{ 700 return __dcbnl_pg_getcfg(netdev, nlh, tb, skb, 0); 701} 702 703static int dcbnl_pgrx_getcfg(struct net_device *netdev, struct nlmsghdr *nlh, 704 u32 seq, struct nlattr **tb, struct sk_buff *skb) 705{ 706 return __dcbnl_pg_getcfg(netdev, nlh, tb, skb, 1); 707} 708 709static int dcbnl_setstate(struct net_device *netdev, struct nlmsghdr *nlh, 710 u32 seq, struct nlattr **tb, struct sk_buff *skb) 711{ 712 u8 value; 713 714 if (!tb[DCB_ATTR_STATE]) 715 return -EINVAL; 716 717 if (!netdev->dcbnl_ops->setstate) 718 return -EOPNOTSUPP; 719 720 value = nla_get_u8(tb[DCB_ATTR_STATE]); 721 722 return nla_put_u8(skb, DCB_ATTR_STATE, 723 netdev->dcbnl_ops->setstate(netdev, value)); 724} 725 726static int dcbnl_setpfccfg(struct net_device *netdev, struct nlmsghdr *nlh, 727 u32 seq, struct nlattr **tb, struct sk_buff *skb) 728{ 729 struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1]; 730 int i; 731 int ret; 732 u8 value; 733 734 if (!tb[DCB_ATTR_PFC_CFG]) 735 return -EINVAL; 736 737 if (!netdev->dcbnl_ops->setpfccfg) 738 return -EOPNOTSUPP; 739 740 ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX, 741 tb[DCB_ATTR_PFC_CFG], 742 dcbnl_pfc_up_nest); 743 if (ret) 744 return ret; 745 746 for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) { 747 if (data[i] == NULL) 748 continue; 749 value = nla_get_u8(data[i]); 750 netdev->dcbnl_ops->setpfccfg(netdev, 751 data[i]->nla_type - DCB_PFC_UP_ATTR_0, value); 752 } 753 754 return nla_put_u8(skb, DCB_ATTR_PFC_CFG, 0); 755} 756 757static int dcbnl_setall(struct net_device *netdev, struct nlmsghdr *nlh, 758 u32 seq, struct nlattr **tb, struct sk_buff *skb) 759{ 760 int ret; 761 762 if (!tb[DCB_ATTR_SET_ALL]) 763 return -EINVAL; 764 765 if (!netdev->dcbnl_ops->setall) 766 return -EOPNOTSUPP; 767 768 ret = nla_put_u8(skb, DCB_ATTR_SET_ALL, 769 netdev->dcbnl_ops->setall(netdev)); 770 dcbnl_cee_notify(netdev, RTM_SETDCB, DCB_CMD_SET_ALL, seq, 0); 771 772 return ret; 773} 774 775static int __dcbnl_pg_setcfg(struct net_device *netdev, struct nlmsghdr *nlh, 776 u32 seq, struct nlattr **tb, struct sk_buff *skb, 777 int dir) 778{ 779 struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1]; 780 struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1]; 781 int ret; 782 int i; 783 u8 pgid; 784 u8 up_map; 785 u8 prio; 786 u8 tc_pct; 787 788 if (!tb[DCB_ATTR_PG_CFG]) 789 return -EINVAL; 790 791 if (!netdev->dcbnl_ops->setpgtccfgtx || 792 !netdev->dcbnl_ops->setpgtccfgrx || 793 !netdev->dcbnl_ops->setpgbwgcfgtx || 794 !netdev->dcbnl_ops->setpgbwgcfgrx) 795 return -EOPNOTSUPP; 796 797 ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX, 798 tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest); 799 if (ret) 800 return ret; 801 802 for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) { 803 if (!pg_tb[i]) 804 continue; 805 806 ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX, 807 pg_tb[i], dcbnl_tc_param_nest); 808 if (ret) 809 return ret; 810 811 pgid = DCB_ATTR_VALUE_UNDEFINED; 812 prio = DCB_ATTR_VALUE_UNDEFINED; 813 tc_pct = DCB_ATTR_VALUE_UNDEFINED; 814 up_map = DCB_ATTR_VALUE_UNDEFINED; 815 816 if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO]) 817 prio = 818 nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO]); 819 820 if (param_tb[DCB_TC_ATTR_PARAM_PGID]) 821 pgid = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_PGID]); 822 823 if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT]) 824 tc_pct = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_BW_PCT]); 825 826 if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING]) 827 up_map = 828 nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING]); 829 830 /* dir: Tx = 0, Rx = 1 */ 831 if (dir) { 832 /* Rx */ 833 netdev->dcbnl_ops->setpgtccfgrx(netdev, 834 i - DCB_PG_ATTR_TC_0, 835 prio, pgid, tc_pct, up_map); 836 } else { 837 /* Tx */ 838 netdev->dcbnl_ops->setpgtccfgtx(netdev, 839 i - DCB_PG_ATTR_TC_0, 840 prio, pgid, tc_pct, up_map); 841 } 842 } 843 844 for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) { 845 if (!pg_tb[i]) 846 continue; 847 848 tc_pct = nla_get_u8(pg_tb[i]); 849 850 /* dir: Tx = 0, Rx = 1 */ 851 if (dir) { 852 /* Rx */ 853 netdev->dcbnl_ops->setpgbwgcfgrx(netdev, 854 i - DCB_PG_ATTR_BW_ID_0, tc_pct); 855 } else { 856 /* Tx */ 857 netdev->dcbnl_ops->setpgbwgcfgtx(netdev, 858 i - DCB_PG_ATTR_BW_ID_0, tc_pct); 859 } 860 } 861 862 return nla_put_u8(skb, DCB_ATTR_PG_CFG, 0); 863} 864 865static int dcbnl_pgtx_setcfg(struct net_device *netdev, struct nlmsghdr *nlh, 866 u32 seq, struct nlattr **tb, struct sk_buff *skb) 867{ 868 return __dcbnl_pg_setcfg(netdev, nlh, seq, tb, skb, 0); 869} 870 871static int dcbnl_pgrx_setcfg(struct net_device *netdev, struct nlmsghdr *nlh, 872 u32 seq, struct nlattr **tb, struct sk_buff *skb) 873{ 874 return __dcbnl_pg_setcfg(netdev, nlh, seq, tb, skb, 1); 875} 876 877static int dcbnl_bcn_getcfg(struct net_device *netdev, struct nlmsghdr *nlh, 878 u32 seq, struct nlattr **tb, struct sk_buff *skb) 879{ 880 struct nlattr *bcn_nest; 881 struct nlattr *bcn_tb[DCB_BCN_ATTR_MAX + 1]; 882 u8 value_byte; 883 u32 value_integer; 884 int ret; 885 bool getall = false; 886 int i; 887 888 if (!tb[DCB_ATTR_BCN]) 889 return -EINVAL; 890 891 if (!netdev->dcbnl_ops->getbcnrp || 892 !netdev->dcbnl_ops->getbcncfg) 893 return -EOPNOTSUPP; 894 895 ret = nla_parse_nested(bcn_tb, DCB_BCN_ATTR_MAX, 896 tb[DCB_ATTR_BCN], dcbnl_bcn_nest); 897 if (ret) 898 return ret; 899 900 bcn_nest = nla_nest_start(skb, DCB_ATTR_BCN); 901 if (!bcn_nest) 902 return -EMSGSIZE; 903 904 if (bcn_tb[DCB_BCN_ATTR_ALL]) 905 getall = true; 906 907 for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) { 908 if (!getall && !bcn_tb[i]) 909 continue; 910 911 netdev->dcbnl_ops->getbcnrp(netdev, i - DCB_BCN_ATTR_RP_0, 912 &value_byte); 913 ret = nla_put_u8(skb, i, value_byte); 914 if (ret) 915 goto err_bcn; 916 } 917 918 for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) { 919 if (!getall && !bcn_tb[i]) 920 continue; 921 922 netdev->dcbnl_ops->getbcncfg(netdev, i, 923 &value_integer); 924 ret = nla_put_u32(skb, i, value_integer); 925 if (ret) 926 goto err_bcn; 927 } 928 929 nla_nest_end(skb, bcn_nest); 930 931 return 0; 932 933err_bcn: 934 nla_nest_cancel(skb, bcn_nest); 935 return ret; 936} 937 938static int dcbnl_bcn_setcfg(struct net_device *netdev, struct nlmsghdr *nlh, 939 u32 seq, struct nlattr **tb, struct sk_buff *skb) 940{ 941 struct nlattr *data[DCB_BCN_ATTR_MAX + 1]; 942 int i; 943 int ret; 944 u8 value_byte; 945 u32 value_int; 946 947 if (!tb[DCB_ATTR_BCN]) 948 return -EINVAL; 949 950 if (!netdev->dcbnl_ops->setbcncfg || 951 !netdev->dcbnl_ops->setbcnrp) 952 return -EOPNOTSUPP; 953 954 ret = nla_parse_nested(data, DCB_BCN_ATTR_MAX, 955 tb[DCB_ATTR_BCN], 956 dcbnl_pfc_up_nest); 957 if (ret) 958 return ret; 959 960 for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) { 961 if (data[i] == NULL) 962 continue; 963 value_byte = nla_get_u8(data[i]); 964 netdev->dcbnl_ops->setbcnrp(netdev, 965 data[i]->nla_type - DCB_BCN_ATTR_RP_0, value_byte); 966 } 967 968 for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) { 969 if (data[i] == NULL) 970 continue; 971 value_int = nla_get_u32(data[i]); 972 netdev->dcbnl_ops->setbcncfg(netdev, 973 i, value_int); 974 } 975 976 return nla_put_u8(skb, DCB_ATTR_BCN, 0); 977} 978 979static int dcbnl_build_peer_app(struct net_device *netdev, struct sk_buff* skb, 980 int app_nested_type, int app_info_type, 981 int app_entry_type) 982{ 983 struct dcb_peer_app_info info; 984 struct dcb_app *table = NULL; 985 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 986 u16 app_count; 987 int err; 988 989 990 /** 991 * retrieve the peer app configuration form the driver. If the driver 992 * handlers fail exit without doing anything 993 */ 994 err = ops->peer_getappinfo(netdev, &info, &app_count); 995 if (!err && app_count) { 996 table = kmalloc(sizeof(struct dcb_app) * app_count, GFP_KERNEL); 997 if (!table) 998 return -ENOMEM; 999 1000 err = ops->peer_getapptable(netdev, table); 1001 } 1002 1003 if (!err) { 1004 u16 i; 1005 struct nlattr *app; 1006 1007 /** 1008 * build the message, from here on the only possible failure 1009 * is due to the skb size 1010 */ 1011 err = -EMSGSIZE; 1012 1013 app = nla_nest_start(skb, app_nested_type); 1014 if (!app) 1015 goto nla_put_failure; 1016 1017 if (app_info_type && 1018 nla_put(skb, app_info_type, sizeof(info), &info)) 1019 goto nla_put_failure; 1020 1021 for (i = 0; i < app_count; i++) { 1022 if (nla_put(skb, app_entry_type, sizeof(struct dcb_app), 1023 &table[i])) 1024 goto nla_put_failure; 1025 } 1026 nla_nest_end(skb, app); 1027 } 1028 err = 0; 1029 1030nla_put_failure: 1031 kfree(table); 1032 return err; 1033} 1034 1035/* Handle IEEE 802.1Qaz/802.1Qau/802.1Qbb GET commands. */ 1036static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev) 1037{ 1038 struct nlattr *ieee, *app; 1039 struct dcb_app_type *itr; 1040 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1041 int dcbx; 1042 int err; 1043 1044 if (nla_put_string(skb, DCB_ATTR_IFNAME, netdev->name)) 1045 return -EMSGSIZE; 1046 1047 ieee = nla_nest_start(skb, DCB_ATTR_IEEE); 1048 if (!ieee) 1049 return -EMSGSIZE; 1050 1051 if (ops->ieee_getets) { 1052 struct ieee_ets ets; 1053 memset(&ets, 0, sizeof(ets)); 1054 err = ops->ieee_getets(netdev, &ets); 1055 if (!err && 1056 nla_put(skb, DCB_ATTR_IEEE_ETS, sizeof(ets), &ets)) 1057 return -EMSGSIZE; 1058 } 1059 1060 if (ops->ieee_getmaxrate) { 1061 struct ieee_maxrate maxrate; 1062 memset(&maxrate, 0, sizeof(maxrate)); 1063 err = ops->ieee_getmaxrate(netdev, &maxrate); 1064 if (!err) { 1065 err = nla_put(skb, DCB_ATTR_IEEE_MAXRATE, 1066 sizeof(maxrate), &maxrate); 1067 if (err) 1068 return -EMSGSIZE; 1069 } 1070 } 1071 1072 if (ops->ieee_getqcn) { 1073 struct ieee_qcn qcn; 1074 1075 memset(&qcn, 0, sizeof(qcn)); 1076 err = ops->ieee_getqcn(netdev, &qcn); 1077 if (!err) { 1078 err = nla_put(skb, DCB_ATTR_IEEE_QCN, 1079 sizeof(qcn), &qcn); 1080 if (err) 1081 return -EMSGSIZE; 1082 } 1083 } 1084 1085 if (ops->ieee_getqcnstats) { 1086 struct ieee_qcn_stats qcn_stats; 1087 1088 memset(&qcn_stats, 0, sizeof(qcn_stats)); 1089 err = ops->ieee_getqcnstats(netdev, &qcn_stats); 1090 if (!err) { 1091 err = nla_put(skb, DCB_ATTR_IEEE_QCN_STATS, 1092 sizeof(qcn_stats), &qcn_stats); 1093 if (err) 1094 return -EMSGSIZE; 1095 } 1096 } 1097 1098 if (ops->ieee_getpfc) { 1099 struct ieee_pfc pfc; 1100 memset(&pfc, 0, sizeof(pfc)); 1101 err = ops->ieee_getpfc(netdev, &pfc); 1102 if (!err && 1103 nla_put(skb, DCB_ATTR_IEEE_PFC, sizeof(pfc), &pfc)) 1104 return -EMSGSIZE; 1105 } 1106 1107 app = nla_nest_start(skb, DCB_ATTR_IEEE_APP_TABLE); 1108 if (!app) 1109 return -EMSGSIZE; 1110 1111 spin_lock_bh(&dcb_lock); 1112 list_for_each_entry(itr, &dcb_app_list, list) { 1113 if (itr->ifindex == netdev->ifindex) { 1114 err = nla_put(skb, DCB_ATTR_IEEE_APP, sizeof(itr->app), 1115 &itr->app); 1116 if (err) { 1117 spin_unlock_bh(&dcb_lock); 1118 return -EMSGSIZE; 1119 } 1120 } 1121 } 1122 1123 if (netdev->dcbnl_ops->getdcbx) 1124 dcbx = netdev->dcbnl_ops->getdcbx(netdev); 1125 else 1126 dcbx = -EOPNOTSUPP; 1127 1128 spin_unlock_bh(&dcb_lock); 1129 nla_nest_end(skb, app); 1130 1131 /* get peer info if available */ 1132 if (ops->ieee_peer_getets) { 1133 struct ieee_ets ets; 1134 memset(&ets, 0, sizeof(ets)); 1135 err = ops->ieee_peer_getets(netdev, &ets); 1136 if (!err && 1137 nla_put(skb, DCB_ATTR_IEEE_PEER_ETS, sizeof(ets), &ets)) 1138 return -EMSGSIZE; 1139 } 1140 1141 if (ops->ieee_peer_getpfc) { 1142 struct ieee_pfc pfc; 1143 memset(&pfc, 0, sizeof(pfc)); 1144 err = ops->ieee_peer_getpfc(netdev, &pfc); 1145 if (!err && 1146 nla_put(skb, DCB_ATTR_IEEE_PEER_PFC, sizeof(pfc), &pfc)) 1147 return -EMSGSIZE; 1148 } 1149 1150 if (ops->peer_getappinfo && ops->peer_getapptable) { 1151 err = dcbnl_build_peer_app(netdev, skb, 1152 DCB_ATTR_IEEE_PEER_APP, 1153 DCB_ATTR_IEEE_APP_UNSPEC, 1154 DCB_ATTR_IEEE_APP); 1155 if (err) 1156 return -EMSGSIZE; 1157 } 1158 1159 nla_nest_end(skb, ieee); 1160 if (dcbx >= 0) { 1161 err = nla_put_u8(skb, DCB_ATTR_DCBX, dcbx); 1162 if (err) 1163 return -EMSGSIZE; 1164 } 1165 1166 return 0; 1167} 1168 1169static int dcbnl_cee_pg_fill(struct sk_buff *skb, struct net_device *dev, 1170 int dir) 1171{ 1172 u8 pgid, up_map, prio, tc_pct; 1173 const struct dcbnl_rtnl_ops *ops = dev->dcbnl_ops; 1174 int i = dir ? DCB_ATTR_CEE_TX_PG : DCB_ATTR_CEE_RX_PG; 1175 struct nlattr *pg = nla_nest_start(skb, i); 1176 1177 if (!pg) 1178 return -EMSGSIZE; 1179 1180 for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) { 1181 struct nlattr *tc_nest = nla_nest_start(skb, i); 1182 1183 if (!tc_nest) 1184 return -EMSGSIZE; 1185 1186 pgid = DCB_ATTR_VALUE_UNDEFINED; 1187 prio = DCB_ATTR_VALUE_UNDEFINED; 1188 tc_pct = DCB_ATTR_VALUE_UNDEFINED; 1189 up_map = DCB_ATTR_VALUE_UNDEFINED; 1190 1191 if (!dir) 1192 ops->getpgtccfgrx(dev, i - DCB_PG_ATTR_TC_0, 1193 &prio, &pgid, &tc_pct, &up_map); 1194 else 1195 ops->getpgtccfgtx(dev, i - DCB_PG_ATTR_TC_0, 1196 &prio, &pgid, &tc_pct, &up_map); 1197 1198 if (nla_put_u8(skb, DCB_TC_ATTR_PARAM_PGID, pgid) || 1199 nla_put_u8(skb, DCB_TC_ATTR_PARAM_UP_MAPPING, up_map) || 1200 nla_put_u8(skb, DCB_TC_ATTR_PARAM_STRICT_PRIO, prio) || 1201 nla_put_u8(skb, DCB_TC_ATTR_PARAM_BW_PCT, tc_pct)) 1202 return -EMSGSIZE; 1203 nla_nest_end(skb, tc_nest); 1204 } 1205 1206 for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) { 1207 tc_pct = DCB_ATTR_VALUE_UNDEFINED; 1208 1209 if (!dir) 1210 ops->getpgbwgcfgrx(dev, i - DCB_PG_ATTR_BW_ID_0, 1211 &tc_pct); 1212 else 1213 ops->getpgbwgcfgtx(dev, i - DCB_PG_ATTR_BW_ID_0, 1214 &tc_pct); 1215 if (nla_put_u8(skb, i, tc_pct)) 1216 return -EMSGSIZE; 1217 } 1218 nla_nest_end(skb, pg); 1219 return 0; 1220} 1221 1222static int dcbnl_cee_fill(struct sk_buff *skb, struct net_device *netdev) 1223{ 1224 struct nlattr *cee, *app; 1225 struct dcb_app_type *itr; 1226 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1227 int dcbx, i, err = -EMSGSIZE; 1228 u8 value; 1229 1230 if (nla_put_string(skb, DCB_ATTR_IFNAME, netdev->name)) 1231 goto nla_put_failure; 1232 cee = nla_nest_start(skb, DCB_ATTR_CEE); 1233 if (!cee) 1234 goto nla_put_failure; 1235 1236 /* local pg */ 1237 if (ops->getpgtccfgtx && ops->getpgbwgcfgtx) { 1238 err = dcbnl_cee_pg_fill(skb, netdev, 1); 1239 if (err) 1240 goto nla_put_failure; 1241 } 1242 1243 if (ops->getpgtccfgrx && ops->getpgbwgcfgrx) { 1244 err = dcbnl_cee_pg_fill(skb, netdev, 0); 1245 if (err) 1246 goto nla_put_failure; 1247 } 1248 1249 /* local pfc */ 1250 if (ops->getpfccfg) { 1251 struct nlattr *pfc_nest = nla_nest_start(skb, DCB_ATTR_CEE_PFC); 1252 1253 if (!pfc_nest) 1254 goto nla_put_failure; 1255 1256 for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) { 1257 ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0, &value); 1258 if (nla_put_u8(skb, i, value)) 1259 goto nla_put_failure; 1260 } 1261 nla_nest_end(skb, pfc_nest); 1262 } 1263 1264 /* local app */ 1265 spin_lock_bh(&dcb_lock); 1266 app = nla_nest_start(skb, DCB_ATTR_CEE_APP_TABLE); 1267 if (!app) 1268 goto dcb_unlock; 1269 1270 list_for_each_entry(itr, &dcb_app_list, list) { 1271 if (itr->ifindex == netdev->ifindex) { 1272 struct nlattr *app_nest = nla_nest_start(skb, 1273 DCB_ATTR_APP); 1274 if (!app_nest) 1275 goto dcb_unlock; 1276 1277 err = nla_put_u8(skb, DCB_APP_ATTR_IDTYPE, 1278 itr->app.selector); 1279 if (err) 1280 goto dcb_unlock; 1281 1282 err = nla_put_u16(skb, DCB_APP_ATTR_ID, 1283 itr->app.protocol); 1284 if (err) 1285 goto dcb_unlock; 1286 1287 err = nla_put_u8(skb, DCB_APP_ATTR_PRIORITY, 1288 itr->app.priority); 1289 if (err) 1290 goto dcb_unlock; 1291 1292 nla_nest_end(skb, app_nest); 1293 } 1294 } 1295 nla_nest_end(skb, app); 1296 1297 if (netdev->dcbnl_ops->getdcbx) 1298 dcbx = netdev->dcbnl_ops->getdcbx(netdev); 1299 else 1300 dcbx = -EOPNOTSUPP; 1301 1302 spin_unlock_bh(&dcb_lock); 1303 1304 /* features flags */ 1305 if (ops->getfeatcfg) { 1306 struct nlattr *feat = nla_nest_start(skb, DCB_ATTR_CEE_FEAT); 1307 if (!feat) 1308 goto nla_put_failure; 1309 1310 for (i = DCB_FEATCFG_ATTR_ALL + 1; i <= DCB_FEATCFG_ATTR_MAX; 1311 i++) 1312 if (!ops->getfeatcfg(netdev, i, &value) && 1313 nla_put_u8(skb, i, value)) 1314 goto nla_put_failure; 1315 1316 nla_nest_end(skb, feat); 1317 } 1318 1319 /* peer info if available */ 1320 if (ops->cee_peer_getpg) { 1321 struct cee_pg pg; 1322 memset(&pg, 0, sizeof(pg)); 1323 err = ops->cee_peer_getpg(netdev, &pg); 1324 if (!err && 1325 nla_put(skb, DCB_ATTR_CEE_PEER_PG, sizeof(pg), &pg)) 1326 goto nla_put_failure; 1327 } 1328 1329 if (ops->cee_peer_getpfc) { 1330 struct cee_pfc pfc; 1331 memset(&pfc, 0, sizeof(pfc)); 1332 err = ops->cee_peer_getpfc(netdev, &pfc); 1333 if (!err && 1334 nla_put(skb, DCB_ATTR_CEE_PEER_PFC, sizeof(pfc), &pfc)) 1335 goto nla_put_failure; 1336 } 1337 1338 if (ops->peer_getappinfo && ops->peer_getapptable) { 1339 err = dcbnl_build_peer_app(netdev, skb, 1340 DCB_ATTR_CEE_PEER_APP_TABLE, 1341 DCB_ATTR_CEE_PEER_APP_INFO, 1342 DCB_ATTR_CEE_PEER_APP); 1343 if (err) 1344 goto nla_put_failure; 1345 } 1346 nla_nest_end(skb, cee); 1347 1348 /* DCBX state */ 1349 if (dcbx >= 0) { 1350 err = nla_put_u8(skb, DCB_ATTR_DCBX, dcbx); 1351 if (err) 1352 goto nla_put_failure; 1353 } 1354 return 0; 1355 1356dcb_unlock: 1357 spin_unlock_bh(&dcb_lock); 1358nla_put_failure: 1359 return err; 1360} 1361 1362static int dcbnl_notify(struct net_device *dev, int event, int cmd, 1363 u32 seq, u32 portid, int dcbx_ver) 1364{ 1365 struct net *net = dev_net(dev); 1366 struct sk_buff *skb; 1367 struct nlmsghdr *nlh; 1368 const struct dcbnl_rtnl_ops *ops = dev->dcbnl_ops; 1369 int err; 1370 1371 if (!ops) 1372 return -EOPNOTSUPP; 1373 1374 skb = dcbnl_newmsg(event, cmd, portid, seq, 0, &nlh); 1375 if (!skb) 1376 return -ENOBUFS; 1377 1378 if (dcbx_ver == DCB_CAP_DCBX_VER_IEEE) 1379 err = dcbnl_ieee_fill(skb, dev); 1380 else 1381 err = dcbnl_cee_fill(skb, dev); 1382 1383 if (err < 0) { 1384 /* Report error to broadcast listeners */ 1385 nlmsg_free(skb); 1386 rtnl_set_sk_err(net, RTNLGRP_DCB, err); 1387 } else { 1388 /* End nlmsg and notify broadcast listeners */ 1389 nlmsg_end(skb, nlh); 1390 rtnl_notify(skb, net, 0, RTNLGRP_DCB, NULL, GFP_KERNEL); 1391 } 1392 1393 return err; 1394} 1395 1396int dcbnl_ieee_notify(struct net_device *dev, int event, int cmd, 1397 u32 seq, u32 portid) 1398{ 1399 return dcbnl_notify(dev, event, cmd, seq, portid, DCB_CAP_DCBX_VER_IEEE); 1400} 1401EXPORT_SYMBOL(dcbnl_ieee_notify); 1402 1403int dcbnl_cee_notify(struct net_device *dev, int event, int cmd, 1404 u32 seq, u32 portid) 1405{ 1406 return dcbnl_notify(dev, event, cmd, seq, portid, DCB_CAP_DCBX_VER_CEE); 1407} 1408EXPORT_SYMBOL(dcbnl_cee_notify); 1409 1410/* Handle IEEE 802.1Qaz/802.1Qau/802.1Qbb SET commands. 1411 * If any requested operation can not be completed 1412 * the entire msg is aborted and error value is returned. 1413 * No attempt is made to reconcile the case where only part of the 1414 * cmd can be completed. 1415 */ 1416static int dcbnl_ieee_set(struct net_device *netdev, struct nlmsghdr *nlh, 1417 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1418{ 1419 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1420 struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1]; 1421 int err; 1422 1423 if (!ops) 1424 return -EOPNOTSUPP; 1425 1426 if (!tb[DCB_ATTR_IEEE]) 1427 return -EINVAL; 1428 1429 err = nla_parse_nested(ieee, DCB_ATTR_IEEE_MAX, 1430 tb[DCB_ATTR_IEEE], dcbnl_ieee_policy); 1431 if (err) 1432 return err; 1433 1434 if (ieee[DCB_ATTR_IEEE_ETS] && ops->ieee_setets) { 1435 struct ieee_ets *ets = nla_data(ieee[DCB_ATTR_IEEE_ETS]); 1436 err = ops->ieee_setets(netdev, ets); 1437 if (err) 1438 goto err; 1439 } 1440 1441 if (ieee[DCB_ATTR_IEEE_MAXRATE] && ops->ieee_setmaxrate) { 1442 struct ieee_maxrate *maxrate = 1443 nla_data(ieee[DCB_ATTR_IEEE_MAXRATE]); 1444 err = ops->ieee_setmaxrate(netdev, maxrate); 1445 if (err) 1446 goto err; 1447 } 1448 1449 if (ieee[DCB_ATTR_IEEE_QCN] && ops->ieee_setqcn) { 1450 struct ieee_qcn *qcn = 1451 nla_data(ieee[DCB_ATTR_IEEE_QCN]); 1452 1453 err = ops->ieee_setqcn(netdev, qcn); 1454 if (err) 1455 goto err; 1456 } 1457 1458 if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setpfc) { 1459 struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]); 1460 err = ops->ieee_setpfc(netdev, pfc); 1461 if (err) 1462 goto err; 1463 } 1464 1465 if (ieee[DCB_ATTR_IEEE_APP_TABLE]) { 1466 struct nlattr *attr; 1467 int rem; 1468 1469 nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) { 1470 struct dcb_app *app_data; 1471 if (nla_type(attr) != DCB_ATTR_IEEE_APP) 1472 continue; 1473 app_data = nla_data(attr); 1474 if (ops->ieee_setapp) 1475 err = ops->ieee_setapp(netdev, app_data); 1476 else 1477 err = dcb_ieee_setapp(netdev, app_data); 1478 if (err) 1479 goto err; 1480 } 1481 } 1482 1483err: 1484 err = nla_put_u8(skb, DCB_ATTR_IEEE, err); 1485 dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_SET, seq, 0); 1486 return err; 1487} 1488 1489static int dcbnl_ieee_get(struct net_device *netdev, struct nlmsghdr *nlh, 1490 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1491{ 1492 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1493 1494 if (!ops) 1495 return -EOPNOTSUPP; 1496 1497 return dcbnl_ieee_fill(skb, netdev); 1498} 1499 1500static int dcbnl_ieee_del(struct net_device *netdev, struct nlmsghdr *nlh, 1501 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1502{ 1503 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1504 struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1]; 1505 int err; 1506 1507 if (!ops) 1508 return -EOPNOTSUPP; 1509 1510 if (!tb[DCB_ATTR_IEEE]) 1511 return -EINVAL; 1512 1513 err = nla_parse_nested(ieee, DCB_ATTR_IEEE_MAX, 1514 tb[DCB_ATTR_IEEE], dcbnl_ieee_policy); 1515 if (err) 1516 return err; 1517 1518 if (ieee[DCB_ATTR_IEEE_APP_TABLE]) { 1519 struct nlattr *attr; 1520 int rem; 1521 1522 nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) { 1523 struct dcb_app *app_data; 1524 1525 if (nla_type(attr) != DCB_ATTR_IEEE_APP) 1526 continue; 1527 app_data = nla_data(attr); 1528 if (ops->ieee_delapp) 1529 err = ops->ieee_delapp(netdev, app_data); 1530 else 1531 err = dcb_ieee_delapp(netdev, app_data); 1532 if (err) 1533 goto err; 1534 } 1535 } 1536 1537err: 1538 err = nla_put_u8(skb, DCB_ATTR_IEEE, err); 1539 dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_DEL, seq, 0); 1540 return err; 1541} 1542 1543 1544/* DCBX configuration */ 1545static int dcbnl_getdcbx(struct net_device *netdev, struct nlmsghdr *nlh, 1546 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1547{ 1548 if (!netdev->dcbnl_ops->getdcbx) 1549 return -EOPNOTSUPP; 1550 1551 return nla_put_u8(skb, DCB_ATTR_DCBX, 1552 netdev->dcbnl_ops->getdcbx(netdev)); 1553} 1554 1555static int dcbnl_setdcbx(struct net_device *netdev, struct nlmsghdr *nlh, 1556 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1557{ 1558 u8 value; 1559 1560 if (!netdev->dcbnl_ops->setdcbx) 1561 return -EOPNOTSUPP; 1562 1563 if (!tb[DCB_ATTR_DCBX]) 1564 return -EINVAL; 1565 1566 value = nla_get_u8(tb[DCB_ATTR_DCBX]); 1567 1568 return nla_put_u8(skb, DCB_ATTR_DCBX, 1569 netdev->dcbnl_ops->setdcbx(netdev, value)); 1570} 1571 1572static int dcbnl_getfeatcfg(struct net_device *netdev, struct nlmsghdr *nlh, 1573 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1574{ 1575 struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1], *nest; 1576 u8 value; 1577 int ret, i; 1578 int getall = 0; 1579 1580 if (!netdev->dcbnl_ops->getfeatcfg) 1581 return -EOPNOTSUPP; 1582 1583 if (!tb[DCB_ATTR_FEATCFG]) 1584 return -EINVAL; 1585 1586 ret = nla_parse_nested(data, DCB_FEATCFG_ATTR_MAX, tb[DCB_ATTR_FEATCFG], 1587 dcbnl_featcfg_nest); 1588 if (ret) 1589 return ret; 1590 1591 nest = nla_nest_start(skb, DCB_ATTR_FEATCFG); 1592 if (!nest) 1593 return -EMSGSIZE; 1594 1595 if (data[DCB_FEATCFG_ATTR_ALL]) 1596 getall = 1; 1597 1598 for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) { 1599 if (!getall && !data[i]) 1600 continue; 1601 1602 ret = netdev->dcbnl_ops->getfeatcfg(netdev, i, &value); 1603 if (!ret) 1604 ret = nla_put_u8(skb, i, value); 1605 1606 if (ret) { 1607 nla_nest_cancel(skb, nest); 1608 goto nla_put_failure; 1609 } 1610 } 1611 nla_nest_end(skb, nest); 1612 1613nla_put_failure: 1614 return ret; 1615} 1616 1617static int dcbnl_setfeatcfg(struct net_device *netdev, struct nlmsghdr *nlh, 1618 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1619{ 1620 struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1]; 1621 int ret, i; 1622 u8 value; 1623 1624 if (!netdev->dcbnl_ops->setfeatcfg) 1625 return -ENOTSUPP; 1626 1627 if (!tb[DCB_ATTR_FEATCFG]) 1628 return -EINVAL; 1629 1630 ret = nla_parse_nested(data, DCB_FEATCFG_ATTR_MAX, tb[DCB_ATTR_FEATCFG], 1631 dcbnl_featcfg_nest); 1632 1633 if (ret) 1634 goto err; 1635 1636 for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) { 1637 if (data[i] == NULL) 1638 continue; 1639 1640 value = nla_get_u8(data[i]); 1641 1642 ret = netdev->dcbnl_ops->setfeatcfg(netdev, i, value); 1643 1644 if (ret) 1645 goto err; 1646 } 1647err: 1648 ret = nla_put_u8(skb, DCB_ATTR_FEATCFG, ret); 1649 1650 return ret; 1651} 1652 1653/* Handle CEE DCBX GET commands. */ 1654static int dcbnl_cee_get(struct net_device *netdev, struct nlmsghdr *nlh, 1655 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1656{ 1657 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1658 1659 if (!ops) 1660 return -EOPNOTSUPP; 1661 1662 return dcbnl_cee_fill(skb, netdev); 1663} 1664 1665struct reply_func { 1666 /* reply netlink message type */ 1667 int type; 1668 1669 /* function to fill message contents */ 1670 int (*cb)(struct net_device *, struct nlmsghdr *, u32, 1671 struct nlattr **, struct sk_buff *); 1672}; 1673 1674static const struct reply_func reply_funcs[DCB_CMD_MAX+1] = { 1675 [DCB_CMD_GSTATE] = { RTM_GETDCB, dcbnl_getstate }, 1676 [DCB_CMD_SSTATE] = { RTM_SETDCB, dcbnl_setstate }, 1677 [DCB_CMD_PFC_GCFG] = { RTM_GETDCB, dcbnl_getpfccfg }, 1678 [DCB_CMD_PFC_SCFG] = { RTM_SETDCB, dcbnl_setpfccfg }, 1679 [DCB_CMD_GPERM_HWADDR] = { RTM_GETDCB, dcbnl_getperm_hwaddr }, 1680 [DCB_CMD_GCAP] = { RTM_GETDCB, dcbnl_getcap }, 1681 [DCB_CMD_GNUMTCS] = { RTM_GETDCB, dcbnl_getnumtcs }, 1682 [DCB_CMD_SNUMTCS] = { RTM_SETDCB, dcbnl_setnumtcs }, 1683 [DCB_CMD_PFC_GSTATE] = { RTM_GETDCB, dcbnl_getpfcstate }, 1684 [DCB_CMD_PFC_SSTATE] = { RTM_SETDCB, dcbnl_setpfcstate }, 1685 [DCB_CMD_GAPP] = { RTM_GETDCB, dcbnl_getapp }, 1686 [DCB_CMD_SAPP] = { RTM_SETDCB, dcbnl_setapp }, 1687 [DCB_CMD_PGTX_GCFG] = { RTM_GETDCB, dcbnl_pgtx_getcfg }, 1688 [DCB_CMD_PGTX_SCFG] = { RTM_SETDCB, dcbnl_pgtx_setcfg }, 1689 [DCB_CMD_PGRX_GCFG] = { RTM_GETDCB, dcbnl_pgrx_getcfg }, 1690 [DCB_CMD_PGRX_SCFG] = { RTM_SETDCB, dcbnl_pgrx_setcfg }, 1691 [DCB_CMD_SET_ALL] = { RTM_SETDCB, dcbnl_setall }, 1692 [DCB_CMD_BCN_GCFG] = { RTM_GETDCB, dcbnl_bcn_getcfg }, 1693 [DCB_CMD_BCN_SCFG] = { RTM_SETDCB, dcbnl_bcn_setcfg }, 1694 [DCB_CMD_IEEE_GET] = { RTM_GETDCB, dcbnl_ieee_get }, 1695 [DCB_CMD_IEEE_SET] = { RTM_SETDCB, dcbnl_ieee_set }, 1696 [DCB_CMD_IEEE_DEL] = { RTM_SETDCB, dcbnl_ieee_del }, 1697 [DCB_CMD_GDCBX] = { RTM_GETDCB, dcbnl_getdcbx }, 1698 [DCB_CMD_SDCBX] = { RTM_SETDCB, dcbnl_setdcbx }, 1699 [DCB_CMD_GFEATCFG] = { RTM_GETDCB, dcbnl_getfeatcfg }, 1700 [DCB_CMD_SFEATCFG] = { RTM_SETDCB, dcbnl_setfeatcfg }, 1701 [DCB_CMD_CEE_GET] = { RTM_GETDCB, dcbnl_cee_get }, 1702}; 1703 1704static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh) 1705{ 1706 struct net *net = sock_net(skb->sk); 1707 struct net_device *netdev; 1708 struct dcbmsg *dcb = nlmsg_data(nlh); 1709 struct nlattr *tb[DCB_ATTR_MAX + 1]; 1710 u32 portid = skb ? NETLINK_CB(skb).portid : 0; 1711 int ret = -EINVAL; 1712 struct sk_buff *reply_skb; 1713 struct nlmsghdr *reply_nlh = NULL; 1714 const struct reply_func *fn; 1715 1716 if ((nlh->nlmsg_type == RTM_SETDCB) && !netlink_capable(skb, CAP_NET_ADMIN)) 1717 return -EPERM; 1718 1719 ret = nlmsg_parse(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX, 1720 dcbnl_rtnl_policy); 1721 if (ret < 0) 1722 return ret; 1723 1724 if (dcb->cmd > DCB_CMD_MAX) 1725 return -EINVAL; 1726 1727 /* check if a reply function has been defined for the command */ 1728 fn = &reply_funcs[dcb->cmd]; 1729 if (!fn->cb) 1730 return -EOPNOTSUPP; 1731 1732 if (!tb[DCB_ATTR_IFNAME]) 1733 return -EINVAL; 1734 1735 netdev = __dev_get_by_name(net, nla_data(tb[DCB_ATTR_IFNAME])); 1736 if (!netdev) 1737 return -ENODEV; 1738 1739 if (!netdev->dcbnl_ops) 1740 return -EOPNOTSUPP; 1741 1742 reply_skb = dcbnl_newmsg(fn->type, dcb->cmd, portid, nlh->nlmsg_seq, 1743 nlh->nlmsg_flags, &reply_nlh); 1744 if (!reply_skb) 1745 return -ENOBUFS; 1746 1747 ret = fn->cb(netdev, nlh, nlh->nlmsg_seq, tb, reply_skb); 1748 if (ret < 0) { 1749 nlmsg_free(reply_skb); 1750 goto out; 1751 } 1752 1753 nlmsg_end(reply_skb, reply_nlh); 1754 1755 ret = rtnl_unicast(reply_skb, net, portid); 1756out: 1757 return ret; 1758} 1759 1760static struct dcb_app_type *dcb_app_lookup(const struct dcb_app *app, 1761 int ifindex, int prio) 1762{ 1763 struct dcb_app_type *itr; 1764 1765 list_for_each_entry(itr, &dcb_app_list, list) { 1766 if (itr->app.selector == app->selector && 1767 itr->app.protocol == app->protocol && 1768 itr->ifindex == ifindex && 1769 (!prio || itr->app.priority == prio)) 1770 return itr; 1771 } 1772 1773 return NULL; 1774} 1775 1776static int dcb_app_add(const struct dcb_app *app, int ifindex) 1777{ 1778 struct dcb_app_type *entry; 1779 1780 entry = kmalloc(sizeof(*entry), GFP_ATOMIC); 1781 if (!entry) 1782 return -ENOMEM; 1783 1784 memcpy(&entry->app, app, sizeof(*app)); 1785 entry->ifindex = ifindex; 1786 list_add(&entry->list, &dcb_app_list); 1787 1788 return 0; 1789} 1790 1791/** 1792 * dcb_getapp - retrieve the DCBX application user priority 1793 * 1794 * On success returns a non-zero 802.1p user priority bitmap 1795 * otherwise returns 0 as the invalid user priority bitmap to 1796 * indicate an error. 1797 */ 1798u8 dcb_getapp(struct net_device *dev, struct dcb_app *app) 1799{ 1800 struct dcb_app_type *itr; 1801 u8 prio = 0; 1802 1803 spin_lock_bh(&dcb_lock); 1804 if ((itr = dcb_app_lookup(app, dev->ifindex, 0))) 1805 prio = itr->app.priority; 1806 spin_unlock_bh(&dcb_lock); 1807 1808 return prio; 1809} 1810EXPORT_SYMBOL(dcb_getapp); 1811 1812/** 1813 * dcb_setapp - add CEE dcb application data to app list 1814 * 1815 * Priority 0 is an invalid priority in CEE spec. This routine 1816 * removes applications from the app list if the priority is 1817 * set to zero. Priority is expected to be 8-bit 802.1p user priority bitmap 1818 */ 1819int dcb_setapp(struct net_device *dev, struct dcb_app *new) 1820{ 1821 struct dcb_app_type *itr; 1822 struct dcb_app_type event; 1823 int err = 0; 1824 1825 event.ifindex = dev->ifindex; 1826 memcpy(&event.app, new, sizeof(event.app)); 1827 if (dev->dcbnl_ops->getdcbx) 1828 event.dcbx = dev->dcbnl_ops->getdcbx(dev); 1829 1830 spin_lock_bh(&dcb_lock); 1831 /* Search for existing match and replace */ 1832 if ((itr = dcb_app_lookup(new, dev->ifindex, 0))) { 1833 if (new->priority) 1834 itr->app.priority = new->priority; 1835 else { 1836 list_del(&itr->list); 1837 kfree(itr); 1838 } 1839 goto out; 1840 } 1841 /* App type does not exist add new application type */ 1842 if (new->priority) 1843 err = dcb_app_add(new, dev->ifindex); 1844out: 1845 spin_unlock_bh(&dcb_lock); 1846 if (!err) 1847 call_dcbevent_notifiers(DCB_APP_EVENT, &event); 1848 return err; 1849} 1850EXPORT_SYMBOL(dcb_setapp); 1851 1852/** 1853 * dcb_ieee_getapp_mask - retrieve the IEEE DCB application priority 1854 * 1855 * Helper routine which on success returns a non-zero 802.1Qaz user 1856 * priority bitmap otherwise returns 0 to indicate the dcb_app was 1857 * not found in APP list. 1858 */ 1859u8 dcb_ieee_getapp_mask(struct net_device *dev, struct dcb_app *app) 1860{ 1861 struct dcb_app_type *itr; 1862 u8 prio = 0; 1863 1864 spin_lock_bh(&dcb_lock); 1865 if ((itr = dcb_app_lookup(app, dev->ifindex, 0))) 1866 prio |= 1 << itr->app.priority; 1867 spin_unlock_bh(&dcb_lock); 1868 1869 return prio; 1870} 1871EXPORT_SYMBOL(dcb_ieee_getapp_mask); 1872 1873/** 1874 * dcb_ieee_setapp - add IEEE dcb application data to app list 1875 * 1876 * This adds Application data to the list. Multiple application 1877 * entries may exists for the same selector and protocol as long 1878 * as the priorities are different. Priority is expected to be a 1879 * 3-bit unsigned integer 1880 */ 1881int dcb_ieee_setapp(struct net_device *dev, struct dcb_app *new) 1882{ 1883 struct dcb_app_type event; 1884 int err = 0; 1885 1886 event.ifindex = dev->ifindex; 1887 memcpy(&event.app, new, sizeof(event.app)); 1888 if (dev->dcbnl_ops->getdcbx) 1889 event.dcbx = dev->dcbnl_ops->getdcbx(dev); 1890 1891 spin_lock_bh(&dcb_lock); 1892 /* Search for existing match and abort if found */ 1893 if (dcb_app_lookup(new, dev->ifindex, new->priority)) { 1894 err = -EEXIST; 1895 goto out; 1896 } 1897 1898 err = dcb_app_add(new, dev->ifindex); 1899out: 1900 spin_unlock_bh(&dcb_lock); 1901 if (!err) 1902 call_dcbevent_notifiers(DCB_APP_EVENT, &event); 1903 return err; 1904} 1905EXPORT_SYMBOL(dcb_ieee_setapp); 1906 1907/** 1908 * dcb_ieee_delapp - delete IEEE dcb application data from list 1909 * 1910 * This removes a matching APP data from the APP list 1911 */ 1912int dcb_ieee_delapp(struct net_device *dev, struct dcb_app *del) 1913{ 1914 struct dcb_app_type *itr; 1915 struct dcb_app_type event; 1916 int err = -ENOENT; 1917 1918 event.ifindex = dev->ifindex; 1919 memcpy(&event.app, del, sizeof(event.app)); 1920 if (dev->dcbnl_ops->getdcbx) 1921 event.dcbx = dev->dcbnl_ops->getdcbx(dev); 1922 1923 spin_lock_bh(&dcb_lock); 1924 /* Search for existing match and remove it. */ 1925 if ((itr = dcb_app_lookup(del, dev->ifindex, del->priority))) { 1926 list_del(&itr->list); 1927 kfree(itr); 1928 err = 0; 1929 } 1930 1931 spin_unlock_bh(&dcb_lock); 1932 if (!err) 1933 call_dcbevent_notifiers(DCB_APP_EVENT, &event); 1934 return err; 1935} 1936EXPORT_SYMBOL(dcb_ieee_delapp); 1937 1938static void dcb_flushapp(void) 1939{ 1940 struct dcb_app_type *app; 1941 struct dcb_app_type *tmp; 1942 1943 spin_lock_bh(&dcb_lock); 1944 list_for_each_entry_safe(app, tmp, &dcb_app_list, list) { 1945 list_del(&app->list); 1946 kfree(app); 1947 } 1948 spin_unlock_bh(&dcb_lock); 1949} 1950 1951static int __init dcbnl_init(void) 1952{ 1953 INIT_LIST_HEAD(&dcb_app_list); 1954 1955 rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL, NULL); 1956 rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL, NULL); 1957 1958 return 0; 1959} 1960module_init(dcbnl_init); 1961 1962static void __exit dcbnl_exit(void) 1963{ 1964 rtnl_unregister(PF_UNSPEC, RTM_GETDCB); 1965 rtnl_unregister(PF_UNSPEC, RTM_SETDCB); 1966 dcb_flushapp(); 1967} 1968module_exit(dcbnl_exit); 1969