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