diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2015-06-24 04:23:46 +0200 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2015-06-24 10:03:18 +0200 |
commit | e5067d7cd967cb17067de24a162306b79f432b20 (patch) | |
tree | 541f101762df32a5742bec354009986a96d8e564 /net/rose/af_rose.c | |
parent | 86a981e836404006efc35881ebf3d5ae36925e82 (diff) |
Import newax25-2.4.3.patch.1.bz2HEADnewax25-2.4.3-1
And cleanup the *.orig and *.rej files and whitespace errors that are part
of the original patch.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'net/rose/af_rose.c')
-rw-r--r-- | net/rose/af_rose.c | 107 |
1 files changed, 77 insertions, 30 deletions
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index a92bf86f5..07acd3946 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -39,6 +39,7 @@ #include <linux/net.h> #include <linux/stat.h> #include <net/ax25.h> +#include <net/ax25_uid.h> #include <linux/inet.h> #include <linux/netdevice.h> #include <linux/if_arp.h> @@ -404,6 +405,8 @@ static int rose_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen) { struct sock *sk = sock->sk; + struct net_device *dev; + char devname[IFNAMSIZ]; int opt; if (level != SOL_ROSE) @@ -454,6 +457,22 @@ static int rose_setsockopt(struct socket *sock, int level, int optname, sk->protinfo.rose->qbitincl = opt ? 1 : 0; return 0; + + case SO_BINDTODEVICE: + if (optlen > IFNAMSIZ) optlen = IFNAMSIZ; + if (copy_from_user(devname, optval, optlen)) + return -EFAULT; + + dev = dev_get_by_name(devname); + if (dev == NULL) return -ENODEV; + + if (sk->type == SOCK_SEQPACKET && + (sock->state != SS_UNCONNECTED || sk->state == TCP_LISTEN)) + return -EADDRNOTAVAIL; + + sk->protinfo.rose->device = dev; + return 0; + default: return -ENOPROTOOPT; } @@ -463,14 +482,23 @@ static int rose_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen) { struct sock *sk = sock->sk; + struct net_device *dev; + char devname[IFNAMSIZ]; + void *valptr; int val = 0; - int len; + int maxlen, length; if (level != SOL_ROSE) return -ENOPROTOOPT; - if (get_user(len, optlen)) + if (get_user(maxlen, optlen)) return -EFAULT; + + if (maxlen < 1) + return -EFAULT; + + valptr = (void *) &val; + length = min(maxlen, sizeof(int)); switch (optname) { case ROSE_DEFER: @@ -501,16 +529,32 @@ static int rose_getsockopt(struct socket *sock, int level, int optname, val = sk->protinfo.rose->qbitincl; break; + case SO_BINDTODEVICE: + dev = sk->protinfo.rose->device; + + if (dev != NULL) { + strncpy(devname, dev->name, IFNAMSIZ); + length = min(strlen(dev->name)+1, maxlen); + devname[length-1] = '\0'; + } else { + *devname = '\0'; + length = 1; + } + + valptr = (void *) devname; + break; + default: return -ENOPROTOOPT; } - len = min(len, sizeof(int)); + if (put_user(length, optlen)) + return -EFAULT; - if (put_user(len, optlen)) + if (copy_to_user(optval, valptr, length)) return -EFAULT; - return copy_to_user(optval, &val, len) ? -EFAULT : 0; + return 0; } static int rose_listen(struct socket *sock, int backlog) @@ -666,7 +710,8 @@ static int rose_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) struct sock *sk = sock->sk; struct sockaddr_rose *addr = (struct sockaddr_rose *)uaddr; struct net_device *dev; - ax25_address *user, *source; + ax25_address *user = NULL; + rose_address *source = NULL; int n; if (sk->zapped == 0) @@ -683,21 +728,36 @@ static int rose_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) if (addr->srose_ndigis > ROSE_MAX_DIGIS) return -EINVAL; + /* + * User did not set interface with SO_BINDTODEVICE + * thus we'll use the compatibility code + */ + + dev = sk->protinfo.rose->device; + if (dev == NULL) { + if ((dev = rose_dev_get(&addr->srose_addr)) == NULL) { + SOCK_DEBUG(sk, "ROSE: bind failed: invalid address\n"); + return -EADDRNOTAVAIL; + } - if ((dev = rose_dev_get(&addr->srose_addr)) == NULL) { - SOCK_DEBUG(sk, "ROSE: bind failed: invalid address\n"); - return -EADDRNOTAVAIL; + source = &addr->srose_addr; + sk->protinfo.rose->device = dev; + } else { + source = (rose_address *) dev->dev_addr; } - source = &addr->srose_call; - - if ((user = ax25_findbyuid(current->euid)) == NULL) { - if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) + /* root can do whatever (s)he likes, but anyone else... */ + if (!capable(CAP_NET_BIND_SERVICE)) + { + /* FIXME: strictly speaking this has nothing to do with AX.25 */ + user = ax25_find_match_for_uid(current->euid, &addr->srose_call, dev->name); + if (user == NULL && ax25_uid_policy) return -EACCES; - user = source; } - sk->protinfo.rose->source_addr = addr->srose_addr; + if (user == NULL) user = &addr->srose_call; + + sk->protinfo.rose->source_addr = *source; sk->protinfo.rose->source_call = *user; sk->protinfo.rose->device = dev; sk->protinfo.rose->source_ndigis = addr->srose_ndigis; @@ -766,21 +826,8 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le if ((sk->protinfo.rose->lci = rose_new_lci(sk->protinfo.rose->neighbour)) == 0) return -ENETUNREACH; - if (sk->zapped) { /* Must bind first - autobinding in this may or may not work */ - sk->zapped = 0; - - if ((dev = rose_dev_first()) == NULL) - return -ENETUNREACH; - - if ((user = ax25_findbyuid(current->euid)) == NULL) - return -EINVAL; - - memcpy(&sk->protinfo.rose->source_addr, dev->dev_addr, ROSE_ADDR_LEN); - sk->protinfo.rose->source_call = *user; - sk->protinfo.rose->device = dev; - - rose_insert_socket(sk); /* Finish the bind */ - } + if (sk->zapped) + return -EINVAL; sk->protinfo.rose->dest_addr = addr->srose_addr; sk->protinfo.rose->dest_call = addr->srose_call; |