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