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