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