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