diff options
Diffstat (limited to 'drivers/net/netconsole.c')
-rw-r--r-- | drivers/net/netconsole.c | 108 |
1 files changed, 35 insertions, 73 deletions
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index eb41e44921e..dfc82720065 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c | |||
@@ -242,34 +242,6 @@ static struct netconsole_target *to_target(struct config_item *item) | |||
242 | } | 242 | } |
243 | 243 | ||
244 | /* | 244 | /* |
245 | * Wrapper over simple_strtol (base 10) with sanity and range checking. | ||
246 | * We return (signed) long only because we may want to return errors. | ||
247 | * Do not use this to convert numbers that are allowed to be negative. | ||
248 | */ | ||
249 | static long strtol10_check_range(const char *cp, long min, long max) | ||
250 | { | ||
251 | long ret; | ||
252 | char *p = (char *) cp; | ||
253 | |||
254 | WARN_ON(min < 0); | ||
255 | WARN_ON(max < min); | ||
256 | |||
257 | ret = simple_strtol(p, &p, 10); | ||
258 | |||
259 | if (*p && (*p != '\n')) { | ||
260 | printk(KERN_ERR "netconsole: invalid input\n"); | ||
261 | return -EINVAL; | ||
262 | } | ||
263 | if ((ret < min) || (ret > max)) { | ||
264 | printk(KERN_ERR "netconsole: input %ld must be between " | ||
265 | "%ld and %ld\n", ret, min, max); | ||
266 | return -EINVAL; | ||
267 | } | ||
268 | |||
269 | return ret; | ||
270 | } | ||
271 | |||
272 | /* | ||
273 | * Attribute operations for netconsole_target. | 245 | * Attribute operations for netconsole_target. |
274 | */ | 246 | */ |
275 | 247 | ||
@@ -327,12 +299,14 @@ static ssize_t store_enabled(struct netconsole_target *nt, | |||
327 | const char *buf, | 299 | const char *buf, |
328 | size_t count) | 300 | size_t count) |
329 | { | 301 | { |
302 | int enabled; | ||
330 | int err; | 303 | int err; |
331 | long enabled; | ||
332 | 304 | ||
333 | enabled = strtol10_check_range(buf, 0, 1); | 305 | err = kstrtoint(buf, 10, &enabled); |
334 | if (enabled < 0) | 306 | if (err < 0) |
335 | return enabled; | 307 | return err; |
308 | if (enabled < 0 || enabled > 1) | ||
309 | return -EINVAL; | ||
336 | 310 | ||
337 | if (enabled) { /* 1 */ | 311 | if (enabled) { /* 1 */ |
338 | 312 | ||
@@ -384,8 +358,7 @@ static ssize_t store_local_port(struct netconsole_target *nt, | |||
384 | const char *buf, | 358 | const char *buf, |
385 | size_t count) | 359 | size_t count) |
386 | { | 360 | { |
387 | long local_port; | 361 | int rv; |
388 | #define __U16_MAX ((__u16) ~0U) | ||
389 | 362 | ||
390 | if (nt->enabled) { | 363 | if (nt->enabled) { |
391 | printk(KERN_ERR "netconsole: target (%s) is enabled, " | 364 | printk(KERN_ERR "netconsole: target (%s) is enabled, " |
@@ -394,12 +367,9 @@ static ssize_t store_local_port(struct netconsole_target *nt, | |||
394 | return -EINVAL; | 367 | return -EINVAL; |
395 | } | 368 | } |
396 | 369 | ||
397 | local_port = strtol10_check_range(buf, 0, __U16_MAX); | 370 | rv = kstrtou16(buf, 10, &nt->np.local_port); |
398 | if (local_port < 0) | 371 | if (rv < 0) |
399 | return local_port; | 372 | return rv; |
400 | |||
401 | nt->np.local_port = local_port; | ||
402 | |||
403 | return strnlen(buf, count); | 373 | return strnlen(buf, count); |
404 | } | 374 | } |
405 | 375 | ||
@@ -407,8 +377,7 @@ static ssize_t store_remote_port(struct netconsole_target *nt, | |||
407 | const char *buf, | 377 | const char *buf, |
408 | size_t count) | 378 | size_t count) |
409 | { | 379 | { |
410 | long remote_port; | 380 | int rv; |
411 | #define __U16_MAX ((__u16) ~0U) | ||
412 | 381 | ||
413 | if (nt->enabled) { | 382 | if (nt->enabled) { |
414 | printk(KERN_ERR "netconsole: target (%s) is enabled, " | 383 | printk(KERN_ERR "netconsole: target (%s) is enabled, " |
@@ -417,12 +386,9 @@ static ssize_t store_remote_port(struct netconsole_target *nt, | |||
417 | return -EINVAL; | 386 | return -EINVAL; |
418 | } | 387 | } |
419 | 388 | ||
420 | remote_port = strtol10_check_range(buf, 0, __U16_MAX); | 389 | rv = kstrtou16(buf, 10, &nt->np.remote_port); |
421 | if (remote_port < 0) | 390 | if (rv < 0) |
422 | return remote_port; | 391 | return rv; |
423 | |||
424 | nt->np.remote_port = remote_port; | ||
425 | |||
426 | return strnlen(buf, count); | 392 | return strnlen(buf, count); |
427 | } | 393 | } |
428 | 394 | ||
@@ -463,8 +429,6 @@ static ssize_t store_remote_mac(struct netconsole_target *nt, | |||
463 | size_t count) | 429 | size_t count) |
464 | { | 430 | { |
465 | u8 remote_mac[ETH_ALEN]; | 431 | u8 remote_mac[ETH_ALEN]; |
466 | char *p = (char *) buf; | ||
467 | int i; | ||
468 | 432 | ||
469 | if (nt->enabled) { | 433 | if (nt->enabled) { |
470 | printk(KERN_ERR "netconsole: target (%s) is enabled, " | 434 | printk(KERN_ERR "netconsole: target (%s) is enabled, " |
@@ -473,23 +437,13 @@ static ssize_t store_remote_mac(struct netconsole_target *nt, | |||
473 | return -EINVAL; | 437 | return -EINVAL; |
474 | } | 438 | } |
475 | 439 | ||
476 | for (i = 0; i < ETH_ALEN - 1; i++) { | 440 | if (!mac_pton(buf, remote_mac)) |
477 | remote_mac[i] = simple_strtoul(p, &p, 16); | 441 | return -EINVAL; |
478 | if (*p != ':') | 442 | if (buf[3 * ETH_ALEN - 1] && buf[3 * ETH_ALEN - 1] != '\n') |
479 | goto invalid; | 443 | return -EINVAL; |
480 | p++; | ||
481 | } | ||
482 | remote_mac[ETH_ALEN - 1] = simple_strtoul(p, &p, 16); | ||
483 | if (*p && (*p != '\n')) | ||
484 | goto invalid; | ||
485 | |||
486 | memcpy(nt->np.remote_mac, remote_mac, ETH_ALEN); | 444 | memcpy(nt->np.remote_mac, remote_mac, ETH_ALEN); |
487 | 445 | ||
488 | return strnlen(buf, count); | 446 | return strnlen(buf, count); |
489 | |||
490 | invalid: | ||
491 | printk(KERN_ERR "netconsole: invalid input\n"); | ||
492 | return -EINVAL; | ||
493 | } | 447 | } |
494 | 448 | ||
495 | /* | 449 | /* |
@@ -667,11 +621,10 @@ static int netconsole_netdev_event(struct notifier_block *this, | |||
667 | bool stopped = false; | 621 | bool stopped = false; |
668 | 622 | ||
669 | if (!(event == NETDEV_CHANGENAME || event == NETDEV_UNREGISTER || | 623 | if (!(event == NETDEV_CHANGENAME || event == NETDEV_UNREGISTER || |
670 | event == NETDEV_BONDING_DESLAVE || event == NETDEV_GOING_DOWN)) | 624 | event == NETDEV_RELEASE || event == NETDEV_JOIN)) |
671 | goto done; | 625 | goto done; |
672 | 626 | ||
673 | spin_lock_irqsave(&target_list_lock, flags); | 627 | spin_lock_irqsave(&target_list_lock, flags); |
674 | restart: | ||
675 | list_for_each_entry(nt, &target_list, list) { | 628 | list_for_each_entry(nt, &target_list, list) { |
676 | netconsole_target_get(nt); | 629 | netconsole_target_get(nt); |
677 | if (nt->np.dev == dev) { | 630 | if (nt->np.dev == dev) { |
@@ -679,6 +632,8 @@ restart: | |||
679 | case NETDEV_CHANGENAME: | 632 | case NETDEV_CHANGENAME: |
680 | strlcpy(nt->np.dev_name, dev->name, IFNAMSIZ); | 633 | strlcpy(nt->np.dev_name, dev->name, IFNAMSIZ); |
681 | break; | 634 | break; |
635 | case NETDEV_RELEASE: | ||
636 | case NETDEV_JOIN: | ||
682 | case NETDEV_UNREGISTER: | 637 | case NETDEV_UNREGISTER: |
683 | /* | 638 | /* |
684 | * rtnl_lock already held | 639 | * rtnl_lock already held |
@@ -693,11 +648,7 @@ restart: | |||
693 | dev_put(nt->np.dev); | 648 | dev_put(nt->np.dev); |
694 | nt->np.dev = NULL; | 649 | nt->np.dev = NULL; |
695 | netconsole_target_put(nt); | 650 | netconsole_target_put(nt); |
696 | goto restart; | ||
697 | } | 651 | } |
698 | /* Fall through */ | ||
699 | case NETDEV_GOING_DOWN: | ||
700 | case NETDEV_BONDING_DESLAVE: | ||
701 | nt->enabled = 0; | 652 | nt->enabled = 0; |
702 | stopped = true; | 653 | stopped = true; |
703 | break; | 654 | break; |
@@ -706,10 +657,21 @@ restart: | |||
706 | netconsole_target_put(nt); | 657 | netconsole_target_put(nt); |
707 | } | 658 | } |
708 | spin_unlock_irqrestore(&target_list_lock, flags); | 659 | spin_unlock_irqrestore(&target_list_lock, flags); |
709 | if (stopped && (event == NETDEV_UNREGISTER || event == NETDEV_BONDING_DESLAVE)) | 660 | if (stopped) { |
710 | printk(KERN_INFO "netconsole: network logging stopped on " | 661 | printk(KERN_INFO "netconsole: network logging stopped on " |
711 | "interface %s as it %s\n", dev->name, | 662 | "interface %s as it ", dev->name); |
712 | event == NETDEV_UNREGISTER ? "unregistered" : "released slaves"); | 663 | switch (event) { |
664 | case NETDEV_UNREGISTER: | ||
665 | printk(KERN_CONT "unregistered\n"); | ||
666 | break; | ||
667 | case NETDEV_RELEASE: | ||
668 | printk(KERN_CONT "released slaves\n"); | ||
669 | break; | ||
670 | case NETDEV_JOIN: | ||
671 | printk(KERN_CONT "is joining a master device\n"); | ||
672 | break; | ||
673 | } | ||
674 | } | ||
713 | 675 | ||
714 | done: | 676 | done: |
715 | return NOTIFY_DONE; | 677 | return NOTIFY_DONE; |