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 /* Data Center Bridging (DCB) is a collection of Ethernet enhancements 32 * intended to allow network traffic with differing requirements 33 * (highly reliable, no drops vs. best effort vs. low latency) to operate 34 * and co-exist on Ethernet. Current DCB features are: 35 * 36 * Enhanced Transmission Selection (aka Priority Grouping [PG]) - provides a 37 * framework for assigning bandwidth guarantees to traffic classes. 38 * 39 * Priority-based Flow Control (PFC) - provides a flow control mechanism which 40 * can work independently for each 802.1p priority. 41 * 42 * Congestion Notification - provides a mechanism for end-to-end congestion 43 * control for protocols which do not have built-in congestion management. 44 * 45 * More information about the emerging standards for these Ethernet features 46 * can be found at: http://www.ieee802.org/1/pages/dcbridges.html 47 * 48 * This file implements an rtnetlink interface to allow configuration of DCB 49 * features for capable devices. 50 */ 51 52 MODULE_AUTHOR("Lucy Liu, <lucy.liu@intel.com>"); 53 MODULE_DESCRIPTION("Data Center Bridging netlink interface"); 54 MODULE_LICENSE("GPL"); 55 56 /**************** DCB attribute policies *************************************/ 57 58 /* DCB netlink attributes policy */ 59 static const struct nla_policy dcbnl_rtnl_policy[DCB_ATTR_MAX + 1] = { 60 [DCB_ATTR_IFNAME] = {.type = NLA_NUL_STRING, .len = IFNAMSIZ - 1}, 61 [DCB_ATTR_STATE] = {.type = NLA_U8}, 62 [DCB_ATTR_PFC_CFG] = {.type = NLA_NESTED}, 63 [DCB_ATTR_PG_CFG] = {.type = NLA_NESTED}, 64 [DCB_ATTR_SET_ALL] = {.type = NLA_U8}, 65 [DCB_ATTR_PERM_HWADDR] = {.type = NLA_FLAG}, 66 [DCB_ATTR_CAP] = {.type = NLA_NESTED}, 67 [DCB_ATTR_PFC_STATE] = {.type = NLA_U8}, 68 [DCB_ATTR_BCN] = {.type = NLA_NESTED}, 69 [DCB_ATTR_APP] = {.type = NLA_NESTED}, 70 [DCB_ATTR_IEEE] = {.type = NLA_NESTED}, 71 [DCB_ATTR_DCBX] = {.type = NLA_U8}, 72 [DCB_ATTR_FEATCFG] = {.type = NLA_NESTED}, 73 }; 74 75 /* DCB priority flow control to User Priority nested attributes */ 76 static const struct nla_policy dcbnl_pfc_up_nest[DCB_PFC_UP_ATTR_MAX + 1] = { 77 [DCB_PFC_UP_ATTR_0] = {.type = NLA_U8}, 78 [DCB_PFC_UP_ATTR_1] = {.type = NLA_U8}, 79 [DCB_PFC_UP_ATTR_2] = {.type = NLA_U8}, 80 [DCB_PFC_UP_ATTR_3] = {.type = NLA_U8}, 81 [DCB_PFC_UP_ATTR_4] = {.type = NLA_U8}, 82 [DCB_PFC_UP_ATTR_5] = {.type = NLA_U8}, 83 [DCB_PFC_UP_ATTR_6] = {.type = NLA_U8}, 84 [DCB_PFC_UP_ATTR_7] = {.type = NLA_U8}, 85 [DCB_PFC_UP_ATTR_ALL] = {.type = NLA_FLAG}, 86 }; 87 88 /* DCB priority grouping nested attributes */ 89 static const struct nla_policy dcbnl_pg_nest[DCB_PG_ATTR_MAX + 1] = { 90 [DCB_PG_ATTR_TC_0] = {.type = NLA_NESTED}, 91 [DCB_PG_ATTR_TC_1] = {.type = NLA_NESTED}, 92 [DCB_PG_ATTR_TC_2] = {.type = NLA_NESTED}, 93 [DCB_PG_ATTR_TC_3] = {.type = NLA_NESTED}, 94 [DCB_PG_ATTR_TC_4] = {.type = NLA_NESTED}, 95 [DCB_PG_ATTR_TC_5] = {.type = NLA_NESTED}, 96 [DCB_PG_ATTR_TC_6] = {.type = NLA_NESTED}, 97 [DCB_PG_ATTR_TC_7] = {.type = NLA_NESTED}, 98 [DCB_PG_ATTR_TC_ALL] = {.type = NLA_NESTED}, 99 [DCB_PG_ATTR_BW_ID_0] = {.type = NLA_U8}, 100 [DCB_PG_ATTR_BW_ID_1] = {.type = NLA_U8}, 101 [DCB_PG_ATTR_BW_ID_2] = {.type = NLA_U8}, 102 [DCB_PG_ATTR_BW_ID_3] = {.type = NLA_U8}, 103 [DCB_PG_ATTR_BW_ID_4] = {.type = NLA_U8}, 104 [DCB_PG_ATTR_BW_ID_5] = {.type = NLA_U8}, 105 [DCB_PG_ATTR_BW_ID_6] = {.type = NLA_U8}, 106 [DCB_PG_ATTR_BW_ID_7] = {.type = NLA_U8}, 107 [DCB_PG_ATTR_BW_ID_ALL] = {.type = NLA_FLAG}, 108 }; 109 110 /* DCB traffic class nested attributes. */ 111 static const struct nla_policy dcbnl_tc_param_nest[DCB_TC_ATTR_PARAM_MAX + 1] = { 112 [DCB_TC_ATTR_PARAM_PGID] = {.type = NLA_U8}, 113 [DCB_TC_ATTR_PARAM_UP_MAPPING] = {.type = NLA_U8}, 114 [DCB_TC_ATTR_PARAM_STRICT_PRIO] = {.type = NLA_U8}, 115 [DCB_TC_ATTR_PARAM_BW_PCT] = {.type = NLA_U8}, 116 [DCB_TC_ATTR_PARAM_ALL] = {.type = NLA_FLAG}, 117 }; 118 119 /* DCB capabilities nested attributes. */ 120 static const struct nla_policy dcbnl_cap_nest[DCB_CAP_ATTR_MAX + 1] = { 121 [DCB_CAP_ATTR_ALL] = {.type = NLA_FLAG}, 122 [DCB_CAP_ATTR_PG] = {.type = NLA_U8}, 123 [DCB_CAP_ATTR_PFC] = {.type = NLA_U8}, 124 [DCB_CAP_ATTR_UP2TC] = {.type = NLA_U8}, 125 [DCB_CAP_ATTR_PG_TCS] = {.type = NLA_U8}, 126 [DCB_CAP_ATTR_PFC_TCS] = {.type = NLA_U8}, 127 [DCB_CAP_ATTR_GSP] = {.type = NLA_U8}, 128 [DCB_CAP_ATTR_BCN] = {.type = NLA_U8}, 129 [DCB_CAP_ATTR_DCBX] = {.type = NLA_U8}, 130 }; 131 132 /* DCB capabilities nested attributes. */ 133 static const struct nla_policy dcbnl_numtcs_nest[DCB_NUMTCS_ATTR_MAX + 1] = { 134 [DCB_NUMTCS_ATTR_ALL] = {.type = NLA_FLAG}, 135 [DCB_NUMTCS_ATTR_PG] = {.type = NLA_U8}, 136 [DCB_NUMTCS_ATTR_PFC] = {.type = NLA_U8}, 137 }; 138 139 /* DCB BCN nested attributes. */ 140 static const struct nla_policy dcbnl_bcn_nest[DCB_BCN_ATTR_MAX + 1] = { 141 [DCB_BCN_ATTR_RP_0] = {.type = NLA_U8}, 142 [DCB_BCN_ATTR_RP_1] = {.type = NLA_U8}, 143 [DCB_BCN_ATTR_RP_2] = {.type = NLA_U8}, 144 [DCB_BCN_ATTR_RP_3] = {.type = NLA_U8}, 145 [DCB_BCN_ATTR_RP_4] = {.type = NLA_U8}, 146 [DCB_BCN_ATTR_RP_5] = {.type = NLA_U8}, 147 [DCB_BCN_ATTR_RP_6] = {.type = NLA_U8}, 148 [DCB_BCN_ATTR_RP_7] = {.type = NLA_U8}, 149 [DCB_BCN_ATTR_RP_ALL] = {.type = NLA_FLAG}, 150 [DCB_BCN_ATTR_BCNA_0] = {.type = NLA_U32}, 151 [DCB_BCN_ATTR_BCNA_1] = {.type = NLA_U32}, 152 [DCB_BCN_ATTR_ALPHA] = {.type = NLA_U32}, 153 [DCB_BCN_ATTR_BETA] = {.type = NLA_U32}, 154 [DCB_BCN_ATTR_GD] = {.type = NLA_U32}, 155 [DCB_BCN_ATTR_GI] = {.type = NLA_U32}, 156 [DCB_BCN_ATTR_TMAX] = {.type = NLA_U32}, 157 [DCB_BCN_ATTR_TD] = {.type = NLA_U32}, 158 [DCB_BCN_ATTR_RMIN] = {.type = NLA_U32}, 159 [DCB_BCN_ATTR_W] = {.type = NLA_U32}, 160 [DCB_BCN_ATTR_RD] = {.type = NLA_U32}, 161 [DCB_BCN_ATTR_RU] = {.type = NLA_U32}, 162 [DCB_BCN_ATTR_WRTT] = {.type = NLA_U32}, 163 [DCB_BCN_ATTR_RI] = {.type = NLA_U32}, 164 [DCB_BCN_ATTR_C] = {.type = NLA_U32}, 165 [DCB_BCN_ATTR_ALL] = {.type = NLA_FLAG}, 166 }; 167 168 /* DCB APP nested attributes. */ 169 static const struct nla_policy dcbnl_app_nest[DCB_APP_ATTR_MAX + 1] = { 170 [DCB_APP_ATTR_IDTYPE] = {.type = NLA_U8}, 171 [DCB_APP_ATTR_ID] = {.type = NLA_U16}, 172 [DCB_APP_ATTR_PRIORITY] = {.type = NLA_U8}, 173 }; 174 175 /* IEEE 802.1Qaz nested attributes. */ 176 static const struct nla_policy dcbnl_ieee_policy[DCB_ATTR_IEEE_MAX + 1] = { 177 [DCB_ATTR_IEEE_ETS] = {.len = sizeof(struct ieee_ets)}, 178 [DCB_ATTR_IEEE_PFC] = {.len = sizeof(struct ieee_pfc)}, 179 [DCB_ATTR_IEEE_APP_TABLE] = {.type = NLA_NESTED}, 180 [DCB_ATTR_IEEE_MAXRATE] = {.len = sizeof(struct ieee_maxrate)}, 181 }; 182 183 static const struct nla_policy dcbnl_ieee_app[DCB_ATTR_IEEE_APP_MAX + 1] = { 184 [DCB_ATTR_IEEE_APP] = {.len = sizeof(struct dcb_app)}, 185 }; 186 187 /* DCB number of traffic classes nested attributes. */ 188 static const struct nla_policy dcbnl_featcfg_nest[DCB_FEATCFG_ATTR_MAX + 1] = { 189 [DCB_FEATCFG_ATTR_ALL] = {.type = NLA_FLAG}, 190 [DCB_FEATCFG_ATTR_PG] = {.type = NLA_U8}, 191 [DCB_FEATCFG_ATTR_PFC] = {.type = NLA_U8}, 192 [DCB_FEATCFG_ATTR_APP] = {.type = NLA_U8}, 193 }; 194 195 static LIST_HEAD(dcb_app_list); 196 static DEFINE_SPINLOCK(dcb_lock); 197 198 static struct sk_buff *dcbnl_newmsg(int type, u8 cmd, u32 port, u32 seq, 199 u32 flags, struct nlmsghdr **nlhp) 200 { 201 struct sk_buff *skb; 202 struct dcbmsg *dcb; 203 struct nlmsghdr *nlh; 204 205 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 206 if (!skb) 207 return NULL; 208 209 nlh = nlmsg_put(skb, port, seq, type, sizeof(*dcb), flags); 210 BUG_ON(!nlh); 211 212 dcb = nlmsg_data(nlh); 213 dcb->dcb_family = AF_UNSPEC; 214 dcb->cmd = cmd; 215 dcb->dcb_pad = 0; 216 217 if (nlhp) 218 *nlhp = nlh; 219 220 return skb; 221 } 222 223 static int dcbnl_getstate(struct net_device *netdev, struct nlmsghdr *nlh, 224 u32 seq, struct nlattr **tb, struct sk_buff *skb) 225 { 226 /* if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->getstate) */ 227 if (!netdev->dcbnl_ops->getstate) 228 return -EOPNOTSUPP; 229 230 return nla_put_u8(skb, DCB_ATTR_STATE, 231 netdev->dcbnl_ops->getstate(netdev)); 232 } 233 234 static int dcbnl_getpfccfg(struct net_device *netdev, struct nlmsghdr *nlh, 235 u32 seq, struct nlattr **tb, struct sk_buff *skb) 236 { 237 struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1], *nest; 238 u8 value; 239 int ret; 240 int i; 241 int getall = 0; 242 243 if (!tb[DCB_ATTR_PFC_CFG]) 244 return -EINVAL; 245 246 if (!netdev->dcbnl_ops->getpfccfg) 247 return -EOPNOTSUPP; 248 249 ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX, 250 tb[DCB_ATTR_PFC_CFG], 251 dcbnl_pfc_up_nest); 252 if (ret) 253 return ret; 254 255 nest = nla_nest_start(skb, DCB_ATTR_PFC_CFG); 256 if (!nest) 257 return -EMSGSIZE; 258 259 if (data[DCB_PFC_UP_ATTR_ALL]) 260 getall = 1; 261 262 for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) { 263 if (!getall && !data[i]) 264 continue; 265 266 netdev->dcbnl_ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0, 267 &value); 268 ret = nla_put_u8(skb, i, value); 269 if (ret) { 270 nla_nest_cancel(skb, nest); 271 return ret; 272 } 273 } 274 nla_nest_end(skb, nest); 275 276 return 0; 277 } 278 279 static int dcbnl_getperm_hwaddr(struct net_device *netdev, struct nlmsghdr *nlh, 280 u32 seq, struct nlattr **tb, struct sk_buff *skb) 281 { 282 u8 perm_addr[MAX_ADDR_LEN]; 283 284 if (!netdev->dcbnl_ops->getpermhwaddr) 285 return -EOPNOTSUPP; 286 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 err = ops->ieee_getets(netdev, &ets); 1046 if (!err && 1047 nla_put(skb, DCB_ATTR_IEEE_ETS, sizeof(ets), &ets)) 1048 return -EMSGSIZE; 1049 } 1050 1051 if (ops->ieee_getmaxrate) { 1052 struct ieee_maxrate maxrate; 1053 err = ops->ieee_getmaxrate(netdev, &maxrate); 1054 if (!err) { 1055 err = nla_put(skb, DCB_ATTR_IEEE_MAXRATE, 1056 sizeof(maxrate), &maxrate); 1057 if (err) 1058 return -EMSGSIZE; 1059 } 1060 } 1061 1062 if (ops->ieee_getpfc) { 1063 struct ieee_pfc pfc; 1064 err = ops->ieee_getpfc(netdev, &pfc); 1065 if (!err && 1066 nla_put(skb, DCB_ATTR_IEEE_PFC, sizeof(pfc), &pfc)) 1067 return -EMSGSIZE; 1068 } 1069 1070 app = nla_nest_start(skb, DCB_ATTR_IEEE_APP_TABLE); 1071 if (!app) 1072 return -EMSGSIZE; 1073 1074 spin_lock(&dcb_lock); 1075 list_for_each_entry(itr, &dcb_app_list, list) { 1076 if (itr->ifindex == netdev->ifindex) { 1077 err = nla_put(skb, DCB_ATTR_IEEE_APP, sizeof(itr->app), 1078 &itr->app); 1079 if (err) { 1080 spin_unlock(&dcb_lock); 1081 return -EMSGSIZE; 1082 } 1083 } 1084 } 1085 1086 if (netdev->dcbnl_ops->getdcbx) 1087 dcbx = netdev->dcbnl_ops->getdcbx(netdev); 1088 else 1089 dcbx = -EOPNOTSUPP; 1090 1091 spin_unlock(&dcb_lock); 1092 nla_nest_end(skb, app); 1093 1094 /* get peer info if available */ 1095 if (ops->ieee_peer_getets) { 1096 struct ieee_ets ets; 1097 err = ops->ieee_peer_getets(netdev, &ets); 1098 if (!err && 1099 nla_put(skb, DCB_ATTR_IEEE_PEER_ETS, sizeof(ets), &ets)) 1100 return -EMSGSIZE; 1101 } 1102 1103 if (ops->ieee_peer_getpfc) { 1104 struct ieee_pfc pfc; 1105 err = ops->ieee_peer_getpfc(netdev, &pfc); 1106 if (!err && 1107 nla_put(skb, DCB_ATTR_IEEE_PEER_PFC, sizeof(pfc), &pfc)) 1108 return -EMSGSIZE; 1109 } 1110 1111 if (ops->peer_getappinfo && ops->peer_getapptable) { 1112 err = dcbnl_build_peer_app(netdev, skb, 1113 DCB_ATTR_IEEE_PEER_APP, 1114 DCB_ATTR_IEEE_APP_UNSPEC, 1115 DCB_ATTR_IEEE_APP); 1116 if (err) 1117 return -EMSGSIZE; 1118 } 1119 1120 nla_nest_end(skb, ieee); 1121 if (dcbx >= 0) { 1122 err = nla_put_u8(skb, DCB_ATTR_DCBX, dcbx); 1123 if (err) 1124 return -EMSGSIZE; 1125 } 1126 1127 return 0; 1128 } 1129 1130 static int dcbnl_cee_pg_fill(struct sk_buff *skb, struct net_device *dev, 1131 int dir) 1132 { 1133 u8 pgid, up_map, prio, tc_pct; 1134 const struct dcbnl_rtnl_ops *ops = dev->dcbnl_ops; 1135 int i = dir ? DCB_ATTR_CEE_TX_PG : DCB_ATTR_CEE_RX_PG; 1136 struct nlattr *pg = nla_nest_start(skb, i); 1137 1138 if (!pg) 1139 return -EMSGSIZE; 1140 1141 for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) { 1142 struct nlattr *tc_nest = nla_nest_start(skb, i); 1143 1144 if (!tc_nest) 1145 return -EMSGSIZE; 1146 1147 pgid = DCB_ATTR_VALUE_UNDEFINED; 1148 prio = DCB_ATTR_VALUE_UNDEFINED; 1149 tc_pct = DCB_ATTR_VALUE_UNDEFINED; 1150 up_map = DCB_ATTR_VALUE_UNDEFINED; 1151 1152 if (!dir) 1153 ops->getpgtccfgrx(dev, i - DCB_PG_ATTR_TC_0, 1154 &prio, &pgid, &tc_pct, &up_map); 1155 else 1156 ops->getpgtccfgtx(dev, i - DCB_PG_ATTR_TC_0, 1157 &prio, &pgid, &tc_pct, &up_map); 1158 1159 if (nla_put_u8(skb, DCB_TC_ATTR_PARAM_PGID, pgid) || 1160 nla_put_u8(skb, DCB_TC_ATTR_PARAM_UP_MAPPING, up_map) || 1161 nla_put_u8(skb, DCB_TC_ATTR_PARAM_STRICT_PRIO, prio) || 1162 nla_put_u8(skb, DCB_TC_ATTR_PARAM_BW_PCT, tc_pct)) 1163 return -EMSGSIZE; 1164 nla_nest_end(skb, tc_nest); 1165 } 1166 1167 for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) { 1168 tc_pct = DCB_ATTR_VALUE_UNDEFINED; 1169 1170 if (!dir) 1171 ops->getpgbwgcfgrx(dev, i - DCB_PG_ATTR_BW_ID_0, 1172 &tc_pct); 1173 else 1174 ops->getpgbwgcfgtx(dev, i - DCB_PG_ATTR_BW_ID_0, 1175 &tc_pct); 1176 if (nla_put_u8(skb, i, tc_pct)) 1177 return -EMSGSIZE; 1178 } 1179 nla_nest_end(skb, pg); 1180 return 0; 1181 } 1182 1183 static int dcbnl_cee_fill(struct sk_buff *skb, struct net_device *netdev) 1184 { 1185 struct nlattr *cee, *app; 1186 struct dcb_app_type *itr; 1187 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1188 int dcbx, i, err = -EMSGSIZE; 1189 u8 value; 1190 1191 if (nla_put_string(skb, DCB_ATTR_IFNAME, netdev->name)) 1192 goto nla_put_failure; 1193 cee = nla_nest_start(skb, DCB_ATTR_CEE); 1194 if (!cee) 1195 goto nla_put_failure; 1196 1197 /* local pg */ 1198 if (ops->getpgtccfgtx && ops->getpgbwgcfgtx) { 1199 err = dcbnl_cee_pg_fill(skb, netdev, 1); 1200 if (err) 1201 goto nla_put_failure; 1202 } 1203 1204 if (ops->getpgtccfgrx && ops->getpgbwgcfgrx) { 1205 err = dcbnl_cee_pg_fill(skb, netdev, 0); 1206 if (err) 1207 goto nla_put_failure; 1208 } 1209 1210 /* local pfc */ 1211 if (ops->getpfccfg) { 1212 struct nlattr *pfc_nest = nla_nest_start(skb, DCB_ATTR_CEE_PFC); 1213 1214 if (!pfc_nest) 1215 goto nla_put_failure; 1216 1217 for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) { 1218 ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0, &value); 1219 if (nla_put_u8(skb, i, value)) 1220 goto nla_put_failure; 1221 } 1222 nla_nest_end(skb, pfc_nest); 1223 } 1224 1225 /* local app */ 1226 spin_lock(&dcb_lock); 1227 app = nla_nest_start(skb, DCB_ATTR_CEE_APP_TABLE); 1228 if (!app) 1229 goto dcb_unlock; 1230 1231 list_for_each_entry(itr, &dcb_app_list, list) { 1232 if (itr->ifindex == netdev->ifindex) { 1233 struct nlattr *app_nest = nla_nest_start(skb, 1234 DCB_ATTR_APP); 1235 if (!app_nest) 1236 goto dcb_unlock; 1237 1238 err = nla_put_u8(skb, DCB_APP_ATTR_IDTYPE, 1239 itr->app.selector); 1240 if (err) 1241 goto dcb_unlock; 1242 1243 err = nla_put_u16(skb, DCB_APP_ATTR_ID, 1244 itr->app.protocol); 1245 if (err) 1246 goto dcb_unlock; 1247 1248 err = nla_put_u8(skb, DCB_APP_ATTR_PRIORITY, 1249 itr->app.priority); 1250 if (err) 1251 goto dcb_unlock; 1252 1253 nla_nest_end(skb, app_nest); 1254 } 1255 } 1256 nla_nest_end(skb, app); 1257 1258 if (netdev->dcbnl_ops->getdcbx) 1259 dcbx = netdev->dcbnl_ops->getdcbx(netdev); 1260 else 1261 dcbx = -EOPNOTSUPP; 1262 1263 spin_unlock(&dcb_lock); 1264 1265 /* features flags */ 1266 if (ops->getfeatcfg) { 1267 struct nlattr *feat = nla_nest_start(skb, DCB_ATTR_CEE_FEAT); 1268 if (!feat) 1269 goto nla_put_failure; 1270 1271 for (i = DCB_FEATCFG_ATTR_ALL + 1; i <= DCB_FEATCFG_ATTR_MAX; 1272 i++) 1273 if (!ops->getfeatcfg(netdev, i, &value) && 1274 nla_put_u8(skb, i, value)) 1275 goto nla_put_failure; 1276 1277 nla_nest_end(skb, feat); 1278 } 1279 1280 /* peer info if available */ 1281 if (ops->cee_peer_getpg) { 1282 struct cee_pg pg; 1283 err = ops->cee_peer_getpg(netdev, &pg); 1284 if (!err && 1285 nla_put(skb, DCB_ATTR_CEE_PEER_PG, sizeof(pg), &pg)) 1286 goto nla_put_failure; 1287 } 1288 1289 if (ops->cee_peer_getpfc) { 1290 struct cee_pfc pfc; 1291 err = ops->cee_peer_getpfc(netdev, &pfc); 1292 if (!err && 1293 nla_put(skb, DCB_ATTR_CEE_PEER_PFC, sizeof(pfc), &pfc)) 1294 goto nla_put_failure; 1295 } 1296 1297 if (ops->peer_getappinfo && ops->peer_getapptable) { 1298 err = dcbnl_build_peer_app(netdev, skb, 1299 DCB_ATTR_CEE_PEER_APP_TABLE, 1300 DCB_ATTR_CEE_PEER_APP_INFO, 1301 DCB_ATTR_CEE_PEER_APP); 1302 if (err) 1303 goto nla_put_failure; 1304 } 1305 nla_nest_end(skb, cee); 1306 1307 /* DCBX state */ 1308 if (dcbx >= 0) { 1309 err = nla_put_u8(skb, DCB_ATTR_DCBX, dcbx); 1310 if (err) 1311 goto nla_put_failure; 1312 } 1313 return 0; 1314 1315 dcb_unlock: 1316 spin_unlock(&dcb_lock); 1317 nla_put_failure: 1318 return err; 1319 } 1320 1321 static int dcbnl_notify(struct net_device *dev, int event, int cmd, 1322 u32 seq, u32 portid, int dcbx_ver) 1323 { 1324 struct net *net = dev_net(dev); 1325 struct sk_buff *skb; 1326 struct nlmsghdr *nlh; 1327 const struct dcbnl_rtnl_ops *ops = dev->dcbnl_ops; 1328 int err; 1329 1330 if (!ops) 1331 return -EOPNOTSUPP; 1332 1333 skb = dcbnl_newmsg(event, cmd, portid, seq, 0, &nlh); 1334 if (!skb) 1335 return -ENOBUFS; 1336 1337 if (dcbx_ver == DCB_CAP_DCBX_VER_IEEE) 1338 err = dcbnl_ieee_fill(skb, dev); 1339 else 1340 err = dcbnl_cee_fill(skb, dev); 1341 1342 if (err < 0) { 1343 /* Report error to broadcast listeners */ 1344 nlmsg_free(skb); 1345 rtnl_set_sk_err(net, RTNLGRP_DCB, err); 1346 } else { 1347 /* End nlmsg and notify broadcast listeners */ 1348 nlmsg_end(skb, nlh); 1349 rtnl_notify(skb, net, 0, RTNLGRP_DCB, NULL, GFP_KERNEL); 1350 } 1351 1352 return err; 1353 } 1354 1355 int dcbnl_ieee_notify(struct net_device *dev, int event, int cmd, 1356 u32 seq, u32 portid) 1357 { 1358 return dcbnl_notify(dev, event, cmd, seq, portid, DCB_CAP_DCBX_VER_IEEE); 1359 } 1360 EXPORT_SYMBOL(dcbnl_ieee_notify); 1361 1362 int dcbnl_cee_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_CEE); 1366 } 1367 EXPORT_SYMBOL(dcbnl_cee_notify); 1368 1369 /* Handle IEEE 802.1Qaz SET commands. If any requested operation can not 1370 * be completed the entire msg is aborted and error value is returned. 1371 * No attempt is made to reconcile the case where only part of the 1372 * cmd can be completed. 1373 */ 1374 static int dcbnl_ieee_set(struct net_device *netdev, struct nlmsghdr *nlh, 1375 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1376 { 1377 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1378 struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1]; 1379 int err; 1380 1381 if (!ops) 1382 return -EOPNOTSUPP; 1383 1384 if (!tb[DCB_ATTR_IEEE]) 1385 return -EINVAL; 1386 1387 err = nla_parse_nested(ieee, DCB_ATTR_IEEE_MAX, 1388 tb[DCB_ATTR_IEEE], dcbnl_ieee_policy); 1389 if (err) 1390 return err; 1391 1392 if (ieee[DCB_ATTR_IEEE_ETS] && ops->ieee_setets) { 1393 struct ieee_ets *ets = nla_data(ieee[DCB_ATTR_IEEE_ETS]); 1394 err = ops->ieee_setets(netdev, ets); 1395 if (err) 1396 goto err; 1397 } 1398 1399 if (ieee[DCB_ATTR_IEEE_MAXRATE] && ops->ieee_setmaxrate) { 1400 struct ieee_maxrate *maxrate = 1401 nla_data(ieee[DCB_ATTR_IEEE_MAXRATE]); 1402 err = ops->ieee_setmaxrate(netdev, maxrate); 1403 if (err) 1404 goto err; 1405 } 1406 1407 if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setpfc) { 1408 struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]); 1409 err = ops->ieee_setpfc(netdev, pfc); 1410 if (err) 1411 goto err; 1412 } 1413 1414 if (ieee[DCB_ATTR_IEEE_APP_TABLE]) { 1415 struct nlattr *attr; 1416 int rem; 1417 1418 nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) { 1419 struct dcb_app *app_data; 1420 if (nla_type(attr) != DCB_ATTR_IEEE_APP) 1421 continue; 1422 app_data = nla_data(attr); 1423 if (ops->ieee_setapp) 1424 err = ops->ieee_setapp(netdev, app_data); 1425 else 1426 err = dcb_ieee_setapp(netdev, app_data); 1427 if (err) 1428 goto err; 1429 } 1430 } 1431 1432 err: 1433 err = nla_put_u8(skb, DCB_ATTR_IEEE, err); 1434 dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_SET, seq, 0); 1435 return err; 1436 } 1437 1438 static int dcbnl_ieee_get(struct net_device *netdev, struct nlmsghdr *nlh, 1439 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1440 { 1441 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1442 1443 if (!ops) 1444 return -EOPNOTSUPP; 1445 1446 return dcbnl_ieee_fill(skb, netdev); 1447 } 1448 1449 static int dcbnl_ieee_del(struct net_device *netdev, struct nlmsghdr *nlh, 1450 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1451 { 1452 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1453 struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1]; 1454 int err; 1455 1456 if (!ops) 1457 return -EOPNOTSUPP; 1458 1459 if (!tb[DCB_ATTR_IEEE]) 1460 return -EINVAL; 1461 1462 err = nla_parse_nested(ieee, DCB_ATTR_IEEE_MAX, 1463 tb[DCB_ATTR_IEEE], dcbnl_ieee_policy); 1464 if (err) 1465 return err; 1466 1467 if (ieee[DCB_ATTR_IEEE_APP_TABLE]) { 1468 struct nlattr *attr; 1469 int rem; 1470 1471 nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) { 1472 struct dcb_app *app_data; 1473 1474 if (nla_type(attr) != DCB_ATTR_IEEE_APP) 1475 continue; 1476 app_data = nla_data(attr); 1477 if (ops->ieee_delapp) 1478 err = ops->ieee_delapp(netdev, app_data); 1479 else 1480 err = dcb_ieee_delapp(netdev, app_data); 1481 if (err) 1482 goto err; 1483 } 1484 } 1485 1486 err: 1487 err = nla_put_u8(skb, DCB_ATTR_IEEE, err); 1488 dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_DEL, seq, 0); 1489 return err; 1490 } 1491 1492 1493 /* DCBX configuration */ 1494 static int dcbnl_getdcbx(struct net_device *netdev, struct nlmsghdr *nlh, 1495 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1496 { 1497 if (!netdev->dcbnl_ops->getdcbx) 1498 return -EOPNOTSUPP; 1499 1500 return nla_put_u8(skb, DCB_ATTR_DCBX, 1501 netdev->dcbnl_ops->getdcbx(netdev)); 1502 } 1503 1504 static int dcbnl_setdcbx(struct net_device *netdev, struct nlmsghdr *nlh, 1505 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1506 { 1507 u8 value; 1508 1509 if (!netdev->dcbnl_ops->setdcbx) 1510 return -EOPNOTSUPP; 1511 1512 if (!tb[DCB_ATTR_DCBX]) 1513 return -EINVAL; 1514 1515 value = nla_get_u8(tb[DCB_ATTR_DCBX]); 1516 1517 return nla_put_u8(skb, DCB_ATTR_DCBX, 1518 netdev->dcbnl_ops->setdcbx(netdev, value)); 1519 } 1520 1521 static int dcbnl_getfeatcfg(struct net_device *netdev, struct nlmsghdr *nlh, 1522 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1523 { 1524 struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1], *nest; 1525 u8 value; 1526 int ret, i; 1527 int getall = 0; 1528 1529 if (!netdev->dcbnl_ops->getfeatcfg) 1530 return -EOPNOTSUPP; 1531 1532 if (!tb[DCB_ATTR_FEATCFG]) 1533 return -EINVAL; 1534 1535 ret = nla_parse_nested(data, DCB_FEATCFG_ATTR_MAX, tb[DCB_ATTR_FEATCFG], 1536 dcbnl_featcfg_nest); 1537 if (ret) 1538 return ret; 1539 1540 nest = nla_nest_start(skb, DCB_ATTR_FEATCFG); 1541 if (!nest) 1542 return -EMSGSIZE; 1543 1544 if (data[DCB_FEATCFG_ATTR_ALL]) 1545 getall = 1; 1546 1547 for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) { 1548 if (!getall && !data[i]) 1549 continue; 1550 1551 ret = netdev->dcbnl_ops->getfeatcfg(netdev, i, &value); 1552 if (!ret) 1553 ret = nla_put_u8(skb, i, value); 1554 1555 if (ret) { 1556 nla_nest_cancel(skb, nest); 1557 goto nla_put_failure; 1558 } 1559 } 1560 nla_nest_end(skb, nest); 1561 1562 nla_put_failure: 1563 return ret; 1564 } 1565 1566 static int dcbnl_setfeatcfg(struct net_device *netdev, struct nlmsghdr *nlh, 1567 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1568 { 1569 struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1]; 1570 int ret, i; 1571 u8 value; 1572 1573 if (!netdev->dcbnl_ops->setfeatcfg) 1574 return -ENOTSUPP; 1575 1576 if (!tb[DCB_ATTR_FEATCFG]) 1577 return -EINVAL; 1578 1579 ret = nla_parse_nested(data, DCB_FEATCFG_ATTR_MAX, tb[DCB_ATTR_FEATCFG], 1580 dcbnl_featcfg_nest); 1581 1582 if (ret) 1583 goto err; 1584 1585 for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) { 1586 if (data[i] == NULL) 1587 continue; 1588 1589 value = nla_get_u8(data[i]); 1590 1591 ret = netdev->dcbnl_ops->setfeatcfg(netdev, i, value); 1592 1593 if (ret) 1594 goto err; 1595 } 1596 err: 1597 ret = nla_put_u8(skb, DCB_ATTR_FEATCFG, ret); 1598 1599 return ret; 1600 } 1601 1602 /* Handle CEE DCBX GET commands. */ 1603 static int dcbnl_cee_get(struct net_device *netdev, struct nlmsghdr *nlh, 1604 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1605 { 1606 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1607 1608 if (!ops) 1609 return -EOPNOTSUPP; 1610 1611 return dcbnl_cee_fill(skb, netdev); 1612 } 1613 1614 struct reply_func { 1615 /* reply netlink message type */ 1616 int type; 1617 1618 /* function to fill message contents */ 1619 int (*cb)(struct net_device *, struct nlmsghdr *, u32, 1620 struct nlattr **, struct sk_buff *); 1621 }; 1622 1623 static const struct reply_func reply_funcs[DCB_CMD_MAX+1] = { 1624 [DCB_CMD_GSTATE] = { RTM_GETDCB, dcbnl_getstate }, 1625 [DCB_CMD_SSTATE] = { RTM_SETDCB, dcbnl_setstate }, 1626 [DCB_CMD_PFC_GCFG] = { RTM_GETDCB, dcbnl_getpfccfg }, 1627 [DCB_CMD_PFC_SCFG] = { RTM_SETDCB, dcbnl_setpfccfg }, 1628 [DCB_CMD_GPERM_HWADDR] = { RTM_GETDCB, dcbnl_getperm_hwaddr }, 1629 [DCB_CMD_GCAP] = { RTM_GETDCB, dcbnl_getcap }, 1630 [DCB_CMD_GNUMTCS] = { RTM_GETDCB, dcbnl_getnumtcs }, 1631 [DCB_CMD_SNUMTCS] = { RTM_SETDCB, dcbnl_setnumtcs }, 1632 [DCB_CMD_PFC_GSTATE] = { RTM_GETDCB, dcbnl_getpfcstate }, 1633 [DCB_CMD_PFC_SSTATE] = { RTM_SETDCB, dcbnl_setpfcstate }, 1634 [DCB_CMD_GAPP] = { RTM_GETDCB, dcbnl_getapp }, 1635 [DCB_CMD_SAPP] = { RTM_SETDCB, dcbnl_setapp }, 1636 [DCB_CMD_PGTX_GCFG] = { RTM_GETDCB, dcbnl_pgtx_getcfg }, 1637 [DCB_CMD_PGTX_SCFG] = { RTM_SETDCB, dcbnl_pgtx_setcfg }, 1638 [DCB_CMD_PGRX_GCFG] = { RTM_GETDCB, dcbnl_pgrx_getcfg }, 1639 [DCB_CMD_PGRX_SCFG] = { RTM_SETDCB, dcbnl_pgrx_setcfg }, 1640 [DCB_CMD_SET_ALL] = { RTM_SETDCB, dcbnl_setall }, 1641 [DCB_CMD_BCN_GCFG] = { RTM_GETDCB, dcbnl_bcn_getcfg }, 1642 [DCB_CMD_BCN_SCFG] = { RTM_SETDCB, dcbnl_bcn_setcfg }, 1643 [DCB_CMD_IEEE_GET] = { RTM_GETDCB, dcbnl_ieee_get }, 1644 [DCB_CMD_IEEE_SET] = { RTM_SETDCB, dcbnl_ieee_set }, 1645 [DCB_CMD_IEEE_DEL] = { RTM_SETDCB, dcbnl_ieee_del }, 1646 [DCB_CMD_GDCBX] = { RTM_GETDCB, dcbnl_getdcbx }, 1647 [DCB_CMD_SDCBX] = { RTM_SETDCB, dcbnl_setdcbx }, 1648 [DCB_CMD_GFEATCFG] = { RTM_GETDCB, dcbnl_getfeatcfg }, 1649 [DCB_CMD_SFEATCFG] = { RTM_SETDCB, dcbnl_setfeatcfg }, 1650 [DCB_CMD_CEE_GET] = { RTM_GETDCB, dcbnl_cee_get }, 1651 }; 1652 1653 static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) 1654 { 1655 struct net *net = sock_net(skb->sk); 1656 struct net_device *netdev; 1657 struct dcbmsg *dcb = nlmsg_data(nlh); 1658 struct nlattr *tb[DCB_ATTR_MAX + 1]; 1659 u32 portid = skb ? NETLINK_CB(skb).portid : 0; 1660 int ret = -EINVAL; 1661 struct sk_buff *reply_skb; 1662 struct nlmsghdr *reply_nlh = NULL; 1663 const struct reply_func *fn; 1664 1665 if ((nlh->nlmsg_type == RTM_SETDCB) && !capable(CAP_NET_ADMIN)) 1666 return -EPERM; 1667 1668 ret = nlmsg_parse(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX, 1669 dcbnl_rtnl_policy); 1670 if (ret < 0) 1671 return ret; 1672 1673 if (dcb->cmd > DCB_CMD_MAX) 1674 return -EINVAL; 1675 1676 /* check if a reply function has been defined for the command */ 1677 fn = &reply_funcs[dcb->cmd]; 1678 if (!fn->cb) 1679 return -EOPNOTSUPP; 1680 1681 if (!tb[DCB_ATTR_IFNAME]) 1682 return -EINVAL; 1683 1684 netdev = dev_get_by_name(net, nla_data(tb[DCB_ATTR_IFNAME])); 1685 if (!netdev) 1686 return -ENODEV; 1687 1688 if (!netdev->dcbnl_ops) { 1689 ret = -EOPNOTSUPP; 1690 goto out; 1691 } 1692 1693 reply_skb = dcbnl_newmsg(fn->type, dcb->cmd, portid, nlh->nlmsg_seq, 1694 nlh->nlmsg_flags, &reply_nlh); 1695 if (!reply_skb) { 1696 ret = -ENOBUFS; 1697 goto out; 1698 } 1699 1700 ret = fn->cb(netdev, nlh, nlh->nlmsg_seq, tb, reply_skb); 1701 if (ret < 0) { 1702 nlmsg_free(reply_skb); 1703 goto out; 1704 } 1705 1706 nlmsg_end(reply_skb, reply_nlh); 1707 1708 ret = rtnl_unicast(reply_skb, net, portid); 1709 out: 1710 dev_put(netdev); 1711 return ret; 1712 } 1713 1714 static struct dcb_app_type *dcb_app_lookup(const struct dcb_app *app, 1715 int ifindex, int prio) 1716 { 1717 struct dcb_app_type *itr; 1718 1719 list_for_each_entry(itr, &dcb_app_list, list) { 1720 if (itr->app.selector == app->selector && 1721 itr->app.protocol == app->protocol && 1722 itr->ifindex == ifindex && 1723 (!prio || itr->app.priority == prio)) 1724 return itr; 1725 } 1726 1727 return NULL; 1728 } 1729 1730 static int dcb_app_add(const struct dcb_app *app, int ifindex) 1731 { 1732 struct dcb_app_type *entry; 1733 1734 entry = kmalloc(sizeof(*entry), GFP_ATOMIC); 1735 if (!entry) 1736 return -ENOMEM; 1737 1738 memcpy(&entry->app, app, sizeof(*app)); 1739 entry->ifindex = ifindex; 1740 list_add(&entry->list, &dcb_app_list); 1741 1742 return 0; 1743 } 1744 1745 /** 1746 * dcb_getapp - retrieve the DCBX application user priority 1747 * 1748 * On success returns a non-zero 802.1p user priority bitmap 1749 * otherwise returns 0 as the invalid user priority bitmap to 1750 * indicate an error. 1751 */ 1752 u8 dcb_getapp(struct net_device *dev, struct dcb_app *app) 1753 { 1754 struct dcb_app_type *itr; 1755 u8 prio = 0; 1756 1757 spin_lock(&dcb_lock); 1758 if ((itr = dcb_app_lookup(app, dev->ifindex, 0))) 1759 prio = itr->app.priority; 1760 spin_unlock(&dcb_lock); 1761 1762 return prio; 1763 } 1764 EXPORT_SYMBOL(dcb_getapp); 1765 1766 /** 1767 * dcb_setapp - add CEE dcb application data to app list 1768 * 1769 * Priority 0 is an invalid priority in CEE spec. This routine 1770 * removes applications from the app list if the priority is 1771 * set to zero. 1772 */ 1773 int dcb_setapp(struct net_device *dev, struct dcb_app *new) 1774 { 1775 struct dcb_app_type *itr; 1776 struct dcb_app_type event; 1777 int err = 0; 1778 1779 event.ifindex = dev->ifindex; 1780 memcpy(&event.app, new, sizeof(event.app)); 1781 if (dev->dcbnl_ops->getdcbx) 1782 event.dcbx = dev->dcbnl_ops->getdcbx(dev); 1783 1784 spin_lock(&dcb_lock); 1785 /* Search for existing match and replace */ 1786 if ((itr = dcb_app_lookup(new, dev->ifindex, 0))) { 1787 if (new->priority) 1788 itr->app.priority = new->priority; 1789 else { 1790 list_del(&itr->list); 1791 kfree(itr); 1792 } 1793 goto out; 1794 } 1795 /* App type does not exist add new application type */ 1796 if (new->priority) 1797 err = dcb_app_add(new, dev->ifindex); 1798 out: 1799 spin_unlock(&dcb_lock); 1800 if (!err) 1801 call_dcbevent_notifiers(DCB_APP_EVENT, &event); 1802 return err; 1803 } 1804 EXPORT_SYMBOL(dcb_setapp); 1805 1806 /** 1807 * dcb_ieee_getapp_mask - retrieve the IEEE DCB application priority 1808 * 1809 * Helper routine which on success returns a non-zero 802.1Qaz user 1810 * priority bitmap otherwise returns 0 to indicate the dcb_app was 1811 * not found in APP list. 1812 */ 1813 u8 dcb_ieee_getapp_mask(struct net_device *dev, struct dcb_app *app) 1814 { 1815 struct dcb_app_type *itr; 1816 u8 prio = 0; 1817 1818 spin_lock(&dcb_lock); 1819 if ((itr = dcb_app_lookup(app, dev->ifindex, 0))) 1820 prio |= 1 << itr->app.priority; 1821 spin_unlock(&dcb_lock); 1822 1823 return prio; 1824 } 1825 EXPORT_SYMBOL(dcb_ieee_getapp_mask); 1826 1827 /** 1828 * dcb_ieee_setapp - add IEEE dcb application data to app list 1829 * 1830 * This adds Application data to the list. Multiple application 1831 * entries may exists for the same selector and protocol as long 1832 * as the priorities are different. 1833 */ 1834 int dcb_ieee_setapp(struct net_device *dev, struct dcb_app *new) 1835 { 1836 struct dcb_app_type event; 1837 int err = 0; 1838 1839 event.ifindex = dev->ifindex; 1840 memcpy(&event.app, new, sizeof(event.app)); 1841 if (dev->dcbnl_ops->getdcbx) 1842 event.dcbx = dev->dcbnl_ops->getdcbx(dev); 1843 1844 spin_lock(&dcb_lock); 1845 /* Search for existing match and abort if found */ 1846 if (dcb_app_lookup(new, dev->ifindex, new->priority)) { 1847 err = -EEXIST; 1848 goto out; 1849 } 1850 1851 err = dcb_app_add(new, dev->ifindex); 1852 out: 1853 spin_unlock(&dcb_lock); 1854 if (!err) 1855 call_dcbevent_notifiers(DCB_APP_EVENT, &event); 1856 return err; 1857 } 1858 EXPORT_SYMBOL(dcb_ieee_setapp); 1859 1860 /** 1861 * dcb_ieee_delapp - delete IEEE dcb application data from list 1862 * 1863 * This removes a matching APP data from the APP list 1864 */ 1865 int dcb_ieee_delapp(struct net_device *dev, struct dcb_app *del) 1866 { 1867 struct dcb_app_type *itr; 1868 struct dcb_app_type event; 1869 int err = -ENOENT; 1870 1871 event.ifindex = dev->ifindex; 1872 memcpy(&event.app, del, sizeof(event.app)); 1873 if (dev->dcbnl_ops->getdcbx) 1874 event.dcbx = dev->dcbnl_ops->getdcbx(dev); 1875 1876 spin_lock(&dcb_lock); 1877 /* Search for existing match and remove it. */ 1878 if ((itr = dcb_app_lookup(del, dev->ifindex, del->priority))) { 1879 list_del(&itr->list); 1880 kfree(itr); 1881 err = 0; 1882 } 1883 1884 spin_unlock(&dcb_lock); 1885 if (!err) 1886 call_dcbevent_notifiers(DCB_APP_EVENT, &event); 1887 return err; 1888 } 1889 EXPORT_SYMBOL(dcb_ieee_delapp); 1890 1891 static void dcb_flushapp(void) 1892 { 1893 struct dcb_app_type *app; 1894 struct dcb_app_type *tmp; 1895 1896 spin_lock(&dcb_lock); 1897 list_for_each_entry_safe(app, tmp, &dcb_app_list, list) { 1898 list_del(&app->list); 1899 kfree(app); 1900 } 1901 spin_unlock(&dcb_lock); 1902 } 1903 1904 static int __init dcbnl_init(void) 1905 { 1906 INIT_LIST_HEAD(&dcb_app_list); 1907 1908 rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL, NULL); 1909 rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL, NULL); 1910 1911 return 0; 1912 } 1913 module_init(dcbnl_init); 1914 1915 static void __exit dcbnl_exit(void) 1916 { 1917 rtnl_unregister(PF_UNSPEC, RTM_GETDCB); 1918 rtnl_unregister(PF_UNSPEC, RTM_SETDCB); 1919 dcb_flushapp(); 1920 } 1921 module_exit(dcbnl_exit); 1922