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_array(app_count, sizeof(struct dcb_app), 1025 GFP_KERNEL); 1026 if (!table) 1027 return -ENOMEM; 1028 1029 err = ops->peer_getapptable(netdev, table); 1030 } 1031 1032 if (!err) { 1033 u16 i; 1034 struct nlattr *app; 1035 1036 /** 1037 * build the message, from here on the only possible failure 1038 * is due to the skb size 1039 */ 1040 err = -EMSGSIZE; 1041 1042 app = nla_nest_start_noflag(skb, app_nested_type); 1043 if (!app) 1044 goto nla_put_failure; 1045 1046 if (app_info_type && 1047 nla_put(skb, app_info_type, sizeof(info), &info)) 1048 goto nla_put_failure; 1049 1050 for (i = 0; i < app_count; i++) { 1051 if (nla_put(skb, app_entry_type, sizeof(struct dcb_app), 1052 &table[i])) 1053 goto nla_put_failure; 1054 } 1055 nla_nest_end(skb, app); 1056 } 1057 err = 0; 1058 1059 nla_put_failure: 1060 kfree(table); 1061 return err; 1062 } 1063 1064 static int dcbnl_getapptrust(struct net_device *netdev, struct sk_buff *skb) 1065 { 1066 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1067 enum ieee_attrs_app type; 1068 struct nlattr *apptrust; 1069 int nselectors, err, i; 1070 u8 *selectors; 1071 1072 selectors = kzalloc(IEEE_8021QAZ_APP_SEL_MAX + 1, GFP_KERNEL); 1073 if (!selectors) 1074 return -ENOMEM; 1075 1076 err = ops->dcbnl_getapptrust(netdev, selectors, &nselectors); 1077 if (err) { 1078 err = 0; 1079 goto out; 1080 } 1081 1082 apptrust = nla_nest_start(skb, DCB_ATTR_DCB_APP_TRUST_TABLE); 1083 if (!apptrust) { 1084 err = -EMSGSIZE; 1085 goto out; 1086 } 1087 1088 for (i = 0; i < nselectors; i++) { 1089 type = dcbnl_app_attr_type_get(selectors[i]); 1090 err = nla_put_u8(skb, type, selectors[i]); 1091 if (err) { 1092 nla_nest_cancel(skb, apptrust); 1093 goto out; 1094 } 1095 } 1096 nla_nest_end(skb, apptrust); 1097 1098 out: 1099 kfree(selectors); 1100 return err; 1101 } 1102 1103 /* Set or delete APP table or rewrite table entries. The APP struct is validated 1104 * and the appropriate callback function is called. 1105 */ 1106 static int dcbnl_app_table_setdel(struct nlattr *attr, 1107 struct net_device *netdev, 1108 int (*setdel)(struct net_device *dev, 1109 struct dcb_app *app)) 1110 { 1111 struct dcb_app *app_data; 1112 enum ieee_attrs_app type; 1113 struct nlattr *attr_itr; 1114 int rem, err; 1115 1116 nla_for_each_nested(attr_itr, attr, rem) { 1117 type = nla_type(attr_itr); 1118 1119 if (!dcbnl_app_attr_type_validate(type)) 1120 continue; 1121 1122 if (nla_len(attr_itr) < sizeof(struct dcb_app)) 1123 return -ERANGE; 1124 1125 app_data = nla_data(attr_itr); 1126 1127 if (!dcbnl_app_selector_validate(type, app_data->selector)) 1128 return -EINVAL; 1129 1130 err = setdel(netdev, app_data); 1131 if (err) 1132 return err; 1133 } 1134 1135 return 0; 1136 } 1137 1138 /* Handle IEEE 802.1Qaz/802.1Qau/802.1Qbb GET commands. */ 1139 static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev) 1140 { 1141 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1142 struct nlattr *ieee, *app, *rewr; 1143 struct dcb_app_type *itr; 1144 int dcbx; 1145 int err; 1146 1147 if (nla_put_string(skb, DCB_ATTR_IFNAME, netdev->name)) 1148 return -EMSGSIZE; 1149 1150 ieee = nla_nest_start_noflag(skb, DCB_ATTR_IEEE); 1151 if (!ieee) 1152 return -EMSGSIZE; 1153 1154 if (ops->ieee_getets) { 1155 struct ieee_ets ets; 1156 memset(&ets, 0, sizeof(ets)); 1157 err = ops->ieee_getets(netdev, &ets); 1158 if (!err && 1159 nla_put(skb, DCB_ATTR_IEEE_ETS, sizeof(ets), &ets)) 1160 return -EMSGSIZE; 1161 } 1162 1163 if (ops->ieee_getmaxrate) { 1164 struct ieee_maxrate maxrate; 1165 memset(&maxrate, 0, sizeof(maxrate)); 1166 err = ops->ieee_getmaxrate(netdev, &maxrate); 1167 if (!err) { 1168 err = nla_put(skb, DCB_ATTR_IEEE_MAXRATE, 1169 sizeof(maxrate), &maxrate); 1170 if (err) 1171 return -EMSGSIZE; 1172 } 1173 } 1174 1175 if (ops->ieee_getqcn) { 1176 struct ieee_qcn qcn; 1177 1178 memset(&qcn, 0, sizeof(qcn)); 1179 err = ops->ieee_getqcn(netdev, &qcn); 1180 if (!err) { 1181 err = nla_put(skb, DCB_ATTR_IEEE_QCN, 1182 sizeof(qcn), &qcn); 1183 if (err) 1184 return -EMSGSIZE; 1185 } 1186 } 1187 1188 if (ops->ieee_getqcnstats) { 1189 struct ieee_qcn_stats qcn_stats; 1190 1191 memset(&qcn_stats, 0, sizeof(qcn_stats)); 1192 err = ops->ieee_getqcnstats(netdev, &qcn_stats); 1193 if (!err) { 1194 err = nla_put(skb, DCB_ATTR_IEEE_QCN_STATS, 1195 sizeof(qcn_stats), &qcn_stats); 1196 if (err) 1197 return -EMSGSIZE; 1198 } 1199 } 1200 1201 if (ops->ieee_getpfc) { 1202 struct ieee_pfc pfc; 1203 memset(&pfc, 0, sizeof(pfc)); 1204 err = ops->ieee_getpfc(netdev, &pfc); 1205 if (!err && 1206 nla_put(skb, DCB_ATTR_IEEE_PFC, sizeof(pfc), &pfc)) 1207 return -EMSGSIZE; 1208 } 1209 1210 if (ops->dcbnl_getbuffer) { 1211 struct dcbnl_buffer buffer; 1212 1213 memset(&buffer, 0, sizeof(buffer)); 1214 err = ops->dcbnl_getbuffer(netdev, &buffer); 1215 if (!err && 1216 nla_put(skb, DCB_ATTR_DCB_BUFFER, sizeof(buffer), &buffer)) 1217 return -EMSGSIZE; 1218 } 1219 1220 app = nla_nest_start_noflag(skb, DCB_ATTR_IEEE_APP_TABLE); 1221 if (!app) 1222 return -EMSGSIZE; 1223 1224 spin_lock_bh(&dcb_lock); 1225 list_for_each_entry(itr, &dcb_app_list, list) { 1226 if (itr->ifindex == netdev->ifindex) { 1227 enum ieee_attrs_app type = 1228 dcbnl_app_attr_type_get(itr->app.selector); 1229 err = nla_put(skb, type, sizeof(itr->app), &itr->app); 1230 if (err) { 1231 spin_unlock_bh(&dcb_lock); 1232 return -EMSGSIZE; 1233 } 1234 } 1235 } 1236 1237 if (netdev->dcbnl_ops->getdcbx) 1238 dcbx = netdev->dcbnl_ops->getdcbx(netdev); 1239 else 1240 dcbx = -EOPNOTSUPP; 1241 1242 spin_unlock_bh(&dcb_lock); 1243 nla_nest_end(skb, app); 1244 1245 rewr = nla_nest_start(skb, DCB_ATTR_DCB_REWR_TABLE); 1246 if (!rewr) 1247 return -EMSGSIZE; 1248 1249 spin_lock_bh(&dcb_lock); 1250 list_for_each_entry(itr, &dcb_rewr_list, list) { 1251 if (itr->ifindex == netdev->ifindex) { 1252 enum ieee_attrs_app type = 1253 dcbnl_app_attr_type_get(itr->app.selector); 1254 err = nla_put(skb, type, sizeof(itr->app), &itr->app); 1255 if (err) { 1256 spin_unlock_bh(&dcb_lock); 1257 nla_nest_cancel(skb, rewr); 1258 return -EMSGSIZE; 1259 } 1260 } 1261 } 1262 1263 spin_unlock_bh(&dcb_lock); 1264 nla_nest_end(skb, rewr); 1265 1266 if (ops->dcbnl_getapptrust) { 1267 err = dcbnl_getapptrust(netdev, skb); 1268 if (err) 1269 return err; 1270 } 1271 1272 /* get peer info if available */ 1273 if (ops->ieee_peer_getets) { 1274 struct ieee_ets ets; 1275 memset(&ets, 0, sizeof(ets)); 1276 err = ops->ieee_peer_getets(netdev, &ets); 1277 if (!err && 1278 nla_put(skb, DCB_ATTR_IEEE_PEER_ETS, sizeof(ets), &ets)) 1279 return -EMSGSIZE; 1280 } 1281 1282 if (ops->ieee_peer_getpfc) { 1283 struct ieee_pfc pfc; 1284 memset(&pfc, 0, sizeof(pfc)); 1285 err = ops->ieee_peer_getpfc(netdev, &pfc); 1286 if (!err && 1287 nla_put(skb, DCB_ATTR_IEEE_PEER_PFC, sizeof(pfc), &pfc)) 1288 return -EMSGSIZE; 1289 } 1290 1291 if (ops->peer_getappinfo && ops->peer_getapptable) { 1292 err = dcbnl_build_peer_app(netdev, skb, 1293 DCB_ATTR_IEEE_PEER_APP, 1294 DCB_ATTR_IEEE_APP_UNSPEC, 1295 DCB_ATTR_IEEE_APP); 1296 if (err) 1297 return -EMSGSIZE; 1298 } 1299 1300 nla_nest_end(skb, ieee); 1301 if (dcbx >= 0) { 1302 err = nla_put_u8(skb, DCB_ATTR_DCBX, dcbx); 1303 if (err) 1304 return -EMSGSIZE; 1305 } 1306 1307 return 0; 1308 } 1309 1310 static int dcbnl_cee_pg_fill(struct sk_buff *skb, struct net_device *dev, 1311 int dir) 1312 { 1313 u8 pgid, up_map, prio, tc_pct; 1314 const struct dcbnl_rtnl_ops *ops = dev->dcbnl_ops; 1315 int i = dir ? DCB_ATTR_CEE_TX_PG : DCB_ATTR_CEE_RX_PG; 1316 struct nlattr *pg = nla_nest_start_noflag(skb, i); 1317 1318 if (!pg) 1319 return -EMSGSIZE; 1320 1321 for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) { 1322 struct nlattr *tc_nest = nla_nest_start_noflag(skb, i); 1323 1324 if (!tc_nest) 1325 return -EMSGSIZE; 1326 1327 pgid = DCB_ATTR_VALUE_UNDEFINED; 1328 prio = DCB_ATTR_VALUE_UNDEFINED; 1329 tc_pct = DCB_ATTR_VALUE_UNDEFINED; 1330 up_map = DCB_ATTR_VALUE_UNDEFINED; 1331 1332 if (!dir) 1333 ops->getpgtccfgrx(dev, i - DCB_PG_ATTR_TC_0, 1334 &prio, &pgid, &tc_pct, &up_map); 1335 else 1336 ops->getpgtccfgtx(dev, i - DCB_PG_ATTR_TC_0, 1337 &prio, &pgid, &tc_pct, &up_map); 1338 1339 if (nla_put_u8(skb, DCB_TC_ATTR_PARAM_PGID, pgid) || 1340 nla_put_u8(skb, DCB_TC_ATTR_PARAM_UP_MAPPING, up_map) || 1341 nla_put_u8(skb, DCB_TC_ATTR_PARAM_STRICT_PRIO, prio) || 1342 nla_put_u8(skb, DCB_TC_ATTR_PARAM_BW_PCT, tc_pct)) 1343 return -EMSGSIZE; 1344 nla_nest_end(skb, tc_nest); 1345 } 1346 1347 for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) { 1348 tc_pct = DCB_ATTR_VALUE_UNDEFINED; 1349 1350 if (!dir) 1351 ops->getpgbwgcfgrx(dev, i - DCB_PG_ATTR_BW_ID_0, 1352 &tc_pct); 1353 else 1354 ops->getpgbwgcfgtx(dev, i - DCB_PG_ATTR_BW_ID_0, 1355 &tc_pct); 1356 if (nla_put_u8(skb, i, tc_pct)) 1357 return -EMSGSIZE; 1358 } 1359 nla_nest_end(skb, pg); 1360 return 0; 1361 } 1362 1363 static int dcbnl_cee_fill(struct sk_buff *skb, struct net_device *netdev) 1364 { 1365 struct nlattr *cee, *app; 1366 struct dcb_app_type *itr; 1367 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1368 int dcbx, i, err = -EMSGSIZE; 1369 u8 value; 1370 1371 if (nla_put_string(skb, DCB_ATTR_IFNAME, netdev->name)) 1372 goto nla_put_failure; 1373 cee = nla_nest_start_noflag(skb, DCB_ATTR_CEE); 1374 if (!cee) 1375 goto nla_put_failure; 1376 1377 /* local pg */ 1378 if (ops->getpgtccfgtx && ops->getpgbwgcfgtx) { 1379 err = dcbnl_cee_pg_fill(skb, netdev, 1); 1380 if (err) 1381 goto nla_put_failure; 1382 } 1383 1384 if (ops->getpgtccfgrx && ops->getpgbwgcfgrx) { 1385 err = dcbnl_cee_pg_fill(skb, netdev, 0); 1386 if (err) 1387 goto nla_put_failure; 1388 } 1389 1390 /* local pfc */ 1391 if (ops->getpfccfg) { 1392 struct nlattr *pfc_nest = nla_nest_start_noflag(skb, 1393 DCB_ATTR_CEE_PFC); 1394 1395 if (!pfc_nest) 1396 goto nla_put_failure; 1397 1398 for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) { 1399 ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0, &value); 1400 if (nla_put_u8(skb, i, value)) 1401 goto nla_put_failure; 1402 } 1403 nla_nest_end(skb, pfc_nest); 1404 } 1405 1406 /* local app */ 1407 spin_lock_bh(&dcb_lock); 1408 app = nla_nest_start_noflag(skb, DCB_ATTR_CEE_APP_TABLE); 1409 if (!app) 1410 goto dcb_unlock; 1411 1412 list_for_each_entry(itr, &dcb_app_list, list) { 1413 if (itr->ifindex == netdev->ifindex) { 1414 struct nlattr *app_nest = nla_nest_start_noflag(skb, 1415 DCB_ATTR_APP); 1416 if (!app_nest) 1417 goto dcb_unlock; 1418 1419 err = nla_put_u8(skb, DCB_APP_ATTR_IDTYPE, 1420 itr->app.selector); 1421 if (err) 1422 goto dcb_unlock; 1423 1424 err = nla_put_u16(skb, DCB_APP_ATTR_ID, 1425 itr->app.protocol); 1426 if (err) 1427 goto dcb_unlock; 1428 1429 err = nla_put_u8(skb, DCB_APP_ATTR_PRIORITY, 1430 itr->app.priority); 1431 if (err) 1432 goto dcb_unlock; 1433 1434 nla_nest_end(skb, app_nest); 1435 } 1436 } 1437 nla_nest_end(skb, app); 1438 1439 if (netdev->dcbnl_ops->getdcbx) 1440 dcbx = netdev->dcbnl_ops->getdcbx(netdev); 1441 else 1442 dcbx = -EOPNOTSUPP; 1443 1444 spin_unlock_bh(&dcb_lock); 1445 1446 /* features flags */ 1447 if (ops->getfeatcfg) { 1448 struct nlattr *feat = nla_nest_start_noflag(skb, 1449 DCB_ATTR_CEE_FEAT); 1450 if (!feat) 1451 goto nla_put_failure; 1452 1453 for (i = DCB_FEATCFG_ATTR_ALL + 1; i <= DCB_FEATCFG_ATTR_MAX; 1454 i++) 1455 if (!ops->getfeatcfg(netdev, i, &value) && 1456 nla_put_u8(skb, i, value)) 1457 goto nla_put_failure; 1458 1459 nla_nest_end(skb, feat); 1460 } 1461 1462 /* peer info if available */ 1463 if (ops->cee_peer_getpg) { 1464 struct cee_pg pg; 1465 memset(&pg, 0, sizeof(pg)); 1466 err = ops->cee_peer_getpg(netdev, &pg); 1467 if (!err && 1468 nla_put(skb, DCB_ATTR_CEE_PEER_PG, sizeof(pg), &pg)) 1469 goto nla_put_failure; 1470 } 1471 1472 if (ops->cee_peer_getpfc) { 1473 struct cee_pfc pfc; 1474 memset(&pfc, 0, sizeof(pfc)); 1475 err = ops->cee_peer_getpfc(netdev, &pfc); 1476 if (!err && 1477 nla_put(skb, DCB_ATTR_CEE_PEER_PFC, sizeof(pfc), &pfc)) 1478 goto nla_put_failure; 1479 } 1480 1481 if (ops->peer_getappinfo && ops->peer_getapptable) { 1482 err = dcbnl_build_peer_app(netdev, skb, 1483 DCB_ATTR_CEE_PEER_APP_TABLE, 1484 DCB_ATTR_CEE_PEER_APP_INFO, 1485 DCB_ATTR_CEE_PEER_APP); 1486 if (err) 1487 goto nla_put_failure; 1488 } 1489 nla_nest_end(skb, cee); 1490 1491 /* DCBX state */ 1492 if (dcbx >= 0) { 1493 err = nla_put_u8(skb, DCB_ATTR_DCBX, dcbx); 1494 if (err) 1495 goto nla_put_failure; 1496 } 1497 return 0; 1498 1499 dcb_unlock: 1500 spin_unlock_bh(&dcb_lock); 1501 nla_put_failure: 1502 err = -EMSGSIZE; 1503 return err; 1504 } 1505 1506 static int dcbnl_notify(struct net_device *dev, int event, int cmd, 1507 u32 seq, u32 portid, int dcbx_ver) 1508 { 1509 struct net *net = dev_net(dev); 1510 struct sk_buff *skb; 1511 struct nlmsghdr *nlh; 1512 const struct dcbnl_rtnl_ops *ops = dev->dcbnl_ops; 1513 int err; 1514 1515 if (!ops) 1516 return -EOPNOTSUPP; 1517 1518 skb = dcbnl_newmsg(event, cmd, portid, seq, 0, &nlh); 1519 if (!skb) 1520 return -ENOMEM; 1521 1522 if (dcbx_ver == DCB_CAP_DCBX_VER_IEEE) 1523 err = dcbnl_ieee_fill(skb, dev); 1524 else 1525 err = dcbnl_cee_fill(skb, dev); 1526 1527 if (err < 0) { 1528 /* Report error to broadcast listeners */ 1529 nlmsg_free(skb); 1530 rtnl_set_sk_err(net, RTNLGRP_DCB, err); 1531 } else { 1532 /* End nlmsg and notify broadcast listeners */ 1533 nlmsg_end(skb, nlh); 1534 rtnl_notify(skb, net, 0, RTNLGRP_DCB, NULL, GFP_KERNEL); 1535 } 1536 1537 return err; 1538 } 1539 1540 int dcbnl_ieee_notify(struct net_device *dev, int event, int cmd, 1541 u32 seq, u32 portid) 1542 { 1543 return dcbnl_notify(dev, event, cmd, seq, portid, DCB_CAP_DCBX_VER_IEEE); 1544 } 1545 EXPORT_SYMBOL(dcbnl_ieee_notify); 1546 1547 int dcbnl_cee_notify(struct net_device *dev, int event, int cmd, 1548 u32 seq, u32 portid) 1549 { 1550 return dcbnl_notify(dev, event, cmd, seq, portid, DCB_CAP_DCBX_VER_CEE); 1551 } 1552 EXPORT_SYMBOL(dcbnl_cee_notify); 1553 1554 /* Handle IEEE 802.1Qaz/802.1Qau/802.1Qbb SET commands. 1555 * If any requested operation can not be completed 1556 * the entire msg is aborted and error value is returned. 1557 * No attempt is made to reconcile the case where only part of the 1558 * cmd can be completed. 1559 */ 1560 static int dcbnl_ieee_set(struct net_device *netdev, struct nlmsghdr *nlh, 1561 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1562 { 1563 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1564 struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1]; 1565 int prio; 1566 int err; 1567 1568 if (!ops) 1569 return -EOPNOTSUPP; 1570 1571 if (!tb[DCB_ATTR_IEEE]) 1572 return -EINVAL; 1573 1574 err = nla_parse_nested_deprecated(ieee, DCB_ATTR_IEEE_MAX, 1575 tb[DCB_ATTR_IEEE], 1576 dcbnl_ieee_policy, NULL); 1577 if (err) 1578 return err; 1579 1580 if (ieee[DCB_ATTR_IEEE_ETS] && ops->ieee_setets) { 1581 struct ieee_ets *ets = nla_data(ieee[DCB_ATTR_IEEE_ETS]); 1582 err = ops->ieee_setets(netdev, ets); 1583 if (err) 1584 goto err; 1585 } 1586 1587 if (ieee[DCB_ATTR_IEEE_MAXRATE] && ops->ieee_setmaxrate) { 1588 struct ieee_maxrate *maxrate = 1589 nla_data(ieee[DCB_ATTR_IEEE_MAXRATE]); 1590 err = ops->ieee_setmaxrate(netdev, maxrate); 1591 if (err) 1592 goto err; 1593 } 1594 1595 if (ieee[DCB_ATTR_IEEE_QCN] && ops->ieee_setqcn) { 1596 struct ieee_qcn *qcn = 1597 nla_data(ieee[DCB_ATTR_IEEE_QCN]); 1598 1599 err = ops->ieee_setqcn(netdev, qcn); 1600 if (err) 1601 goto err; 1602 } 1603 1604 if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setpfc) { 1605 struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]); 1606 err = ops->ieee_setpfc(netdev, pfc); 1607 if (err) 1608 goto err; 1609 } 1610 1611 if (ieee[DCB_ATTR_DCB_BUFFER] && ops->dcbnl_setbuffer) { 1612 struct dcbnl_buffer *buffer = 1613 nla_data(ieee[DCB_ATTR_DCB_BUFFER]); 1614 1615 for (prio = 0; prio < ARRAY_SIZE(buffer->prio2buffer); prio++) { 1616 if (buffer->prio2buffer[prio] >= DCBX_MAX_BUFFERS) { 1617 err = -EINVAL; 1618 goto err; 1619 } 1620 } 1621 1622 err = ops->dcbnl_setbuffer(netdev, buffer); 1623 if (err) 1624 goto err; 1625 } 1626 1627 if (ieee[DCB_ATTR_DCB_REWR_TABLE]) { 1628 err = dcbnl_app_table_setdel(ieee[DCB_ATTR_DCB_REWR_TABLE], 1629 netdev, 1630 ops->dcbnl_setrewr ?: dcb_setrewr); 1631 if (err) 1632 goto err; 1633 } 1634 1635 if (ieee[DCB_ATTR_IEEE_APP_TABLE]) { 1636 err = dcbnl_app_table_setdel(ieee[DCB_ATTR_IEEE_APP_TABLE], 1637 netdev, ops->ieee_setapp ?: 1638 dcb_ieee_setapp); 1639 if (err) 1640 goto err; 1641 } 1642 1643 if (ieee[DCB_ATTR_DCB_APP_TRUST_TABLE]) { 1644 u8 selectors[IEEE_8021QAZ_APP_SEL_MAX + 1] = {0}; 1645 struct nlattr *attr; 1646 int nselectors = 0; 1647 int rem; 1648 1649 if (!ops->dcbnl_setapptrust) { 1650 err = -EOPNOTSUPP; 1651 goto err; 1652 } 1653 1654 nla_for_each_nested(attr, ieee[DCB_ATTR_DCB_APP_TRUST_TABLE], 1655 rem) { 1656 enum ieee_attrs_app type = nla_type(attr); 1657 u8 selector; 1658 int i; 1659 1660 if (!dcbnl_app_attr_type_validate(type) || 1661 nla_len(attr) != 1 || 1662 nselectors >= sizeof(selectors)) { 1663 err = -EINVAL; 1664 goto err; 1665 } 1666 1667 selector = nla_get_u8(attr); 1668 1669 if (!dcbnl_app_selector_validate(type, selector)) { 1670 err = -EINVAL; 1671 goto err; 1672 } 1673 1674 /* Duplicate selector ? */ 1675 for (i = 0; i < nselectors; i++) { 1676 if (selectors[i] == selector) { 1677 err = -EINVAL; 1678 goto err; 1679 } 1680 } 1681 1682 selectors[nselectors++] = selector; 1683 } 1684 1685 err = ops->dcbnl_setapptrust(netdev, selectors, nselectors); 1686 if (err) 1687 goto err; 1688 } 1689 1690 err: 1691 err = nla_put_u8(skb, DCB_ATTR_IEEE, err); 1692 dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_SET, seq, 0); 1693 return err; 1694 } 1695 1696 static int dcbnl_ieee_get(struct net_device *netdev, struct nlmsghdr *nlh, 1697 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1698 { 1699 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1700 1701 if (!ops) 1702 return -EOPNOTSUPP; 1703 1704 return dcbnl_ieee_fill(skb, netdev); 1705 } 1706 1707 static int dcbnl_ieee_del(struct net_device *netdev, struct nlmsghdr *nlh, 1708 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1709 { 1710 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1711 struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1]; 1712 int err; 1713 1714 if (!ops) 1715 return -EOPNOTSUPP; 1716 1717 if (!tb[DCB_ATTR_IEEE]) 1718 return -EINVAL; 1719 1720 err = nla_parse_nested_deprecated(ieee, DCB_ATTR_IEEE_MAX, 1721 tb[DCB_ATTR_IEEE], 1722 dcbnl_ieee_policy, NULL); 1723 if (err) 1724 return err; 1725 1726 if (ieee[DCB_ATTR_IEEE_APP_TABLE]) { 1727 err = dcbnl_app_table_setdel(ieee[DCB_ATTR_IEEE_APP_TABLE], 1728 netdev, ops->ieee_delapp ?: 1729 dcb_ieee_delapp); 1730 if (err) 1731 goto err; 1732 } 1733 1734 if (ieee[DCB_ATTR_DCB_REWR_TABLE]) { 1735 err = dcbnl_app_table_setdel(ieee[DCB_ATTR_DCB_REWR_TABLE], 1736 netdev, 1737 ops->dcbnl_delrewr ?: dcb_delrewr); 1738 if (err) 1739 goto err; 1740 } 1741 1742 err: 1743 err = nla_put_u8(skb, DCB_ATTR_IEEE, err); 1744 dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_DEL, seq, 0); 1745 return err; 1746 } 1747 1748 1749 /* DCBX configuration */ 1750 static int dcbnl_getdcbx(struct net_device *netdev, struct nlmsghdr *nlh, 1751 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1752 { 1753 if (!netdev->dcbnl_ops->getdcbx) 1754 return -EOPNOTSUPP; 1755 1756 return nla_put_u8(skb, DCB_ATTR_DCBX, 1757 netdev->dcbnl_ops->getdcbx(netdev)); 1758 } 1759 1760 static int dcbnl_setdcbx(struct net_device *netdev, struct nlmsghdr *nlh, 1761 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1762 { 1763 u8 value; 1764 1765 if (!netdev->dcbnl_ops->setdcbx) 1766 return -EOPNOTSUPP; 1767 1768 if (!tb[DCB_ATTR_DCBX]) 1769 return -EINVAL; 1770 1771 value = nla_get_u8(tb[DCB_ATTR_DCBX]); 1772 1773 return nla_put_u8(skb, DCB_ATTR_DCBX, 1774 netdev->dcbnl_ops->setdcbx(netdev, value)); 1775 } 1776 1777 static int dcbnl_getfeatcfg(struct net_device *netdev, struct nlmsghdr *nlh, 1778 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1779 { 1780 struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1], *nest; 1781 u8 value; 1782 int ret, i; 1783 int getall = 0; 1784 1785 if (!netdev->dcbnl_ops->getfeatcfg) 1786 return -EOPNOTSUPP; 1787 1788 if (!tb[DCB_ATTR_FEATCFG]) 1789 return -EINVAL; 1790 1791 ret = nla_parse_nested_deprecated(data, DCB_FEATCFG_ATTR_MAX, 1792 tb[DCB_ATTR_FEATCFG], 1793 dcbnl_featcfg_nest, NULL); 1794 if (ret) 1795 return ret; 1796 1797 nest = nla_nest_start_noflag(skb, DCB_ATTR_FEATCFG); 1798 if (!nest) 1799 return -EMSGSIZE; 1800 1801 if (data[DCB_FEATCFG_ATTR_ALL]) 1802 getall = 1; 1803 1804 for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) { 1805 if (!getall && !data[i]) 1806 continue; 1807 1808 ret = netdev->dcbnl_ops->getfeatcfg(netdev, i, &value); 1809 if (!ret) 1810 ret = nla_put_u8(skb, i, value); 1811 1812 if (ret) { 1813 nla_nest_cancel(skb, nest); 1814 goto nla_put_failure; 1815 } 1816 } 1817 nla_nest_end(skb, nest); 1818 1819 nla_put_failure: 1820 return ret; 1821 } 1822 1823 static int dcbnl_setfeatcfg(struct net_device *netdev, struct nlmsghdr *nlh, 1824 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1825 { 1826 struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1]; 1827 int ret, i; 1828 u8 value; 1829 1830 if (!netdev->dcbnl_ops->setfeatcfg) 1831 return -ENOTSUPP; 1832 1833 if (!tb[DCB_ATTR_FEATCFG]) 1834 return -EINVAL; 1835 1836 ret = nla_parse_nested_deprecated(data, DCB_FEATCFG_ATTR_MAX, 1837 tb[DCB_ATTR_FEATCFG], 1838 dcbnl_featcfg_nest, NULL); 1839 1840 if (ret) 1841 goto err; 1842 1843 for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) { 1844 if (data[i] == NULL) 1845 continue; 1846 1847 value = nla_get_u8(data[i]); 1848 1849 ret = netdev->dcbnl_ops->setfeatcfg(netdev, i, value); 1850 1851 if (ret) 1852 goto err; 1853 } 1854 err: 1855 ret = nla_put_u8(skb, DCB_ATTR_FEATCFG, ret); 1856 1857 return ret; 1858 } 1859 1860 /* Handle CEE DCBX GET commands. */ 1861 static int dcbnl_cee_get(struct net_device *netdev, struct nlmsghdr *nlh, 1862 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1863 { 1864 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1865 1866 if (!ops) 1867 return -EOPNOTSUPP; 1868 1869 return dcbnl_cee_fill(skb, netdev); 1870 } 1871 1872 struct reply_func { 1873 /* reply netlink message type */ 1874 int type; 1875 1876 /* function to fill message contents */ 1877 int (*cb)(struct net_device *, struct nlmsghdr *, u32, 1878 struct nlattr **, struct sk_buff *); 1879 }; 1880 1881 static const struct reply_func reply_funcs[DCB_CMD_MAX+1] = { 1882 [DCB_CMD_GSTATE] = { RTM_GETDCB, dcbnl_getstate }, 1883 [DCB_CMD_SSTATE] = { RTM_SETDCB, dcbnl_setstate }, 1884 [DCB_CMD_PFC_GCFG] = { RTM_GETDCB, dcbnl_getpfccfg }, 1885 [DCB_CMD_PFC_SCFG] = { RTM_SETDCB, dcbnl_setpfccfg }, 1886 [DCB_CMD_GPERM_HWADDR] = { RTM_GETDCB, dcbnl_getperm_hwaddr }, 1887 [DCB_CMD_GCAP] = { RTM_GETDCB, dcbnl_getcap }, 1888 [DCB_CMD_GNUMTCS] = { RTM_GETDCB, dcbnl_getnumtcs }, 1889 [DCB_CMD_SNUMTCS] = { RTM_SETDCB, dcbnl_setnumtcs }, 1890 [DCB_CMD_PFC_GSTATE] = { RTM_GETDCB, dcbnl_getpfcstate }, 1891 [DCB_CMD_PFC_SSTATE] = { RTM_SETDCB, dcbnl_setpfcstate }, 1892 [DCB_CMD_GAPP] = { RTM_GETDCB, dcbnl_getapp }, 1893 [DCB_CMD_SAPP] = { RTM_SETDCB, dcbnl_setapp }, 1894 [DCB_CMD_PGTX_GCFG] = { RTM_GETDCB, dcbnl_pgtx_getcfg }, 1895 [DCB_CMD_PGTX_SCFG] = { RTM_SETDCB, dcbnl_pgtx_setcfg }, 1896 [DCB_CMD_PGRX_GCFG] = { RTM_GETDCB, dcbnl_pgrx_getcfg }, 1897 [DCB_CMD_PGRX_SCFG] = { RTM_SETDCB, dcbnl_pgrx_setcfg }, 1898 [DCB_CMD_SET_ALL] = { RTM_SETDCB, dcbnl_setall }, 1899 [DCB_CMD_BCN_GCFG] = { RTM_GETDCB, dcbnl_bcn_getcfg }, 1900 [DCB_CMD_BCN_SCFG] = { RTM_SETDCB, dcbnl_bcn_setcfg }, 1901 [DCB_CMD_IEEE_GET] = { RTM_GETDCB, dcbnl_ieee_get }, 1902 [DCB_CMD_IEEE_SET] = { RTM_SETDCB, dcbnl_ieee_set }, 1903 [DCB_CMD_IEEE_DEL] = { RTM_SETDCB, dcbnl_ieee_del }, 1904 [DCB_CMD_GDCBX] = { RTM_GETDCB, dcbnl_getdcbx }, 1905 [DCB_CMD_SDCBX] = { RTM_SETDCB, dcbnl_setdcbx }, 1906 [DCB_CMD_GFEATCFG] = { RTM_GETDCB, dcbnl_getfeatcfg }, 1907 [DCB_CMD_SFEATCFG] = { RTM_SETDCB, dcbnl_setfeatcfg }, 1908 [DCB_CMD_CEE_GET] = { RTM_GETDCB, dcbnl_cee_get }, 1909 }; 1910 1911 static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, 1912 struct netlink_ext_ack *extack) 1913 { 1914 struct net *net = sock_net(skb->sk); 1915 struct net_device *netdev; 1916 struct dcbmsg *dcb = nlmsg_data(nlh); 1917 struct nlattr *tb[DCB_ATTR_MAX + 1]; 1918 u32 portid = NETLINK_CB(skb).portid; 1919 int ret = -EINVAL; 1920 struct sk_buff *reply_skb; 1921 struct nlmsghdr *reply_nlh = NULL; 1922 const struct reply_func *fn; 1923 1924 if ((nlh->nlmsg_type == RTM_SETDCB) && !netlink_capable(skb, CAP_NET_ADMIN)) 1925 return -EPERM; 1926 1927 ret = nlmsg_parse_deprecated(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX, 1928 dcbnl_rtnl_policy, extack); 1929 if (ret < 0) 1930 return ret; 1931 1932 if (dcb->cmd > DCB_CMD_MAX) 1933 return -EINVAL; 1934 1935 /* check if a reply function has been defined for the command */ 1936 fn = &reply_funcs[dcb->cmd]; 1937 if (!fn->cb) 1938 return -EOPNOTSUPP; 1939 if (fn->type == RTM_SETDCB && !netlink_capable(skb, CAP_NET_ADMIN)) 1940 return -EPERM; 1941 1942 if (!tb[DCB_ATTR_IFNAME]) 1943 return -EINVAL; 1944 1945 netdev = __dev_get_by_name(net, nla_data(tb[DCB_ATTR_IFNAME])); 1946 if (!netdev) 1947 return -ENODEV; 1948 1949 if (!netdev->dcbnl_ops) 1950 return -EOPNOTSUPP; 1951 1952 reply_skb = dcbnl_newmsg(fn->type, dcb->cmd, portid, nlh->nlmsg_seq, 1953 nlh->nlmsg_flags, &reply_nlh); 1954 if (!reply_skb) 1955 return -ENOMEM; 1956 1957 ret = fn->cb(netdev, nlh, nlh->nlmsg_seq, tb, reply_skb); 1958 if (ret < 0) { 1959 nlmsg_free(reply_skb); 1960 goto out; 1961 } 1962 1963 nlmsg_end(reply_skb, reply_nlh); 1964 1965 ret = rtnl_unicast(reply_skb, net, portid); 1966 out: 1967 return ret; 1968 } 1969 1970 static struct dcb_app_type *dcb_rewr_lookup(const struct dcb_app *app, 1971 int ifindex, int proto) 1972 { 1973 struct dcb_app_type *itr; 1974 1975 list_for_each_entry(itr, &dcb_rewr_list, list) { 1976 if (itr->app.selector == app->selector && 1977 itr->app.priority == app->priority && 1978 itr->ifindex == ifindex && 1979 ((proto == -1) || itr->app.protocol == proto)) 1980 return itr; 1981 } 1982 1983 return NULL; 1984 } 1985 1986 static struct dcb_app_type *dcb_app_lookup(const struct dcb_app *app, 1987 int ifindex, int prio) 1988 { 1989 struct dcb_app_type *itr; 1990 1991 list_for_each_entry(itr, &dcb_app_list, list) { 1992 if (itr->app.selector == app->selector && 1993 itr->app.protocol == app->protocol && 1994 itr->ifindex == ifindex && 1995 ((prio == -1) || itr->app.priority == prio)) 1996 return itr; 1997 } 1998 1999 return NULL; 2000 } 2001 2002 static int dcb_app_add(struct list_head *list, const struct dcb_app *app, 2003 int ifindex) 2004 { 2005 struct dcb_app_type *entry; 2006 2007 entry = kmalloc(sizeof(*entry), GFP_ATOMIC); 2008 if (!entry) 2009 return -ENOMEM; 2010 2011 memcpy(&entry->app, app, sizeof(*app)); 2012 entry->ifindex = ifindex; 2013 list_add(&entry->list, list); 2014 2015 return 0; 2016 } 2017 2018 /** 2019 * dcb_getapp - retrieve the DCBX application user priority 2020 * @dev: network interface 2021 * @app: application to get user priority of 2022 * 2023 * On success returns a non-zero 802.1p user priority bitmap 2024 * otherwise returns 0 as the invalid user priority bitmap to 2025 * indicate an error. 2026 */ 2027 u8 dcb_getapp(struct net_device *dev, struct dcb_app *app) 2028 { 2029 struct dcb_app_type *itr; 2030 u8 prio = 0; 2031 2032 spin_lock_bh(&dcb_lock); 2033 itr = dcb_app_lookup(app, dev->ifindex, -1); 2034 if (itr) 2035 prio = itr->app.priority; 2036 spin_unlock_bh(&dcb_lock); 2037 2038 return prio; 2039 } 2040 EXPORT_SYMBOL(dcb_getapp); 2041 2042 /** 2043 * dcb_setapp - add CEE dcb application data to app list 2044 * @dev: network interface 2045 * @new: application data to add 2046 * 2047 * Priority 0 is an invalid priority in CEE spec. This routine 2048 * removes applications from the app list if the priority is 2049 * set to zero. Priority is expected to be 8-bit 802.1p user priority bitmap 2050 */ 2051 int dcb_setapp(struct net_device *dev, struct dcb_app *new) 2052 { 2053 struct dcb_app_type *itr; 2054 struct dcb_app_type event; 2055 int err = 0; 2056 2057 event.ifindex = dev->ifindex; 2058 memcpy(&event.app, new, sizeof(event.app)); 2059 if (dev->dcbnl_ops->getdcbx) 2060 event.dcbx = dev->dcbnl_ops->getdcbx(dev); 2061 2062 spin_lock_bh(&dcb_lock); 2063 /* Search for existing match and replace */ 2064 itr = dcb_app_lookup(new, dev->ifindex, -1); 2065 if (itr) { 2066 if (new->priority) 2067 itr->app.priority = new->priority; 2068 else { 2069 list_del(&itr->list); 2070 kfree(itr); 2071 } 2072 goto out; 2073 } 2074 /* App type does not exist add new application type */ 2075 if (new->priority) 2076 err = dcb_app_add(&dcb_app_list, new, dev->ifindex); 2077 out: 2078 spin_unlock_bh(&dcb_lock); 2079 if (!err) 2080 call_dcbevent_notifiers(DCB_APP_EVENT, &event); 2081 return err; 2082 } 2083 EXPORT_SYMBOL(dcb_setapp); 2084 2085 /** 2086 * dcb_ieee_getapp_mask - retrieve the IEEE DCB application priority 2087 * @dev: network interface 2088 * @app: where to store the retrieve application data 2089 * 2090 * Helper routine which on success returns a non-zero 802.1Qaz user 2091 * priority bitmap otherwise returns 0 to indicate the dcb_app was 2092 * not found in APP list. 2093 */ 2094 u8 dcb_ieee_getapp_mask(struct net_device *dev, struct dcb_app *app) 2095 { 2096 struct dcb_app_type *itr; 2097 u8 prio = 0; 2098 2099 spin_lock_bh(&dcb_lock); 2100 itr = dcb_app_lookup(app, dev->ifindex, -1); 2101 if (itr) 2102 prio |= 1 << itr->app.priority; 2103 spin_unlock_bh(&dcb_lock); 2104 2105 return prio; 2106 } 2107 EXPORT_SYMBOL(dcb_ieee_getapp_mask); 2108 2109 /* Get protocol value from rewrite entry. */ 2110 u16 dcb_getrewr(struct net_device *dev, struct dcb_app *app) 2111 { 2112 struct dcb_app_type *itr; 2113 u16 proto = 0; 2114 2115 spin_lock_bh(&dcb_lock); 2116 itr = dcb_rewr_lookup(app, dev->ifindex, -1); 2117 if (itr) 2118 proto = itr->app.protocol; 2119 spin_unlock_bh(&dcb_lock); 2120 2121 return proto; 2122 } 2123 EXPORT_SYMBOL(dcb_getrewr); 2124 2125 /* Add rewrite entry to the rewrite list. */ 2126 int dcb_setrewr(struct net_device *dev, struct dcb_app *new) 2127 { 2128 int err; 2129 2130 spin_lock_bh(&dcb_lock); 2131 /* Search for existing match and abort if found. */ 2132 if (dcb_rewr_lookup(new, dev->ifindex, new->protocol)) { 2133 err = -EEXIST; 2134 goto out; 2135 } 2136 2137 err = dcb_app_add(&dcb_rewr_list, new, dev->ifindex); 2138 out: 2139 spin_unlock_bh(&dcb_lock); 2140 2141 return err; 2142 } 2143 EXPORT_SYMBOL(dcb_setrewr); 2144 2145 /* Delete rewrite entry from the rewrite list. */ 2146 int dcb_delrewr(struct net_device *dev, struct dcb_app *del) 2147 { 2148 struct dcb_app_type *itr; 2149 int err = -ENOENT; 2150 2151 spin_lock_bh(&dcb_lock); 2152 /* Search for existing match and remove it. */ 2153 itr = dcb_rewr_lookup(del, dev->ifindex, del->protocol); 2154 if (itr) { 2155 list_del(&itr->list); 2156 kfree(itr); 2157 err = 0; 2158 } 2159 2160 spin_unlock_bh(&dcb_lock); 2161 2162 return err; 2163 } 2164 EXPORT_SYMBOL(dcb_delrewr); 2165 2166 /** 2167 * dcb_ieee_setapp - add IEEE dcb application data to app list 2168 * @dev: network interface 2169 * @new: application data to add 2170 * 2171 * This adds Application data to the list. Multiple application 2172 * entries may exists for the same selector and protocol as long 2173 * as the priorities are different. Priority is expected to be a 2174 * 3-bit unsigned integer 2175 */ 2176 int dcb_ieee_setapp(struct net_device *dev, struct dcb_app *new) 2177 { 2178 struct dcb_app_type event; 2179 int err = 0; 2180 2181 event.ifindex = dev->ifindex; 2182 memcpy(&event.app, new, sizeof(event.app)); 2183 if (dev->dcbnl_ops->getdcbx) 2184 event.dcbx = dev->dcbnl_ops->getdcbx(dev); 2185 2186 spin_lock_bh(&dcb_lock); 2187 /* Search for existing match and abort if found */ 2188 if (dcb_app_lookup(new, dev->ifindex, new->priority)) { 2189 err = -EEXIST; 2190 goto out; 2191 } 2192 2193 err = dcb_app_add(&dcb_app_list, new, dev->ifindex); 2194 out: 2195 spin_unlock_bh(&dcb_lock); 2196 if (!err) 2197 call_dcbevent_notifiers(DCB_APP_EVENT, &event); 2198 return err; 2199 } 2200 EXPORT_SYMBOL(dcb_ieee_setapp); 2201 2202 /** 2203 * dcb_ieee_delapp - delete IEEE dcb application data from list 2204 * @dev: network interface 2205 * @del: application data to delete 2206 * 2207 * This removes a matching APP data from the APP list 2208 */ 2209 int dcb_ieee_delapp(struct net_device *dev, struct dcb_app *del) 2210 { 2211 struct dcb_app_type *itr; 2212 struct dcb_app_type event; 2213 int err = -ENOENT; 2214 2215 event.ifindex = dev->ifindex; 2216 memcpy(&event.app, del, sizeof(event.app)); 2217 if (dev->dcbnl_ops->getdcbx) 2218 event.dcbx = dev->dcbnl_ops->getdcbx(dev); 2219 2220 spin_lock_bh(&dcb_lock); 2221 /* Search for existing match and remove it. */ 2222 if ((itr = dcb_app_lookup(del, dev->ifindex, del->priority))) { 2223 list_del(&itr->list); 2224 kfree(itr); 2225 err = 0; 2226 } 2227 2228 spin_unlock_bh(&dcb_lock); 2229 if (!err) 2230 call_dcbevent_notifiers(DCB_APP_EVENT, &event); 2231 return err; 2232 } 2233 EXPORT_SYMBOL(dcb_ieee_delapp); 2234 2235 /* dcb_getrewr_prio_pcp_mask_map - For a given device, find mapping from 2236 * priorities to the PCP and DEI values assigned to that priority. 2237 */ 2238 void dcb_getrewr_prio_pcp_mask_map(const struct net_device *dev, 2239 struct dcb_rewr_prio_pcp_map *p_map) 2240 { 2241 int ifindex = dev->ifindex; 2242 struct dcb_app_type *itr; 2243 u8 prio; 2244 2245 memset(p_map->map, 0, sizeof(p_map->map)); 2246 2247 spin_lock_bh(&dcb_lock); 2248 list_for_each_entry(itr, &dcb_rewr_list, list) { 2249 if (itr->ifindex == ifindex && 2250 itr->app.selector == DCB_APP_SEL_PCP && 2251 itr->app.protocol < 16 && 2252 itr->app.priority < IEEE_8021QAZ_MAX_TCS) { 2253 prio = itr->app.priority; 2254 p_map->map[prio] |= 1 << itr->app.protocol; 2255 } 2256 } 2257 spin_unlock_bh(&dcb_lock); 2258 } 2259 EXPORT_SYMBOL(dcb_getrewr_prio_pcp_mask_map); 2260 2261 /* dcb_getrewr_prio_dscp_mask_map - For a given device, find mapping from 2262 * priorities to the DSCP values assigned to that priority. 2263 */ 2264 void dcb_getrewr_prio_dscp_mask_map(const struct net_device *dev, 2265 struct dcb_ieee_app_prio_map *p_map) 2266 { 2267 int ifindex = dev->ifindex; 2268 struct dcb_app_type *itr; 2269 u8 prio; 2270 2271 memset(p_map->map, 0, sizeof(p_map->map)); 2272 2273 spin_lock_bh(&dcb_lock); 2274 list_for_each_entry(itr, &dcb_rewr_list, list) { 2275 if (itr->ifindex == ifindex && 2276 itr->app.selector == IEEE_8021QAZ_APP_SEL_DSCP && 2277 itr->app.protocol < 64 && 2278 itr->app.priority < IEEE_8021QAZ_MAX_TCS) { 2279 prio = itr->app.priority; 2280 p_map->map[prio] |= 1ULL << itr->app.protocol; 2281 } 2282 } 2283 spin_unlock_bh(&dcb_lock); 2284 } 2285 EXPORT_SYMBOL(dcb_getrewr_prio_dscp_mask_map); 2286 2287 /* 2288 * dcb_ieee_getapp_prio_dscp_mask_map - For a given device, find mapping from 2289 * priorities to the DSCP values assigned to that priority. Initialize p_map 2290 * such that each map element holds a bit mask of DSCP values configured for 2291 * that priority by APP entries. 2292 */ 2293 void dcb_ieee_getapp_prio_dscp_mask_map(const struct net_device *dev, 2294 struct dcb_ieee_app_prio_map *p_map) 2295 { 2296 int ifindex = dev->ifindex; 2297 struct dcb_app_type *itr; 2298 u8 prio; 2299 2300 memset(p_map->map, 0, sizeof(p_map->map)); 2301 2302 spin_lock_bh(&dcb_lock); 2303 list_for_each_entry(itr, &dcb_app_list, list) { 2304 if (itr->ifindex == ifindex && 2305 itr->app.selector == IEEE_8021QAZ_APP_SEL_DSCP && 2306 itr->app.protocol < 64 && 2307 itr->app.priority < IEEE_8021QAZ_MAX_TCS) { 2308 prio = itr->app.priority; 2309 p_map->map[prio] |= 1ULL << itr->app.protocol; 2310 } 2311 } 2312 spin_unlock_bh(&dcb_lock); 2313 } 2314 EXPORT_SYMBOL(dcb_ieee_getapp_prio_dscp_mask_map); 2315 2316 /* 2317 * dcb_ieee_getapp_dscp_prio_mask_map - For a given device, find mapping from 2318 * DSCP values to the priorities assigned to that DSCP value. Initialize p_map 2319 * such that each map element holds a bit mask of priorities configured for a 2320 * given DSCP value by APP entries. 2321 */ 2322 void 2323 dcb_ieee_getapp_dscp_prio_mask_map(const struct net_device *dev, 2324 struct dcb_ieee_app_dscp_map *p_map) 2325 { 2326 int ifindex = dev->ifindex; 2327 struct dcb_app_type *itr; 2328 2329 memset(p_map->map, 0, sizeof(p_map->map)); 2330 2331 spin_lock_bh(&dcb_lock); 2332 list_for_each_entry(itr, &dcb_app_list, list) { 2333 if (itr->ifindex == ifindex && 2334 itr->app.selector == IEEE_8021QAZ_APP_SEL_DSCP && 2335 itr->app.protocol < 64 && 2336 itr->app.priority < IEEE_8021QAZ_MAX_TCS) 2337 p_map->map[itr->app.protocol] |= 1 << itr->app.priority; 2338 } 2339 spin_unlock_bh(&dcb_lock); 2340 } 2341 EXPORT_SYMBOL(dcb_ieee_getapp_dscp_prio_mask_map); 2342 2343 /* 2344 * Per 802.1Q-2014, the selector value of 1 is used for matching on Ethernet 2345 * type, with valid PID values >= 1536. A special meaning is then assigned to 2346 * protocol value of 0: "default priority. For use when priority is not 2347 * otherwise specified". 2348 * 2349 * dcb_ieee_getapp_default_prio_mask - For a given device, find all APP entries 2350 * of the form {$PRIO, ETHERTYPE, 0} and construct a bit mask of all default 2351 * priorities set by these entries. 2352 */ 2353 u8 dcb_ieee_getapp_default_prio_mask(const struct net_device *dev) 2354 { 2355 int ifindex = dev->ifindex; 2356 struct dcb_app_type *itr; 2357 u8 mask = 0; 2358 2359 spin_lock_bh(&dcb_lock); 2360 list_for_each_entry(itr, &dcb_app_list, list) { 2361 if (itr->ifindex == ifindex && 2362 itr->app.selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE && 2363 itr->app.protocol == 0 && 2364 itr->app.priority < IEEE_8021QAZ_MAX_TCS) 2365 mask |= 1 << itr->app.priority; 2366 } 2367 spin_unlock_bh(&dcb_lock); 2368 2369 return mask; 2370 } 2371 EXPORT_SYMBOL(dcb_ieee_getapp_default_prio_mask); 2372 2373 static void dcbnl_flush_dev(struct net_device *dev) 2374 { 2375 struct dcb_app_type *itr, *tmp; 2376 2377 spin_lock_bh(&dcb_lock); 2378 2379 list_for_each_entry_safe(itr, tmp, &dcb_app_list, list) { 2380 if (itr->ifindex == dev->ifindex) { 2381 list_del(&itr->list); 2382 kfree(itr); 2383 } 2384 } 2385 2386 spin_unlock_bh(&dcb_lock); 2387 } 2388 2389 static int dcbnl_netdevice_event(struct notifier_block *nb, 2390 unsigned long event, void *ptr) 2391 { 2392 struct net_device *dev = netdev_notifier_info_to_dev(ptr); 2393 2394 switch (event) { 2395 case NETDEV_UNREGISTER: 2396 if (!dev->dcbnl_ops) 2397 return NOTIFY_DONE; 2398 2399 dcbnl_flush_dev(dev); 2400 2401 return NOTIFY_OK; 2402 default: 2403 return NOTIFY_DONE; 2404 } 2405 } 2406 2407 static struct notifier_block dcbnl_nb __read_mostly = { 2408 .notifier_call = dcbnl_netdevice_event, 2409 }; 2410 2411 static int __init dcbnl_init(void) 2412 { 2413 int err; 2414 2415 err = register_netdevice_notifier(&dcbnl_nb); 2416 if (err) 2417 return err; 2418 2419 rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL, 0); 2420 rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL, 0); 2421 2422 return 0; 2423 } 2424 device_initcall(dcbnl_init); 2425
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.