aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/core/sock.c106
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}
363EXPORT_SYMBOL(sk_dst_check); 363EXPORT_SYMBOL(sk_dst_check);
364 364
365static 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
414out:
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)) {