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