summaryrefslogtreecommitdiffstats
path: root/net/rose
diff options
context:
space:
mode:
Diffstat (limited to 'net/rose')
-rw-r--r--net/rose/af_rose.c107
-rw-r--r--net/rose/rose_link.c16
-rw-r--r--net/rose/rose_route.c75
-rw-r--r--net/rose/rose_subr.c7
4 files changed, 119 insertions, 86 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;
diff --git a/net/rose/rose_link.c b/net/rose/rose_link.c
index 2c793e4e6..a4e5f71bd 100644
--- a/net/rose/rose_link.c
+++ b/net/rose/rose_link.c
@@ -104,14 +104,12 @@ static void rose_t0timer_expiry(unsigned long param)
*/
static int rose_send_frame(struct sk_buff *skb, struct rose_neigh *neigh)
{
- ax25_address *rose_call;
-
if (ax25cmp(&rose_callsign, &null_ax25_address) == 0)
- rose_call = (ax25_address *)neigh->dev->dev_addr;
+ neigh->addr.src = *((ax25_address *) neigh->dev->dev_addr);
else
- rose_call = &rose_callsign;
+ neigh->addr.src = rose_callsign;
- neigh->ax25 = ax25_send_frame(skb, 260, rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);
+ neigh->ax25 = ax25_send_frame(skb, 260, &neigh->addr, neigh->dev);
return (neigh->ax25 != NULL);
}
@@ -123,14 +121,12 @@ static int rose_send_frame(struct sk_buff *skb, struct rose_neigh *neigh)
*/
static int rose_link_up(struct rose_neigh *neigh)
{
- ax25_address *rose_call;
-
if (ax25cmp(&rose_callsign, &null_ax25_address) == 0)
- rose_call = (ax25_address *)neigh->dev->dev_addr;
+ neigh->addr.src = *((ax25_address *) neigh->dev->dev_addr);
else
- rose_call = &rose_callsign;
+ neigh->addr.src = rose_callsign;
- neigh->ax25 = ax25_find_cb(rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);
+ neigh->ax25 = ax25_find_cb(&neigh->addr, neigh->dev);
return (neigh->ax25 != NULL);
}
diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c
index 1bedfdf0d..4de549586 100644
--- a/net/rose/rose_route.c
+++ b/net/rose/rose_route.c
@@ -77,23 +77,23 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct net_device
return -EINVAL;
for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next)
- if (ax25cmp(&rose_route->neighbour, &rose_neigh->callsign) == 0 && rose_neigh->dev == dev)
+ if (ax25cmp(&rose_route->neighbour, &rose_neigh->addr.dest) == 0 && rose_neigh->dev == dev)
break;
if (rose_neigh == NULL) {
if ((rose_neigh = kmalloc(sizeof(*rose_neigh), GFP_ATOMIC)) == NULL)
return -ENOMEM;
- rose_neigh->callsign = rose_route->neighbour;
- rose_neigh->digipeat = NULL;
- rose_neigh->ax25 = NULL;
- rose_neigh->dev = dev;
- rose_neigh->count = 0;
- rose_neigh->use = 0;
- rose_neigh->dce_mode = 0;
- rose_neigh->loopback = 0;
- rose_neigh->number = rose_neigh_no++;
- rose_neigh->restarted = 0;
+ rose_neigh->addr.dest = rose_route->neighbour;
+ rose_neigh->addr.dcount = 0;
+ rose_neigh->ax25 = NULL;
+ rose_neigh->dev = dev;
+ rose_neigh->count = 0;
+ rose_neigh->use = 0;
+ rose_neigh->dce_mode = 0;
+ rose_neigh->loopback = 0;
+ rose_neigh->number = rose_neigh_no++;
+ rose_neigh->restarted = 0;
skb_queue_head_init(&rose_neigh->queue);
@@ -101,18 +101,11 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct net_device
init_timer(&rose_neigh->t0timer);
if (rose_route->ndigis != 0) {
- if ((rose_neigh->digipeat = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL) {
- kfree(rose_neigh);
- return -ENOMEM;
- }
-
- rose_neigh->digipeat->ndigi = rose_route->ndigis;
- rose_neigh->digipeat->lastrepeat = -1;
+ rose_neigh->addr.dcount = rose_route->ndigis;
+ rose_neigh->addr.lastrepeat = -1;
- for (i = 0; i < rose_route->ndigis; i++) {
- rose_neigh->digipeat->calls[i] = rose_route->digipeaters[i];
- rose_neigh->digipeat->repeated[i] = 0;
- }
+ for (i = 0; i < rose_route->ndigis; i++)
+ rose_neigh->addr.digipeater[i] = rose_route->digipeaters[i];
}
save_flags(flags); cli();
@@ -234,8 +227,6 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh)
if ((s = rose_neigh_list) == rose_neigh) {
rose_neigh_list = rose_neigh->next;
restore_flags(flags);
- if (rose_neigh->digipeat != NULL)
- kfree(rose_neigh->digipeat);
kfree(rose_neigh);
return;
}
@@ -244,8 +235,6 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh)
if (s->next == rose_neigh) {
s->next = rose_neigh->next;
restore_flags(flags);
- if (rose_neigh->digipeat != NULL)
- kfree(rose_neigh->digipeat);
kfree(rose_neigh);
return;
}
@@ -309,7 +298,7 @@ static int rose_del_node(struct rose_route_struct *rose_route, struct net_device
if (rose_node->loopback) return -EINVAL;
for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next)
- if (ax25cmp(&rose_route->neighbour, &rose_neigh->callsign) == 0 && rose_neigh->dev == dev)
+ if (ax25cmp(&rose_route->neighbour, &rose_neigh->addr.dest) == 0 && rose_neigh->dev == dev)
break;
if (rose_neigh == NULL) return -EINVAL;
@@ -353,16 +342,16 @@ int rose_add_loopback_neigh(void)
if ((rose_loopback_neigh = kmalloc(sizeof(struct rose_neigh), GFP_ATOMIC)) == NULL)
return -ENOMEM;
- rose_loopback_neigh->callsign = null_ax25_address;
- rose_loopback_neigh->digipeat = NULL;
- rose_loopback_neigh->ax25 = NULL;
- rose_loopback_neigh->dev = NULL;
- rose_loopback_neigh->count = 0;
- rose_loopback_neigh->use = 0;
- rose_loopback_neigh->dce_mode = 1;
- rose_loopback_neigh->loopback = 1;
- rose_loopback_neigh->number = rose_neigh_no++;
- rose_loopback_neigh->restarted = 1;
+ rose_loopback_neigh->addr.dest = null_ax25_address;
+ rose_loopback_neigh->addr.dcount = 0;
+ rose_loopback_neigh->ax25 = NULL;
+ rose_loopback_neigh->dev = NULL;
+ rose_loopback_neigh->count = 0;
+ rose_loopback_neigh->use = 0;
+ rose_loopback_neigh->dce_mode = 1;
+ rose_loopback_neigh->loopback = 1;
+ rose_loopback_neigh->number = rose_neigh_no++;
+ rose_loopback_neigh->restarted = 1;
skb_queue_head_init(&rose_loopback_neigh->queue);
@@ -787,11 +776,11 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
dest_addr = (rose_address *)(skb->data + 4);
for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next)
- if (ax25cmp(&ax25->dest_addr, &rose_neigh->callsign) == 0 && ax25->ax25_dev->dev == rose_neigh->dev)
+ if (ax25cmp(&ax25->addr.dest, &rose_neigh->addr.dest) == 0 && ax25->device == rose_neigh->dev)
break;
if (rose_neigh == NULL) {
- printk("rose_route : unknown neighbour or device %s\n", ax2asc(&ax25->dest_addr));
+ printk("rose_route : unknown neighbour or device %s\n", ax2asc(&ax25->addr.dest));
return 0;
}
@@ -1034,7 +1023,7 @@ int rose_neigh_get_info(char *buffer, char **start, off_t offset, int length)
/* if (!rose_neigh->loopback) { */
len += sprintf(buffer + len, "%05d %-9s %-4s %3d %3d %3s %3s %3lu %3lu",
rose_neigh->number,
- (rose_neigh->loopback) ? "RSLOOP-0" : ax2asc(&rose_neigh->callsign),
+ (rose_neigh->loopback) ? "RSLOOP-0" : ax2asc(&rose_neigh->addr.dest),
rose_neigh->dev ? rose_neigh->dev->name : "???",
rose_neigh->count,
rose_neigh->use,
@@ -1043,9 +1032,9 @@ int rose_neigh_get_info(char *buffer, char **start, off_t offset, int length)
ax25_display_timer(&rose_neigh->t0timer) / HZ,
ax25_display_timer(&rose_neigh->ftimer) / HZ);
- if (rose_neigh->digipeat != NULL) {
- for (i = 0; i < rose_neigh->digipeat->ndigi; i++)
- len += sprintf(buffer + len, " %s", ax2asc(&rose_neigh->digipeat->calls[i]));
+ if (rose_neigh->addr.dcount != 0) {
+ for (i = 0; i < rose_neigh->addr.dcount; i++)
+ len += sprintf(buffer + len, " %s", ax2asc(&rose_neigh->addr.digipeater[i]));
}
len += sprintf(buffer + len, "\n");
diff --git a/net/rose/rose_subr.c b/net/rose/rose_subr.c
index 384347a0e..f881e5da5 100644
--- a/net/rose/rose_subr.c
+++ b/net/rose/rose_subr.c
@@ -119,8 +119,9 @@ void rose_write_internal(struct sock *sk, int frametype)
unsigned char lci1, lci2;
char buffer[100];
int len, faclen = 0;
+ int ax25_header_len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + 1;
- len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN + 1;
+ len = ax25_header_len + ROSE_MIN_LEN;
switch (frametype) {
case ROSE_CALL_REQUEST:
@@ -141,9 +142,9 @@ void rose_write_internal(struct sock *sk, int frametype)
/*
* Space for AX.25 header and PID.
*/
- skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + 1);
+ skb_reserve(skb, ax25_header_len);
- dptr = skb_put(skb, skb_tailroom(skb));
+ dptr = skb_put(skb, len - ax25_header_len);
lci1 = (sk->protinfo.rose->lci >> 8) & 0x0F;
lci2 = (sk->protinfo.rose->lci >> 0) & 0xFF;