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 err = -EMSGSIZE; 1357 return err; 1358 } 1359 1360 static int dcbnl_notify(struct net_device *dev, int event, int cmd, 1361 u32 seq, u32 portid, int dcbx_ver) 1362 { 1363 struct net *net = dev_net(dev); 1364 struct sk_buff *skb; 1365 struct nlmsghdr *nlh; 1366 const struct dcbnl_rtnl_ops *ops = dev->dcbnl_ops; 1367 int err; 1368 1369 if (!ops) 1370 return -EOPNOTSUPP; 1371 1372 skb = dcbnl_newmsg(event, cmd, portid, seq, 0, &nlh); 1373 if (!skb) 1374 return -ENOBUFS; 1375 1376 if (dcbx_ver == DCB_CAP_DCBX_VER_IEEE) 1377 err = dcbnl_ieee_fill(skb, dev); 1378 else 1379 err = dcbnl_cee_fill(skb, dev); 1380 1381 if (err < 0) { 1382 /* Report error to broadcast listeners */ 1383 nlmsg_free(skb); 1384 rtnl_set_sk_err(net, RTNLGRP_DCB, err); 1385 } else { 1386 /* End nlmsg and notify broadcast listeners */ 1387 nlmsg_end(skb, nlh); 1388 rtnl_notify(skb, net, 0, RTNLGRP_DCB, NULL, GFP_KERNEL); 1389 } 1390 1391 return err; 1392 } 1393 1394 int dcbnl_ieee_notify(struct net_device *dev, int event, int cmd, 1395 u32 seq, u32 portid) 1396 { 1397 return dcbnl_notify(dev, event, cmd, seq, portid, DCB_CAP_DCBX_VER_IEEE); 1398 } 1399 EXPORT_SYMBOL(dcbnl_ieee_notify); 1400 1401 int dcbnl_cee_notify(struct net_device *dev, int event, int cmd, 1402 u32 seq, u32 portid) 1403 { 1404 return dcbnl_notify(dev, event, cmd, seq, portid, DCB_CAP_DCBX_VER_CEE); 1405 } 1406 EXPORT_SYMBOL(dcbnl_cee_notify); 1407 1408 /* Handle IEEE 802.1Qaz/802.1Qau/802.1Qbb SET commands. 1409 * If any requested operation can not be completed 1410 * the entire msg is aborted and error value is returned. 1411 * No attempt is made to reconcile the case where only part of the 1412 * cmd can be completed. 1413 */ 1414 static int dcbnl_ieee_set(struct net_device *netdev, struct nlmsghdr *nlh, 1415 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1416 { 1417 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1418 struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1]; 1419 int err; 1420 1421 if (!ops) 1422 return -EOPNOTSUPP; 1423 1424 if (!tb[DCB_ATTR_IEEE]) 1425 return -EINVAL; 1426 1427 err = nla_parse_nested(ieee, DCB_ATTR_IEEE_MAX, 1428 tb[DCB_ATTR_IEEE], dcbnl_ieee_policy); 1429 if (err) 1430 return err; 1431 1432 if (ieee[DCB_ATTR_IEEE_ETS] && ops->ieee_setets) { 1433 struct ieee_ets *ets = nla_data(ieee[DCB_ATTR_IEEE_ETS]); 1434 err = ops->ieee_setets(netdev, ets); 1435 if (err) 1436 goto err; 1437 } 1438 1439 if (ieee[DCB_ATTR_IEEE_MAXRATE] && ops->ieee_setmaxrate) { 1440 struct ieee_maxrate *maxrate = 1441 nla_data(ieee[DCB_ATTR_IEEE_MAXRATE]); 1442 err = ops->ieee_setmaxrate(netdev, maxrate); 1443 if (err) 1444 goto err; 1445 } 1446 1447 if (ieee[DCB_ATTR_IEEE_QCN] && ops->ieee_setqcn) { 1448 struct ieee_qcn *qcn = 1449 nla_data(ieee[DCB_ATTR_IEEE_QCN]); 1450 1451 err = ops->ieee_setqcn(netdev, qcn); 1452 if (err) 1453 goto err; 1454 } 1455 1456 if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setpfc) { 1457 struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]); 1458 err = ops->ieee_setpfc(netdev, pfc); 1459 if (err) 1460 goto err; 1461 } 1462 1463 if (ieee[DCB_ATTR_IEEE_APP_TABLE]) { 1464 struct nlattr *attr; 1465 int rem; 1466 1467 nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) { 1468 struct dcb_app *app_data; 1469 if (nla_type(attr) != DCB_ATTR_IEEE_APP) 1470 continue; 1471 app_data = nla_data(attr); 1472 if (ops->ieee_setapp) 1473 err = ops->ieee_setapp(netdev, app_data); 1474 else 1475 err = dcb_ieee_setapp(netdev, app_data); 1476 if (err) 1477 goto err; 1478 } 1479 } 1480 1481 err: 1482 err = nla_put_u8(skb, DCB_ATTR_IEEE, err); 1483 dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_SET, seq, 0); 1484 return err; 1485 } 1486 1487 static int dcbnl_ieee_get(struct net_device *netdev, struct nlmsghdr *nlh, 1488 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1489 { 1490 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1491 1492 if (!ops) 1493 return -EOPNOTSUPP; 1494 1495 return dcbnl_ieee_fill(skb, netdev); 1496 } 1497 1498 static int dcbnl_ieee_del(struct net_device *netdev, struct nlmsghdr *nlh, 1499 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1500 { 1501 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1502 struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1]; 1503 int err; 1504 1505 if (!ops) 1506 return -EOPNOTSUPP; 1507 1508 if (!tb[DCB_ATTR_IEEE]) 1509 return -EINVAL; 1510 1511 err = nla_parse_nested(ieee, DCB_ATTR_IEEE_MAX, 1512 tb[DCB_ATTR_IEEE], dcbnl_ieee_policy); 1513 if (err) 1514 return err; 1515 1516 if (ieee[DCB_ATTR_IEEE_APP_TABLE]) { 1517 struct nlattr *attr; 1518 int rem; 1519 1520 nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) { 1521 struct dcb_app *app_data; 1522 1523 if (nla_type(attr) != DCB_ATTR_IEEE_APP) 1524 continue; 1525 app_data = nla_data(attr); 1526 if (ops->ieee_delapp) 1527 err = ops->ieee_delapp(netdev, app_data); 1528 else 1529 err = dcb_ieee_delapp(netdev, app_data); 1530 if (err) 1531 goto err; 1532 } 1533 } 1534 1535 err: 1536 err = nla_put_u8(skb, DCB_ATTR_IEEE, err); 1537 dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_DEL, seq, 0); 1538 return err; 1539 } 1540 1541 1542 /* DCBX configuration */ 1543 static int dcbnl_getdcbx(struct net_device *netdev, struct nlmsghdr *nlh, 1544 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1545 { 1546 if (!netdev->dcbnl_ops->getdcbx) 1547 return -EOPNOTSUPP; 1548 1549 return nla_put_u8(skb, DCB_ATTR_DCBX, 1550 netdev->dcbnl_ops->getdcbx(netdev)); 1551 } 1552 1553 static int dcbnl_setdcbx(struct net_device *netdev, struct nlmsghdr *nlh, 1554 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1555 { 1556 u8 value; 1557 1558 if (!netdev->dcbnl_ops->setdcbx) 1559 return -EOPNOTSUPP; 1560 1561 if (!tb[DCB_ATTR_DCBX]) 1562 return -EINVAL; 1563 1564 value = nla_get_u8(tb[DCB_ATTR_DCBX]); 1565 1566 return nla_put_u8(skb, DCB_ATTR_DCBX, 1567 netdev->dcbnl_ops->setdcbx(netdev, value)); 1568 } 1569 1570 static int dcbnl_getfeatcfg(struct net_device *netdev, struct nlmsghdr *nlh, 1571 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1572 { 1573 struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1], *nest; 1574 u8 value; 1575 int ret, i; 1576 int getall = 0; 1577 1578 if (!netdev->dcbnl_ops->getfeatcfg) 1579 return -EOPNOTSUPP; 1580 1581 if (!tb[DCB_ATTR_FEATCFG]) 1582 return -EINVAL; 1583 1584 ret = nla_parse_nested(data, DCB_FEATCFG_ATTR_MAX, tb[DCB_ATTR_FEATCFG], 1585 dcbnl_featcfg_nest); 1586 if (ret) 1587 return ret; 1588 1589 nest = nla_nest_start(skb, DCB_ATTR_FEATCFG); 1590 if (!nest) 1591 return -EMSGSIZE; 1592 1593 if (data[DCB_FEATCFG_ATTR_ALL]) 1594 getall = 1; 1595 1596 for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) { 1597 if (!getall && !data[i]) 1598 continue; 1599 1600 ret = netdev->dcbnl_ops->getfeatcfg(netdev, i, &value); 1601 if (!ret) 1602 ret = nla_put_u8(skb, i, value); 1603 1604 if (ret) { 1605 nla_nest_cancel(skb, nest); 1606 goto nla_put_failure; 1607 } 1608 } 1609 nla_nest_end(skb, nest); 1610 1611 nla_put_failure: 1612 return ret; 1613 } 1614 1615 static int dcbnl_setfeatcfg(struct net_device *netdev, struct nlmsghdr *nlh, 1616 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1617 { 1618 struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1]; 1619 int ret, i; 1620 u8 value; 1621 1622 if (!netdev->dcbnl_ops->setfeatcfg) 1623 return -ENOTSUPP; 1624 1625 if (!tb[DCB_ATTR_FEATCFG]) 1626 return -EINVAL; 1627 1628 ret = nla_parse_nested(data, DCB_FEATCFG_ATTR_MAX, tb[DCB_ATTR_FEATCFG], 1629 dcbnl_featcfg_nest); 1630 1631 if (ret) 1632 goto err; 1633 1634 for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) { 1635 if (data[i] == NULL) 1636 continue; 1637 1638 value = nla_get_u8(data[i]); 1639 1640 ret = netdev->dcbnl_ops->setfeatcfg(netdev, i, value); 1641 1642 if (ret) 1643 goto err; 1644 } 1645 err: 1646 ret = nla_put_u8(skb, DCB_ATTR_FEATCFG, ret); 1647 1648 return ret; 1649 } 1650 1651 /* Handle CEE DCBX GET commands. */ 1652 static int dcbnl_cee_get(struct net_device *netdev, struct nlmsghdr *nlh, 1653 u32 seq, struct nlattr **tb, struct sk_buff *skb) 1654 { 1655 const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops; 1656 1657 if (!ops) 1658 return -EOPNOTSUPP; 1659 1660 return dcbnl_cee_fill(skb, netdev); 1661 } 1662 1663 struct reply_func { 1664 /* reply netlink message type */ 1665 int type; 1666 1667 /* function to fill message contents */ 1668 int (*cb)(struct net_device *, struct nlmsghdr *, u32, 1669 struct nlattr **, struct sk_buff *); 1670 }; 1671 1672 static const struct reply_func reply_funcs[DCB_CMD_MAX+1] = { 1673 [DCB_CMD_GSTATE] = { RTM_GETDCB, dcbnl_getstate }, 1674 [DCB_CMD_SSTATE] = { RTM_SETDCB, dcbnl_setstate }, 1675 [DCB_CMD_PFC_GCFG] = { RTM_GETDCB, dcbnl_getpfccfg }, 1676 [DCB_CMD_PFC_SCFG] = { RTM_SETDCB, dcbnl_setpfccfg }, 1677 [DCB_CMD_GPERM_HWADDR] = { RTM_GETDCB, dcbnl_getperm_hwaddr }, 1678 [DCB_CMD_GCAP] = { RTM_GETDCB, dcbnl_getcap }, 1679 [DCB_CMD_GNUMTCS] = { RTM_GETDCB, dcbnl_getnumtcs }, 1680 [DCB_CMD_SNUMTCS] = { RTM_SETDCB, dcbnl_setnumtcs }, 1681 [DCB_CMD_PFC_GSTATE] = { RTM_GETDCB, dcbnl_getpfcstate }, 1682 [DCB_CMD_PFC_SSTATE] = { RTM_SETDCB, dcbnl_setpfcstate }, 1683 [DCB_CMD_GAPP] = { RTM_GETDCB, dcbnl_getapp }, 1684 [DCB_CMD_SAPP] = { RTM_SETDCB, dcbnl_setapp }, 1685 [DCB_CMD_PGTX_GCFG] = { RTM_GETDCB, dcbnl_pgtx_getcfg }, 1686 [DCB_CMD_PGTX_SCFG] = { RTM_SETDCB, dcbnl_pgtx_setcfg }, 1687 [DCB_CMD_PGRX_GCFG] = { RTM_GETDCB, dcbnl_pgrx_getcfg }, 1688 [DCB_CMD_PGRX_SCFG] = { RTM_SETDCB, dcbnl_pgrx_setcfg }, 1689 [DCB_CMD_SET_ALL] = { RTM_SETDCB, dcbnl_setall }, 1690 [DCB_CMD_BCN_GCFG] = { RTM_GETDCB, dcbnl_bcn_getcfg }, 1691 [DCB_CMD_BCN_SCFG] = { RTM_SETDCB, dcbnl_bcn_setcfg }, 1692 [DCB_CMD_IEEE_GET] = { RTM_GETDCB, dcbnl_ieee_get }, 1693 [DCB_CMD_IEEE_SET] = { RTM_SETDCB, dcbnl_ieee_set }, 1694 [DCB_CMD_IEEE_DEL] = { RTM_SETDCB, dcbnl_ieee_del }, 1695 [DCB_CMD_GDCBX] = { RTM_GETDCB, dcbnl_getdcbx }, 1696 [DCB_CMD_SDCBX] = { RTM_SETDCB, dcbnl_setdcbx }, 1697 [DCB_CMD_GFEATCFG] = { RTM_GETDCB, dcbnl_getfeatcfg }, 1698 [DCB_CMD_SFEATCFG] = { RTM_SETDCB, dcbnl_setfeatcfg }, 1699 [DCB_CMD_CEE_GET] = { RTM_GETDCB, dcbnl_cee_get }, 1700 }; 1701 1702 static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh) 1703 { 1704 struct net *net = sock_net(skb->sk); 1705 struct net_device *netdev; 1706 struct dcbmsg *dcb = nlmsg_data(nlh); 1707 struct nlattr *tb[DCB_ATTR_MAX + 1]; 1708 u32 portid = skb ? NETLINK_CB(skb).portid : 0; 1709 int ret = -EINVAL; 1710 struct sk_buff *reply_skb; 1711 struct nlmsghdr *reply_nlh = NULL; 1712 const struct reply_func *fn; 1713 1714 if ((nlh->nlmsg_type == RTM_SETDCB) && !netlink_capable(skb, CAP_NET_ADMIN)) 1715 return -EPERM; 1716 1717 ret = nlmsg_parse(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX, 1718 dcbnl_rtnl_policy); 1719 if (ret < 0) 1720 return ret; 1721 1722 if (dcb->cmd > DCB_CMD_MAX) 1723 return -EINVAL; 1724 1725 /* check if a reply function has been defined for the command */ 1726 fn = &reply_funcs[dcb->cmd]; 1727 if (!fn->cb) 1728 return -EOPNOTSUPP; 1729 1730 if (!tb[DCB_ATTR_IFNAME]) 1731 return -EINVAL; 1732 1733 netdev = __dev_get_by_name(net, nla_data(tb[DCB_ATTR_IFNAME])); 1734 if (!netdev) 1735 return -ENODEV; 1736 1737 if (!netdev->dcbnl_ops) 1738 return -EOPNOTSUPP; 1739 1740 reply_skb = dcbnl_newmsg(fn->type, dcb->cmd, portid, nlh->nlmsg_seq, 1741 nlh->nlmsg_flags, &reply_nlh); 1742 if (!reply_skb) 1743 return -ENOBUFS; 1744 1745 ret = fn->cb(netdev, nlh, nlh->nlmsg_seq, tb, reply_skb); 1746 if (ret < 0) { 1747 nlmsg_free(reply_skb); 1748 goto out; 1749 } 1750 1751 nlmsg_end(reply_skb, reply_nlh); 1752 1753 ret = rtnl_unicast(reply_skb, net, portid); 1754 out: 1755 return ret; 1756 } 1757 1758 static struct dcb_app_type *dcb_app_lookup(const struct dcb_app *app, 1759 int ifindex, int prio) 1760 { 1761 struct dcb_app_type *itr; 1762 1763 list_for_each_entry(itr, &dcb_app_list, list) { 1764 if (itr->app.selector == app->selector && 1765 itr->app.protocol == app->protocol && 1766 itr->ifindex == ifindex && 1767 (!prio || itr->app.priority == prio)) 1768 return itr; 1769 } 1770 1771 return NULL; 1772 } 1773 1774 static int dcb_app_add(const struct dcb_app *app, int ifindex) 1775 { 1776 struct dcb_app_type *entry; 1777 1778 entry = kmalloc(sizeof(*entry), GFP_ATOMIC); 1779 if (!entry) 1780 return -ENOMEM; 1781 1782 memcpy(&entry->app, app, sizeof(*app)); 1783 entry->ifindex = ifindex; 1784 list_add(&entry->list, &dcb_app_list); 1785 1786 return 0; 1787 } 1788 1789 /** 1790 * dcb_getapp - retrieve the DCBX application user priority 1791 * 1792 * On success returns a non-zero 802.1p user priority bitmap 1793 * otherwise returns 0 as the invalid user priority bitmap to 1794 * indicate an error. 1795 */ 1796 u8 dcb_getapp(struct net_device *dev, struct dcb_app *app) 1797 { 1798 struct dcb_app_type *itr; 1799 u8 prio = 0; 1800 1801 spin_lock_bh(&dcb_lock); 1802 if ((itr = dcb_app_lookup(app, dev->ifindex, 0))) 1803 prio = itr->app.priority; 1804 spin_unlock_bh(&dcb_lock); 1805 1806 return prio; 1807 } 1808 EXPORT_SYMBOL(dcb_getapp); 1809 1810 /** 1811 * dcb_setapp - add CEE dcb application data to app list 1812 * 1813 * Priority 0 is an invalid priority in CEE spec. This routine 1814 * removes applications from the app list if the priority is 1815 * set to zero. Priority is expected to be 8-bit 802.1p user priority bitmap 1816 */ 1817 int dcb_setapp(struct net_device *dev, struct dcb_app *new) 1818 { 1819 struct dcb_app_type *itr; 1820 struct dcb_app_type event; 1821 int err = 0; 1822 1823 event.ifindex = dev->ifindex; 1824 memcpy(&event.app, new, sizeof(event.app)); 1825 if (dev->dcbnl_ops->getdcbx) 1826 event.dcbx = dev->dcbnl_ops->getdcbx(dev); 1827 1828 spin_lock_bh(&dcb_lock); 1829 /* Search for existing match and replace */ 1830 if ((itr = dcb_app_lookup(new, dev->ifindex, 0))) { 1831 if (new->priority) 1832 itr->app.priority = new->priority; 1833 else { 1834 list_del(&itr->list); 1835 kfree(itr); 1836 } 1837 goto out; 1838 } 1839 /* App type does not exist add new application type */ 1840 if (new->priority) 1841 err = dcb_app_add(new, dev->ifindex); 1842 out: 1843 spin_unlock_bh(&dcb_lock); 1844 if (!err) 1845 call_dcbevent_notifiers(DCB_APP_EVENT, &event); 1846 return err; 1847 } 1848 EXPORT_SYMBOL(dcb_setapp); 1849 1850 /** 1851 * dcb_ieee_getapp_mask - retrieve the IEEE DCB application priority 1852 * 1853 * Helper routine which on success returns a non-zero 802.1Qaz user 1854 * priority bitmap otherwise returns 0 to indicate the dcb_app was 1855 * not found in APP list. 1856 */ 1857 u8 dcb_ieee_getapp_mask(struct net_device *dev, struct dcb_app *app) 1858 { 1859 struct dcb_app_type *itr; 1860 u8 prio = 0; 1861 1862 spin_lock_bh(&dcb_lock); 1863 if ((itr = dcb_app_lookup(app, dev->ifindex, 0))) 1864 prio |= 1 << itr->app.priority; 1865 spin_unlock_bh(&dcb_lock); 1866 1867 return prio; 1868 } 1869 EXPORT_SYMBOL(dcb_ieee_getapp_mask); 1870 1871 /** 1872 * dcb_ieee_setapp - add IEEE dcb application data to app list 1873 * 1874 * This adds Application data to the list. Multiple application 1875 * entries may exists for the same selector and protocol as long 1876 * as the priorities are different. Priority is expected to be a 1877 * 3-bit unsigned integer 1878 */ 1879 int dcb_ieee_setapp(struct net_device *dev, struct dcb_app *new) 1880 { 1881 struct dcb_app_type event; 1882 int err = 0; 1883 1884 event.ifindex = dev->ifindex; 1885 memcpy(&event.app, new, sizeof(event.app)); 1886 if (dev->dcbnl_ops->getdcbx) 1887 event.dcbx = dev->dcbnl_ops->getdcbx(dev); 1888 1889 spin_lock_bh(&dcb_lock); 1890 /* Search for existing match and abort if found */ 1891 if (dcb_app_lookup(new, dev->ifindex, new->priority)) { 1892 err = -EEXIST; 1893 goto out; 1894 } 1895 1896 err = dcb_app_add(new, dev->ifindex); 1897 out: 1898 spin_unlock_bh(&dcb_lock); 1899 if (!err) 1900 call_dcbevent_notifiers(DCB_APP_EVENT, &event); 1901 return err; 1902 } 1903 EXPORT_SYMBOL(dcb_ieee_setapp); 1904 1905 /** 1906 * dcb_ieee_delapp - delete IEEE dcb application data from list 1907 * 1908 * This removes a matching APP data from the APP list 1909 */ 1910 int dcb_ieee_delapp(struct net_device *dev, struct dcb_app *del) 1911 { 1912 struct dcb_app_type *itr; 1913 struct dcb_app_type event; 1914 int err = -ENOENT; 1915 1916 event.ifindex = dev->ifindex; 1917 memcpy(&event.app, del, sizeof(event.app)); 1918 if (dev->dcbnl_ops->getdcbx) 1919 event.dcbx = dev->dcbnl_ops->getdcbx(dev); 1920 1921 spin_lock_bh(&dcb_lock); 1922 /* Search for existing match and remove it. */ 1923 if ((itr = dcb_app_lookup(del, dev->ifindex, del->priority))) { 1924 list_del(&itr->list); 1925 kfree(itr); 1926 err = 0; 1927 } 1928 1929 spin_unlock_bh(&dcb_lock); 1930 if (!err) 1931 call_dcbevent_notifiers(DCB_APP_EVENT, &event); 1932 return err; 1933 } 1934 EXPORT_SYMBOL(dcb_ieee_delapp); 1935 1936 static int __init dcbnl_init(void) 1937 { 1938 INIT_LIST_HEAD(&dcb_app_list); 1939 1940 rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL, NULL); 1941 rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL, NULL); 1942 1943 return 0; 1944 } 1945 device_initcall(dcbnl_init); 1946