diff options
Diffstat (limited to 'net/core/ethtool.c')
| -rw-r--r-- | net/core/ethtool.c | 387 |
1 files changed, 373 insertions, 14 deletions
diff --git a/net/core/ethtool.c b/net/core/ethtool.c index d8aee584e8d1..0f2f82185ec4 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c | |||
| @@ -120,7 +120,7 @@ int ethtool_op_set_ufo(struct net_device *dev, u32 data) | |||
| 120 | * NETIF_F_xxx values in include/linux/netdevice.h | 120 | * NETIF_F_xxx values in include/linux/netdevice.h |
| 121 | */ | 121 | */ |
| 122 | static const u32 flags_dup_features = | 122 | static const u32 flags_dup_features = |
| 123 | ETH_FLAG_LRO; | 123 | (ETH_FLAG_LRO | ETH_FLAG_NTUPLE); |
| 124 | 124 | ||
| 125 | u32 ethtool_op_get_flags(struct net_device *dev) | 125 | u32 ethtool_op_get_flags(struct net_device *dev) |
| 126 | { | 126 | { |
| @@ -134,19 +134,44 @@ u32 ethtool_op_get_flags(struct net_device *dev) | |||
| 134 | 134 | ||
| 135 | int ethtool_op_set_flags(struct net_device *dev, u32 data) | 135 | int ethtool_op_set_flags(struct net_device *dev, u32 data) |
| 136 | { | 136 | { |
| 137 | const struct ethtool_ops *ops = dev->ethtool_ops; | ||
| 138 | unsigned long features = dev->features; | ||
| 139 | |||
| 137 | if (data & ETH_FLAG_LRO) | 140 | if (data & ETH_FLAG_LRO) |
| 138 | dev->features |= NETIF_F_LRO; | 141 | features |= NETIF_F_LRO; |
| 139 | else | 142 | else |
| 140 | dev->features &= ~NETIF_F_LRO; | 143 | features &= ~NETIF_F_LRO; |
| 144 | |||
| 145 | if (data & ETH_FLAG_NTUPLE) { | ||
| 146 | if (!ops->set_rx_ntuple) | ||
| 147 | return -EOPNOTSUPP; | ||
| 148 | features |= NETIF_F_NTUPLE; | ||
| 149 | } else { | ||
| 150 | /* safe to clear regardless */ | ||
| 151 | features &= ~NETIF_F_NTUPLE; | ||
| 152 | } | ||
| 141 | 153 | ||
| 154 | dev->features = features; | ||
| 142 | return 0; | 155 | return 0; |
| 143 | } | 156 | } |
| 144 | 157 | ||
| 158 | void ethtool_ntuple_flush(struct net_device *dev) | ||
| 159 | { | ||
| 160 | struct ethtool_rx_ntuple_flow_spec_container *fsc, *f; | ||
| 161 | |||
| 162 | list_for_each_entry_safe(fsc, f, &dev->ethtool_ntuple_list.list, list) { | ||
| 163 | list_del(&fsc->list); | ||
| 164 | kfree(fsc); | ||
| 165 | } | ||
| 166 | dev->ethtool_ntuple_list.count = 0; | ||
| 167 | } | ||
| 168 | EXPORT_SYMBOL(ethtool_ntuple_flush); | ||
| 169 | |||
| 145 | /* Handlers for each ethtool command */ | 170 | /* Handlers for each ethtool command */ |
| 146 | 171 | ||
| 147 | static int ethtool_get_settings(struct net_device *dev, void __user *useraddr) | 172 | static int ethtool_get_settings(struct net_device *dev, void __user *useraddr) |
| 148 | { | 173 | { |
| 149 | struct ethtool_cmd cmd = { ETHTOOL_GSET }; | 174 | struct ethtool_cmd cmd = { .cmd = ETHTOOL_GSET }; |
| 150 | int err; | 175 | int err; |
| 151 | 176 | ||
| 152 | if (!dev->ethtool_ops->get_settings) | 177 | if (!dev->ethtool_ops->get_settings) |
| @@ -174,7 +199,10 @@ static int ethtool_set_settings(struct net_device *dev, void __user *useraddr) | |||
| 174 | return dev->ethtool_ops->set_settings(dev, &cmd); | 199 | return dev->ethtool_ops->set_settings(dev, &cmd); |
| 175 | } | 200 | } |
| 176 | 201 | ||
| 177 | static int ethtool_get_drvinfo(struct net_device *dev, void __user *useraddr) | 202 | /* |
| 203 | * noinline attribute so that gcc doesnt use too much stack in dev_ethtool() | ||
| 204 | */ | ||
| 205 | static noinline int ethtool_get_drvinfo(struct net_device *dev, void __user *useraddr) | ||
| 178 | { | 206 | { |
| 179 | struct ethtool_drvinfo info; | 207 | struct ethtool_drvinfo info; |
| 180 | const struct ethtool_ops *ops = dev->ethtool_ops; | 208 | const struct ethtool_ops *ops = dev->ethtool_ops; |
| @@ -209,7 +237,10 @@ static int ethtool_get_drvinfo(struct net_device *dev, void __user *useraddr) | |||
| 209 | return 0; | 237 | return 0; |
| 210 | } | 238 | } |
| 211 | 239 | ||
| 212 | static int ethtool_set_rxnfc(struct net_device *dev, void __user *useraddr) | 240 | /* |
| 241 | * noinline attribute so that gcc doesnt use too much stack in dev_ethtool() | ||
| 242 | */ | ||
| 243 | static noinline int ethtool_set_rxnfc(struct net_device *dev, void __user *useraddr) | ||
| 213 | { | 244 | { |
| 214 | struct ethtool_rxnfc cmd; | 245 | struct ethtool_rxnfc cmd; |
| 215 | 246 | ||
| @@ -222,7 +253,10 @@ static int ethtool_set_rxnfc(struct net_device *dev, void __user *useraddr) | |||
| 222 | return dev->ethtool_ops->set_rxnfc(dev, &cmd); | 253 | return dev->ethtool_ops->set_rxnfc(dev, &cmd); |
| 223 | } | 254 | } |
| 224 | 255 | ||
| 225 | static int ethtool_get_rxnfc(struct net_device *dev, void __user *useraddr) | 256 | /* |
| 257 | * noinline attribute so that gcc doesnt use too much stack in dev_ethtool() | ||
| 258 | */ | ||
| 259 | static noinline int ethtool_get_rxnfc(struct net_device *dev, void __user *useraddr) | ||
| 226 | { | 260 | { |
| 227 | struct ethtool_rxnfc info; | 261 | struct ethtool_rxnfc info; |
| 228 | const struct ethtool_ops *ops = dev->ethtool_ops; | 262 | const struct ethtool_ops *ops = dev->ethtool_ops; |
| @@ -266,6 +300,315 @@ err_out: | |||
| 266 | return ret; | 300 | return ret; |
| 267 | } | 301 | } |
| 268 | 302 | ||
| 303 | static void __rx_ntuple_filter_add(struct ethtool_rx_ntuple_list *list, | ||
| 304 | struct ethtool_rx_ntuple_flow_spec *spec, | ||
| 305 | struct ethtool_rx_ntuple_flow_spec_container *fsc) | ||
| 306 | { | ||
| 307 | |||
| 308 | /* don't add filters forever */ | ||
| 309 | if (list->count >= ETHTOOL_MAX_NTUPLE_LIST_ENTRY) { | ||
| 310 | /* free the container */ | ||
| 311 | kfree(fsc); | ||
| 312 | return; | ||
| 313 | } | ||
| 314 | |||
| 315 | /* Copy the whole filter over */ | ||
| 316 | fsc->fs.flow_type = spec->flow_type; | ||
| 317 | memcpy(&fsc->fs.h_u, &spec->h_u, sizeof(spec->h_u)); | ||
| 318 | memcpy(&fsc->fs.m_u, &spec->m_u, sizeof(spec->m_u)); | ||
| 319 | |||
| 320 | fsc->fs.vlan_tag = spec->vlan_tag; | ||
| 321 | fsc->fs.vlan_tag_mask = spec->vlan_tag_mask; | ||
| 322 | fsc->fs.data = spec->data; | ||
| 323 | fsc->fs.data_mask = spec->data_mask; | ||
| 324 | fsc->fs.action = spec->action; | ||
| 325 | |||
| 326 | /* add to the list */ | ||
| 327 | list_add_tail_rcu(&fsc->list, &list->list); | ||
| 328 | list->count++; | ||
| 329 | } | ||
| 330 | |||
| 331 | /* | ||
| 332 | * noinline attribute so that gcc doesnt use too much stack in dev_ethtool() | ||
| 333 | */ | ||
| 334 | static noinline int ethtool_set_rx_ntuple(struct net_device *dev, void __user *useraddr) | ||
| 335 | { | ||
| 336 | struct ethtool_rx_ntuple cmd; | ||
| 337 | const struct ethtool_ops *ops = dev->ethtool_ops; | ||
| 338 | struct ethtool_rx_ntuple_flow_spec_container *fsc = NULL; | ||
| 339 | int ret; | ||
| 340 | |||
| 341 | if (!(dev->features & NETIF_F_NTUPLE)) | ||
| 342 | return -EINVAL; | ||
| 343 | |||
| 344 | if (copy_from_user(&cmd, useraddr, sizeof(cmd))) | ||
| 345 | return -EFAULT; | ||
| 346 | |||
| 347 | /* | ||
| 348 | * Cache filter in dev struct for GET operation only if | ||
| 349 | * the underlying driver doesn't have its own GET operation, and | ||
| 350 | * only if the filter was added successfully. First make sure we | ||
| 351 | * can allocate the filter, then continue if successful. | ||
| 352 | */ | ||
| 353 | if (!ops->get_rx_ntuple) { | ||
| 354 | fsc = kmalloc(sizeof(*fsc), GFP_ATOMIC); | ||
| 355 | if (!fsc) | ||
| 356 | return -ENOMEM; | ||
| 357 | } | ||
| 358 | |||
| 359 | ret = ops->set_rx_ntuple(dev, &cmd); | ||
| 360 | if (ret) { | ||
| 361 | kfree(fsc); | ||
| 362 | return ret; | ||
| 363 | } | ||
| 364 | |||
| 365 | if (!ops->get_rx_ntuple) | ||
| 366 | __rx_ntuple_filter_add(&dev->ethtool_ntuple_list, &cmd.fs, fsc); | ||
| 367 | |||
| 368 | return ret; | ||
| 369 | } | ||
| 370 | |||
| 371 | static int ethtool_get_rx_ntuple(struct net_device *dev, void __user *useraddr) | ||
| 372 | { | ||
| 373 | struct ethtool_gstrings gstrings; | ||
| 374 | const struct ethtool_ops *ops = dev->ethtool_ops; | ||
| 375 | struct ethtool_rx_ntuple_flow_spec_container *fsc; | ||
| 376 | u8 *data; | ||
| 377 | char *p; | ||
| 378 | int ret, i, num_strings = 0; | ||
| 379 | |||
| 380 | if (!ops->get_sset_count) | ||
| 381 | return -EOPNOTSUPP; | ||
| 382 | |||
| 383 | if (copy_from_user(&gstrings, useraddr, sizeof(gstrings))) | ||
| 384 | return -EFAULT; | ||
| 385 | |||
| 386 | ret = ops->get_sset_count(dev, gstrings.string_set); | ||
| 387 | if (ret < 0) | ||
| 388 | return ret; | ||
| 389 | |||
| 390 | gstrings.len = ret; | ||
| 391 | |||
| 392 | data = kmalloc(gstrings.len * ETH_GSTRING_LEN, GFP_USER); | ||
| 393 | if (!data) | ||
| 394 | return -ENOMEM; | ||
| 395 | |||
| 396 | if (ops->get_rx_ntuple) { | ||
| 397 | /* driver-specific filter grab */ | ||
| 398 | ret = ops->get_rx_ntuple(dev, gstrings.string_set, data); | ||
| 399 | goto copy; | ||
| 400 | } | ||
| 401 | |||
| 402 | /* default ethtool filter grab */ | ||
| 403 | i = 0; | ||
| 404 | p = (char *)data; | ||
| 405 | list_for_each_entry(fsc, &dev->ethtool_ntuple_list.list, list) { | ||
| 406 | sprintf(p, "Filter %d:\n", i); | ||
| 407 | p += ETH_GSTRING_LEN; | ||
| 408 | num_strings++; | ||
| 409 | |||
| 410 | switch (fsc->fs.flow_type) { | ||
| 411 | case TCP_V4_FLOW: | ||
| 412 | sprintf(p, "\tFlow Type: TCP\n"); | ||
| 413 | p += ETH_GSTRING_LEN; | ||
| 414 | num_strings++; | ||
| 415 | break; | ||
| 416 | case UDP_V4_FLOW: | ||
| 417 | sprintf(p, "\tFlow Type: UDP\n"); | ||
| 418 | p += ETH_GSTRING_LEN; | ||
| 419 | num_strings++; | ||
| 420 | break; | ||
| 421 | case SCTP_V4_FLOW: | ||
| 422 | sprintf(p, "\tFlow Type: SCTP\n"); | ||
| 423 | p += ETH_GSTRING_LEN; | ||
| 424 | num_strings++; | ||
| 425 | break; | ||
| 426 | case AH_ESP_V4_FLOW: | ||
| 427 | sprintf(p, "\tFlow Type: AH ESP\n"); | ||
| 428 | p += ETH_GSTRING_LEN; | ||
| 429 | num_strings++; | ||
| 430 | break; | ||
| 431 | case ESP_V4_FLOW: | ||
| 432 | sprintf(p, "\tFlow Type: ESP\n"); | ||
| 433 | p += ETH_GSTRING_LEN; | ||
| 434 | num_strings++; | ||
| 435 | break; | ||
| 436 | case IP_USER_FLOW: | ||
| 437 | sprintf(p, "\tFlow Type: Raw IP\n"); | ||
| 438 | p += ETH_GSTRING_LEN; | ||
| 439 | num_strings++; | ||
| 440 | break; | ||
| 441 | case IPV4_FLOW: | ||
| 442 | sprintf(p, "\tFlow Type: IPv4\n"); | ||
| 443 | p += ETH_GSTRING_LEN; | ||
| 444 | num_strings++; | ||
| 445 | break; | ||
| 446 | default: | ||
| 447 | sprintf(p, "\tFlow Type: Unknown\n"); | ||
| 448 | p += ETH_GSTRING_LEN; | ||
| 449 | num_strings++; | ||
| 450 | goto unknown_filter; | ||
| 451 | }; | ||
| 452 | |||
| 453 | /* now the rest of the filters */ | ||
| 454 | switch (fsc->fs.flow_type) { | ||
| 455 | case TCP_V4_FLOW: | ||
| 456 | case UDP_V4_FLOW: | ||
| 457 | case SCTP_V4_FLOW: | ||
| 458 | sprintf(p, "\tSrc IP addr: 0x%x\n", | ||
| 459 | fsc->fs.h_u.tcp_ip4_spec.ip4src); | ||
| 460 | p += ETH_GSTRING_LEN; | ||
| 461 | num_strings++; | ||
| 462 | sprintf(p, "\tSrc IP mask: 0x%x\n", | ||
| 463 | fsc->fs.m_u.tcp_ip4_spec.ip4src); | ||
| 464 | p += ETH_GSTRING_LEN; | ||
| 465 | num_strings++; | ||
| 466 | sprintf(p, "\tDest IP addr: 0x%x\n", | ||
| 467 | fsc->fs.h_u.tcp_ip4_spec.ip4dst); | ||
| 468 | p += ETH_GSTRING_LEN; | ||
| 469 | num_strings++; | ||
| 470 | sprintf(p, "\tDest IP mask: 0x%x\n", | ||
| 471 | fsc->fs.m_u.tcp_ip4_spec.ip4dst); | ||
| 472 | p += ETH_GSTRING_LEN; | ||
| 473 | num_strings++; | ||
| 474 | sprintf(p, "\tSrc Port: %d, mask: 0x%x\n", | ||
| 475 | fsc->fs.h_u.tcp_ip4_spec.psrc, | ||
| 476 | fsc->fs.m_u.tcp_ip4_spec.psrc); | ||
| 477 | p += ETH_GSTRING_LEN; | ||
| 478 | num_strings++; | ||
| 479 | sprintf(p, "\tDest Port: %d, mask: 0x%x\n", | ||
| 480 | fsc->fs.h_u.tcp_ip4_spec.pdst, | ||
| 481 | fsc->fs.m_u.tcp_ip4_spec.pdst); | ||
| 482 | p += ETH_GSTRING_LEN; | ||
| 483 | num_strings++; | ||
| 484 | sprintf(p, "\tTOS: %d, mask: 0x%x\n", | ||
| 485 | fsc->fs.h_u.tcp_ip4_spec.tos, | ||
| 486 | fsc->fs.m_u.tcp_ip4_spec.tos); | ||
| 487 | p += ETH_GSTRING_LEN; | ||
| 488 | num_strings++; | ||
| 489 | break; | ||
| 490 | case AH_ESP_V4_FLOW: | ||
| 491 | case ESP_V4_FLOW: | ||
| 492 | sprintf(p, "\tSrc IP addr: 0x%x\n", | ||
| 493 | fsc->fs.h_u.ah_ip4_spec.ip4src); | ||
| 494 | p += ETH_GSTRING_LEN; | ||
| 495 | num_strings++; | ||
| 496 | sprintf(p, "\tSrc IP mask: 0x%x\n", | ||
| 497 | fsc->fs.m_u.ah_ip4_spec.ip4src); | ||
| 498 | p += ETH_GSTRING_LEN; | ||
| 499 | num_strings++; | ||
| 500 | sprintf(p, "\tDest IP addr: 0x%x\n", | ||
| 501 | fsc->fs.h_u.ah_ip4_spec.ip4dst); | ||
| 502 | p += ETH_GSTRING_LEN; | ||
| 503 | num_strings++; | ||
| 504 | sprintf(p, "\tDest IP mask: 0x%x\n", | ||
| 505 | fsc->fs.m_u.ah_ip4_spec.ip4dst); | ||
| 506 | p += ETH_GSTRING_LEN; | ||
| 507 | num_strings++; | ||
| 508 | sprintf(p, "\tSPI: %d, mask: 0x%x\n", | ||
| 509 | fsc->fs.h_u.ah_ip4_spec.spi, | ||
| 510 | fsc->fs.m_u.ah_ip4_spec.spi); | ||
| 511 | p += ETH_GSTRING_LEN; | ||
| 512 | num_strings++; | ||
| 513 | sprintf(p, "\tTOS: %d, mask: 0x%x\n", | ||
| 514 | fsc->fs.h_u.ah_ip4_spec.tos, | ||
| 515 | fsc->fs.m_u.ah_ip4_spec.tos); | ||
| 516 | p += ETH_GSTRING_LEN; | ||
| 517 | num_strings++; | ||
| 518 | break; | ||
| 519 | case IP_USER_FLOW: | ||
| 520 | sprintf(p, "\tSrc IP addr: 0x%x\n", | ||
| 521 | fsc->fs.h_u.raw_ip4_spec.ip4src); | ||
| 522 | p += ETH_GSTRING_LEN; | ||
| 523 | num_strings++; | ||
| 524 | sprintf(p, "\tSrc IP mask: 0x%x\n", | ||
| 525 | fsc->fs.m_u.raw_ip4_spec.ip4src); | ||
| 526 | p += ETH_GSTRING_LEN; | ||
| 527 | num_strings++; | ||
| 528 | sprintf(p, "\tDest IP addr: 0x%x\n", | ||
| 529 | fsc->fs.h_u.raw_ip4_spec.ip4dst); | ||
| 530 | p += ETH_GSTRING_LEN; | ||
| 531 | num_strings++; | ||
| 532 | sprintf(p, "\tDest IP mask: 0x%x\n", | ||
| 533 | fsc->fs.m_u.raw_ip4_spec.ip4dst); | ||
| 534 | p += ETH_GSTRING_LEN; | ||
| 535 | num_strings++; | ||
| 536 | break; | ||
| 537 | case IPV4_FLOW: | ||
| 538 | sprintf(p, "\tSrc IP addr: 0x%x\n", | ||
| 539 | fsc->fs.h_u.usr_ip4_spec.ip4src); | ||
| 540 | p += ETH_GSTRING_LEN; | ||
| 541 | num_strings++; | ||
| 542 | sprintf(p, "\tSrc IP mask: 0x%x\n", | ||
| 543 | fsc->fs.m_u.usr_ip4_spec.ip4src); | ||
| 544 | p += ETH_GSTRING_LEN; | ||
| 545 | num_strings++; | ||
| 546 | sprintf(p, "\tDest IP addr: 0x%x\n", | ||
| 547 | fsc->fs.h_u.usr_ip4_spec.ip4dst); | ||
| 548 | p += ETH_GSTRING_LEN; | ||
| 549 | num_strings++; | ||
| 550 | sprintf(p, "\tDest IP mask: 0x%x\n", | ||
| 551 | fsc->fs.m_u.usr_ip4_spec.ip4dst); | ||
| 552 | p += ETH_GSTRING_LEN; | ||
| 553 | num_strings++; | ||
| 554 | sprintf(p, "\tL4 bytes: 0x%x, mask: 0x%x\n", | ||
| 555 | fsc->fs.h_u.usr_ip4_spec.l4_4_bytes, | ||
| 556 | fsc->fs.m_u.usr_ip4_spec.l4_4_bytes); | ||
| 557 | p += ETH_GSTRING_LEN; | ||
| 558 | num_strings++; | ||
| 559 | sprintf(p, "\tTOS: %d, mask: 0x%x\n", | ||
| 560 | fsc->fs.h_u.usr_ip4_spec.tos, | ||
| 561 | fsc->fs.m_u.usr_ip4_spec.tos); | ||
| 562 | p += ETH_GSTRING_LEN; | ||
| 563 | num_strings++; | ||
| 564 | sprintf(p, "\tIP Version: %d, mask: 0x%x\n", | ||
| 565 | fsc->fs.h_u.usr_ip4_spec.ip_ver, | ||
| 566 | fsc->fs.m_u.usr_ip4_spec.ip_ver); | ||
| 567 | p += ETH_GSTRING_LEN; | ||
| 568 | num_strings++; | ||
| 569 | sprintf(p, "\tProtocol: %d, mask: 0x%x\n", | ||
| 570 | fsc->fs.h_u.usr_ip4_spec.proto, | ||
| 571 | fsc->fs.m_u.usr_ip4_spec.proto); | ||
| 572 | p += ETH_GSTRING_LEN; | ||
| 573 | num_strings++; | ||
| 574 | break; | ||
| 575 | }; | ||
| 576 | sprintf(p, "\tVLAN: %d, mask: 0x%x\n", | ||
| 577 | fsc->fs.vlan_tag, fsc->fs.vlan_tag_mask); | ||
| 578 | p += ETH_GSTRING_LEN; | ||
| 579 | num_strings++; | ||
| 580 | sprintf(p, "\tUser-defined: 0x%Lx\n", fsc->fs.data); | ||
| 581 | p += ETH_GSTRING_LEN; | ||
| 582 | num_strings++; | ||
| 583 | sprintf(p, "\tUser-defined mask: 0x%Lx\n", fsc->fs.data_mask); | ||
| 584 | p += ETH_GSTRING_LEN; | ||
| 585 | num_strings++; | ||
| 586 | if (fsc->fs.action == ETHTOOL_RXNTUPLE_ACTION_DROP) | ||
| 587 | sprintf(p, "\tAction: Drop\n"); | ||
| 588 | else | ||
| 589 | sprintf(p, "\tAction: Direct to queue %d\n", | ||
| 590 | fsc->fs.action); | ||
| 591 | p += ETH_GSTRING_LEN; | ||
| 592 | num_strings++; | ||
| 593 | unknown_filter: | ||
| 594 | i++; | ||
| 595 | } | ||
| 596 | copy: | ||
| 597 | /* indicate to userspace how many strings we actually have */ | ||
| 598 | gstrings.len = num_strings; | ||
| 599 | ret = -EFAULT; | ||
| 600 | if (copy_to_user(useraddr, &gstrings, sizeof(gstrings))) | ||
| 601 | goto out; | ||
| 602 | useraddr += sizeof(gstrings); | ||
| 603 | if (copy_to_user(useraddr, data, gstrings.len * ETH_GSTRING_LEN)) | ||
| 604 | goto out; | ||
| 605 | ret = 0; | ||
| 606 | |||
| 607 | out: | ||
| 608 | kfree(data); | ||
| 609 | return ret; | ||
| 610 | } | ||
| 611 | |||
| 269 | static int ethtool_get_regs(struct net_device *dev, char __user *useraddr) | 612 | static int ethtool_get_regs(struct net_device *dev, char __user *useraddr) |
| 270 | { | 613 | { |
| 271 | struct ethtool_regs regs; | 614 | struct ethtool_regs regs; |
| @@ -324,7 +667,7 @@ static int ethtool_reset(struct net_device *dev, char __user *useraddr) | |||
| 324 | 667 | ||
| 325 | static int ethtool_get_wol(struct net_device *dev, char __user *useraddr) | 668 | static int ethtool_get_wol(struct net_device *dev, char __user *useraddr) |
| 326 | { | 669 | { |
| 327 | struct ethtool_wolinfo wol = { ETHTOOL_GWOL }; | 670 | struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL }; |
| 328 | 671 | ||
| 329 | if (!dev->ethtool_ops->get_wol) | 672 | if (!dev->ethtool_ops->get_wol) |
| 330 | return -EOPNOTSUPP; | 673 | return -EOPNOTSUPP; |
| @@ -456,9 +799,12 @@ static int ethtool_set_eeprom(struct net_device *dev, void __user *useraddr) | |||
| 456 | return ret; | 799 | return ret; |
| 457 | } | 800 | } |
| 458 | 801 | ||
| 459 | static int ethtool_get_coalesce(struct net_device *dev, void __user *useraddr) | 802 | /* |
| 803 | * noinline attribute so that gcc doesnt use too much stack in dev_ethtool() | ||
| 804 | */ | ||
| 805 | static noinline int ethtool_get_coalesce(struct net_device *dev, void __user *useraddr) | ||
| 460 | { | 806 | { |
| 461 | struct ethtool_coalesce coalesce = { ETHTOOL_GCOALESCE }; | 807 | struct ethtool_coalesce coalesce = { .cmd = ETHTOOL_GCOALESCE }; |
| 462 | 808 | ||
| 463 | if (!dev->ethtool_ops->get_coalesce) | 809 | if (!dev->ethtool_ops->get_coalesce) |
| 464 | return -EOPNOTSUPP; | 810 | return -EOPNOTSUPP; |
| @@ -470,7 +816,10 @@ static int ethtool_get_coalesce(struct net_device *dev, void __user *useraddr) | |||
| 470 | return 0; | 816 | return 0; |
| 471 | } | 817 | } |
| 472 | 818 | ||
| 473 | static int ethtool_set_coalesce(struct net_device *dev, void __user *useraddr) | 819 | /* |
| 820 | * noinline attribute so that gcc doesnt use too much stack in dev_ethtool() | ||
| 821 | */ | ||
| 822 | static noinline int ethtool_set_coalesce(struct net_device *dev, void __user *useraddr) | ||
| 474 | { | 823 | { |
| 475 | struct ethtool_coalesce coalesce; | 824 | struct ethtool_coalesce coalesce; |
| 476 | 825 | ||
| @@ -485,7 +834,7 @@ static int ethtool_set_coalesce(struct net_device *dev, void __user *useraddr) | |||
| 485 | 834 | ||
| 486 | static int ethtool_get_ringparam(struct net_device *dev, void __user *useraddr) | 835 | static int ethtool_get_ringparam(struct net_device *dev, void __user *useraddr) |
| 487 | { | 836 | { |
| 488 | struct ethtool_ringparam ringparam = { ETHTOOL_GRINGPARAM }; | 837 | struct ethtool_ringparam ringparam = { .cmd = ETHTOOL_GRINGPARAM }; |
| 489 | 838 | ||
| 490 | if (!dev->ethtool_ops->get_ringparam) | 839 | if (!dev->ethtool_ops->get_ringparam) |
| 491 | return -EOPNOTSUPP; | 840 | return -EOPNOTSUPP; |
| @@ -839,7 +1188,7 @@ static int ethtool_get_perm_addr(struct net_device *dev, void __user *useraddr) | |||
| 839 | static int ethtool_get_value(struct net_device *dev, char __user *useraddr, | 1188 | static int ethtool_get_value(struct net_device *dev, char __user *useraddr, |
| 840 | u32 cmd, u32 (*actor)(struct net_device *)) | 1189 | u32 cmd, u32 (*actor)(struct net_device *)) |
| 841 | { | 1190 | { |
| 842 | struct ethtool_value edata = { cmd }; | 1191 | struct ethtool_value edata = { .cmd = cmd }; |
| 843 | 1192 | ||
| 844 | if (!actor) | 1193 | if (!actor) |
| 845 | return -EOPNOTSUPP; | 1194 | return -EOPNOTSUPP; |
| @@ -880,7 +1229,10 @@ static int ethtool_set_value(struct net_device *dev, char __user *useraddr, | |||
| 880 | return actor(dev, edata.data); | 1229 | return actor(dev, edata.data); |
| 881 | } | 1230 | } |
| 882 | 1231 | ||
| 883 | static int ethtool_flash_device(struct net_device *dev, char __user *useraddr) | 1232 | /* |
| 1233 | * noinline attribute so that gcc doesnt use too much stack in dev_ethtool() | ||
| 1234 | */ | ||
| 1235 | static noinline int ethtool_flash_device(struct net_device *dev, char __user *useraddr) | ||
| 884 | { | 1236 | { |
| 885 | struct ethtool_flash efl; | 1237 | struct ethtool_flash efl; |
| 886 | 1238 | ||
| @@ -927,6 +1279,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) | |||
| 927 | case ETHTOOL_GPERMADDR: | 1279 | case ETHTOOL_GPERMADDR: |
| 928 | case ETHTOOL_GUFO: | 1280 | case ETHTOOL_GUFO: |
| 929 | case ETHTOOL_GGSO: | 1281 | case ETHTOOL_GGSO: |
| 1282 | case ETHTOOL_GGRO: | ||
| 930 | case ETHTOOL_GFLAGS: | 1283 | case ETHTOOL_GFLAGS: |
| 931 | case ETHTOOL_GPFLAGS: | 1284 | case ETHTOOL_GPFLAGS: |
| 932 | case ETHTOOL_GRXFH: | 1285 | case ETHTOOL_GRXFH: |
| @@ -1112,6 +1465,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) | |||
| 1112 | case ETHTOOL_RESET: | 1465 | case ETHTOOL_RESET: |
| 1113 | rc = ethtool_reset(dev, useraddr); | 1466 | rc = ethtool_reset(dev, useraddr); |
| 1114 | break; | 1467 | break; |
| 1468 | case ETHTOOL_SRXNTUPLE: | ||
| 1469 | rc = ethtool_set_rx_ntuple(dev, useraddr); | ||
| 1470 | break; | ||
| 1471 | case ETHTOOL_GRXNTUPLE: | ||
| 1472 | rc = ethtool_get_rx_ntuple(dev, useraddr); | ||
| 1473 | break; | ||
| 1115 | default: | 1474 | default: |
| 1116 | rc = -EOPNOTSUPP; | 1475 | rc = -EOPNOTSUPP; |
| 1117 | } | 1476 | } |
