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