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