diff options
-rw-r--r-- | net/core/sock.c | 106 |
1 files changed, 58 insertions, 48 deletions
diff --git a/net/core/sock.c b/net/core/sock.c index cfed7d42c485..190de61cd648 100644 --- a/net/core/sock.c +++ b/net/core/sock.c | |||
@@ -362,6 +362,61 @@ struct dst_entry *sk_dst_check(struct sock *sk, u32 cookie) | |||
362 | } | 362 | } |
363 | EXPORT_SYMBOL(sk_dst_check); | 363 | EXPORT_SYMBOL(sk_dst_check); |
364 | 364 | ||
365 | static int sock_bindtodevice(struct sock *sk, char __user *optval, int optlen) | ||
366 | { | ||
367 | int ret = -ENOPROTOOPT; | ||
368 | #ifdef CONFIG_NETDEVICES | ||
369 | char devname[IFNAMSIZ]; | ||
370 | int index; | ||
371 | |||
372 | /* Sorry... */ | ||
373 | ret = -EPERM; | ||
374 | if (!capable(CAP_NET_RAW)) | ||
375 | goto out; | ||
376 | |||
377 | ret = -EINVAL; | ||
378 | if (optlen < 0) | ||
379 | goto out; | ||
380 | |||
381 | /* Bind this socket to a particular device like "eth0", | ||
382 | * as specified in the passed interface name. If the | ||
383 | * name is "" or the option length is zero the socket | ||
384 | * is not bound. | ||
385 | */ | ||
386 | if (optlen > IFNAMSIZ - 1) | ||
387 | optlen = IFNAMSIZ - 1; | ||
388 | memset(devname, 0, sizeof(devname)); | ||
389 | |||
390 | ret = -EFAULT; | ||
391 | if (copy_from_user(devname, optval, optlen)) | ||
392 | goto out; | ||
393 | |||
394 | if (devname[0] == '\0') { | ||
395 | index = 0; | ||
396 | } else { | ||
397 | struct net_device *dev = dev_get_by_name(devname); | ||
398 | |||
399 | ret = -ENODEV; | ||
400 | if (!dev) | ||
401 | goto out; | ||
402 | |||
403 | index = dev->ifindex; | ||
404 | dev_put(dev); | ||
405 | } | ||
406 | |||
407 | lock_sock(sk); | ||
408 | sk->sk_bound_dev_if = index; | ||
409 | sk_dst_reset(sk); | ||
410 | release_sock(sk); | ||
411 | |||
412 | ret = 0; | ||
413 | |||
414 | out: | ||
415 | #endif | ||
416 | |||
417 | return ret; | ||
418 | } | ||
419 | |||
365 | /* | 420 | /* |
366 | * This is meant for all protocols to use and covers goings on | 421 | * This is meant for all protocols to use and covers goings on |
367 | * at the socket level. Everything here is generic. | 422 | * at the socket level. Everything here is generic. |
@@ -390,6 +445,9 @@ int sock_setsockopt(struct socket *sock, int level, int optname, | |||
390 | } | 445 | } |
391 | #endif | 446 | #endif |
392 | 447 | ||
448 | if (optname == SO_BINDTODEVICE) | ||
449 | return sock_bindtodevice(sk, optval, optlen); | ||
450 | |||
393 | if (optlen < sizeof(int)) | 451 | if (optlen < sizeof(int)) |
394 | return -EINVAL; | 452 | return -EINVAL; |
395 | 453 | ||
@@ -578,54 +636,6 @@ set_rcvbuf: | |||
578 | ret = sock_set_timeout(&sk->sk_sndtimeo, optval, optlen); | 636 | ret = sock_set_timeout(&sk->sk_sndtimeo, optval, optlen); |
579 | break; | 637 | break; |
580 | 638 | ||
581 | #ifdef CONFIG_NETDEVICES | ||
582 | case SO_BINDTODEVICE: | ||
583 | { | ||
584 | char devname[IFNAMSIZ]; | ||
585 | |||
586 | /* Sorry... */ | ||
587 | if (!capable(CAP_NET_RAW)) { | ||
588 | ret = -EPERM; | ||
589 | break; | ||
590 | } | ||
591 | |||
592 | /* Bind this socket to a particular device like "eth0", | ||
593 | * as specified in the passed interface name. If the | ||
594 | * name is "" or the option length is zero the socket | ||
595 | * is not bound. | ||
596 | */ | ||
597 | |||
598 | if (!valbool) { | ||
599 | sk->sk_bound_dev_if = 0; | ||
600 | } else { | ||
601 | if (optlen > IFNAMSIZ - 1) | ||
602 | optlen = IFNAMSIZ - 1; | ||
603 | memset(devname, 0, sizeof(devname)); | ||
604 | if (copy_from_user(devname, optval, optlen)) { | ||
605 | ret = -EFAULT; | ||
606 | break; | ||
607 | } | ||
608 | |||
609 | /* Remove any cached route for this socket. */ | ||
610 | sk_dst_reset(sk); | ||
611 | |||
612 | if (devname[0] == '\0') { | ||
613 | sk->sk_bound_dev_if = 0; | ||
614 | } else { | ||
615 | struct net_device *dev = dev_get_by_name(devname); | ||
616 | if (!dev) { | ||
617 | ret = -ENODEV; | ||
618 | break; | ||
619 | } | ||
620 | sk->sk_bound_dev_if = dev->ifindex; | ||
621 | dev_put(dev); | ||
622 | } | ||
623 | } | ||
624 | break; | ||
625 | } | ||
626 | #endif | ||
627 | |||
628 | |||
629 | case SO_ATTACH_FILTER: | 639 | case SO_ATTACH_FILTER: |
630 | ret = -EINVAL; | 640 | ret = -EINVAL; |
631 | if (optlen == sizeof(struct sock_fprog)) { | 641 | if (optlen == sizeof(struct sock_fprog)) { |