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/netrom/af_netrom.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/netrom/af_netrom.c')
-rw-r--r-- | net/netrom/af_netrom.c | 130 |
1 files changed, 82 insertions, 48 deletions
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index a4b89d294..3ba0b8c81 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -47,6 +47,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> @@ -347,6 +348,8 @@ static int nr_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen) { struct sock *sk = sock->sk; + char devname[IFNAMSIZ]; + struct net_device *dev; int opt; if (level != SOL_NETROM) @@ -389,6 +392,21 @@ static int nr_setsockopt(struct socket *sock, int level, int optname, sk->protinfo.nr->idle = opt * 60 * HZ; 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.nr->device=dev; + return 0; + default: return -ENOPROTOOPT; } @@ -398,15 +416,24 @@ static int nr_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_NETROM) 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 NETROM_T1: val = sk->protinfo.nr->t1 / HZ; @@ -428,16 +455,33 @@ static int nr_getsockopt(struct socket *sock, int level, int optname, val = sk->protinfo.nr->idle / (60 * HZ); break; + case SO_BINDTODEVICE: + dev = sk->protinfo.nr->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 nr_listen(struct socket *sock, int backlog) @@ -589,13 +633,12 @@ static int nr_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) struct sock *sk = sock->sk; struct full_sockaddr_ax25 *addr = (struct full_sockaddr_ax25 *)uaddr; struct net_device *dev; - ax25_address *user, *source; + ax25_address *user = NULL, *source = NULL; if (sk->zapped == 0) return -EINVAL; - if (addr_len < sizeof(struct sockaddr_ax25) || addr_len > sizeof(struct -full_sockaddr_ax25)) + if (addr_len < sizeof(struct sockaddr_ax25) || addr_len > sizeof(struct full_sockaddr_ax25)) return -EINVAL; if (addr_len < (addr->fsa_ax25.sax25_ndigis * sizeof(ax25_address) + sizeof(struct sockaddr_ax25))) @@ -604,32 +647,42 @@ full_sockaddr_ax25)) if (addr->fsa_ax25.sax25_family != AF_NETROM) return -EINVAL; - if ((dev = nr_dev_get(&addr->fsa_ax25.sax25_call)) == NULL) { - SOCK_DEBUG(sk, "NET/ROM: bind failed: invalid node callsign\n"); - return -EADDRNOTAVAIL; - } - /* - * Only the super user can set an arbitrary user callsign. + * User did not set the interfave with SO_BINDTODEVICE, + * use compatibility code. */ - if (addr->fsa_ax25.sax25_ndigis == 1) { - if (!capable(CAP_NET_BIND_SERVICE)) - return -EACCES; - sk->protinfo.nr->user_addr = addr->fsa_digipeater[0]; - sk->protinfo.nr->source_addr = addr->fsa_ax25.sax25_call; - } else { - source = &addr->fsa_ax25.sax25_call; - if ((user = ax25_findbyuid(current->euid)) == NULL) { - if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) - return -EPERM; - user = source; + dev = sk->protinfo.nr->device; + if (dev == NULL) { + if (addr_len > sizeof(struct sockaddr_ax25) && addr->fsax25_ndigis == 1) { + /* device callsign provided */ + if(ax25cmp(&addr->fsa_digipeater[0], &null_ax25_address) && + (dev = nr_dev_get(&addr->fsa_digipeater[0])) == NULL) + return -EADDRNOTAVAIL; + source = &addr->fsa_digipeater[0]; + } else { + if ((dev = nr_dev_get(&addr->fsax25_call)) == NULL) + return -EADDRNOTAVAIL; + source = &addr->fsa_ax25.sax25_call; } - sk->protinfo.nr->user_addr = *user; - sk->protinfo.nr->source_addr = *source; + sk->protinfo.nr->device = dev; + } else { + source = (ax25_address *) dev->dev_addr; } + if (!capable(CAP_NET_BIND_SERVICE)) + { + /* FIXME: should not be coupled with AX.25 */ + user = ax25_find_match_for_uid(current->euid, &addr->fsax25_call, dev->name); + if (user == NULL && ax25_uid_policy) + return -EACCES; + } + + if (user == NULL) user = &addr->fsax25_call; + sk->protinfo.nr->user_addr = *user; + sk->protinfo.nr->source_addr = *source; + sk->protinfo.nr->device = dev; nr_insert_socket(sk); @@ -643,7 +696,6 @@ static int nr_connect(struct socket *sock, struct sockaddr *uaddr, { struct sock *sk = sock->sk; struct sockaddr_ax25 *addr = (struct sockaddr_ax25 *)uaddr; - ax25_address *user, *source = NULL; struct net_device *dev; if (sk->state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) { @@ -668,26 +720,8 @@ static int nr_connect(struct socket *sock, struct sockaddr *uaddr, if (addr->sax25_family != AF_NETROM) return -EINVAL; - if (sk->zapped) { /* Must bind first - autobinding in this may or may not work */ - sk->zapped = 0; - - if ((dev = nr_dev_first()) == NULL) - return -ENETUNREACH; - - source = (ax25_address *)dev->dev_addr; - - if ((user = ax25_findbyuid(current->euid)) == NULL) { - if (ax25_uid_policy && !capable(CAP_NET_ADMIN)) - return -EPERM; - user = source; - } - - sk->protinfo.nr->user_addr = *user; - sk->protinfo.nr->source_addr = *source; - sk->protinfo.nr->device = dev; - - nr_insert_socket(sk); /* Finish the bind */ - } + if (sk->zapped) + return -EADDRNOTAVAIL; sk->protinfo.nr->dest_addr = addr->sax25_call; |