diff options
Diffstat (limited to 'net/ax25')
| -rw-r--r-- | net/ax25/Kconfig | 69 | ||||
| -rw-r--r-- | net/ax25/TODO | 4 | ||||
| -rw-r--r-- | net/ax25/af_ax25.c | 634 | ||||
| -rw-r--r-- | net/ax25/ax25_addr.c | 59 | ||||
| -rw-r--r-- | net/ax25/ax25_dev.c | 20 | ||||
| -rw-r--r-- | net/ax25/ax25_ds_in.c | 4 | ||||
| -rw-r--r-- | net/ax25/ax25_ds_subr.c | 21 | ||||
| -rw-r--r-- | net/ax25/ax25_ds_timer.c | 27 | ||||
| -rw-r--r-- | net/ax25/ax25_iface.c | 145 | ||||
| -rw-r--r-- | net/ax25/ax25_in.c | 80 | ||||
| -rw-r--r-- | net/ax25/ax25_ip.c | 141 | ||||
| -rw-r--r-- | net/ax25/ax25_out.c | 44 | ||||
| -rw-r--r-- | net/ax25/ax25_route.c | 111 | ||||
| -rw-r--r-- | net/ax25/ax25_std_in.c | 2 | ||||
| -rw-r--r-- | net/ax25/ax25_std_subr.c | 2 | ||||
| -rw-r--r-- | net/ax25/ax25_std_timer.c | 8 | ||||
| -rw-r--r-- | net/ax25/ax25_subr.c | 22 | ||||
| -rw-r--r-- | net/ax25/ax25_timer.c | 65 | ||||
| -rw-r--r-- | net/ax25/ax25_uid.c | 71 | ||||
| -rw-r--r-- | net/ax25/sysctl_net_ax25.c | 190 |
20 files changed, 778 insertions, 941 deletions
diff --git a/net/ax25/Kconfig b/net/ax25/Kconfig index a8993a04172..705e53ef4af 100644 --- a/net/ax25/Kconfig +++ b/net/ax25/Kconfig @@ -1,30 +1,27 @@ # # Amateur Radio protocols and AX.25 device configuration # -# 19971130 Now in an own category to make correct compilation of the -# AX.25 stuff easier... -# Joerg Reuter DL1BKE <jreuter@yaina.de> -# 19980129 Moved to net/ax25/Config.in, sourcing device drivers. menuconfig HAMRADIO - depends on NET + depends on NET && !S390 bool "Amateur Radio support" help If you want to connect your Linux box to an amateur radio, answer Y - here. You want to read <http://www.tapr.org/tapr/html/pkthome.html> and - the AX25-HOWTO, available from <http://www.tldp.org/docs.html#howto>. + here. You want to read <http://www.tapr.org/> + and more specifically about AX.25 on Linux + <http://www.linux-ax25.org/>. Note that the answer to this question won't directly affect the kernel: saying N will just cause the configurator to skip all the questions about amateur radio. comment "Packet Radio protocols" - depends on HAMRADIO && NET + depends on HAMRADIO config AX25 tristate "Amateur Radio AX.25 Level 2 protocol" - depends on HAMRADIO && NET - ---help--- + depends on HAMRADIO + help This is the protocol used for computer communication over amateur radio. It is either used by itself for point-to-point links, or to carry other protocols such as tcp/ip. To use it, you need a device @@ -45,13 +42,14 @@ config AX25 check out the file <file:Documentation/networking/ax25.txt> in the kernel source. More information about digital amateur radio in general is on the WWW at - <http://www.tapr.org/tapr/html/pkthome.html>. + <http://www.tapr.org/>. To compile this driver as a module, choose M here: the module will be called ax25. config AX25_DAMA_SLAVE bool "AX.25 DAMA Slave support" + default y depends on AX25 help DAMA is a mechanism to prevent collisions when doing AX.25 @@ -59,24 +57,39 @@ config AX25_DAMA_SLAVE from clients (called "slaves") and redistributes it to other slaves. If you say Y here, your Linux box will act as a DAMA slave; this is transparent in that you don't have to do any special DAMA - configuration. (Linux cannot yet act as a DAMA server.) If unsure, - say N. + configuration. Linux cannot yet act as a DAMA server. This option + only compiles DAMA slave support into the kernel. It still needs to + be enabled at runtime. For more about DAMA see + <http://www.linux-ax25.org>. If unsure, say Y. + +# placeholder until implemented +config AX25_DAMA_MASTER + bool 'AX.25 DAMA Master support' + depends on AX25_DAMA_SLAVE && BROKEN + help + DAMA is a mechanism to prevent collisions when doing AX.25 + networking. A DAMA server (called "master") accepts incoming traffic + from clients (called "slaves") and redistributes it to other slaves. + If you say Y here, your Linux box will act as a DAMA master; this is + transparent in that you don't have to do any special DAMA + configuration. Linux cannot yet act as a DAMA server. This option + only compiles DAMA slave support into the kernel. It still needs to + be explicitly enabled, so if unsure, say Y. -# bool ' AX.25 DAMA Master support' CONFIG_AX25_DAMA_MASTER config NETROM tristate "Amateur Radio NET/ROM protocol" depends on AX25 - ---help--- + help NET/ROM is a network layer protocol on top of AX.25 useful for routing. A comprehensive listing of all the software for Linux amateur radio users as well as information about how to configure an AX.25 port is - contained in the AX25-HOWTO, available from - <http://www.tldp.org/docs.html#howto>. You also might want to - check out the file <file:Documentation/networking/ax25.txt>. More - information about digital amateur radio in general is on the WWW at - <http://www.tapr.org/tapr/html/pkthome.html>. + contained in the Linux Ham Wiki, available from + <http://www.linux-ax25.org>. You also might want to check out the + file <file:Documentation/networking/ax25.txt>. More information about + digital amateur radio in general is on the WWW at + <http://www.tapr.org/>. To compile this driver as a module, choose M here: the module will be called netrom. @@ -84,27 +97,25 @@ config NETROM config ROSE tristate "Amateur Radio X.25 PLP (Rose)" depends on AX25 - ---help--- + help The Packet Layer Protocol (PLP) is a way to route packets over X.25 connections in general and amateur radio AX.25 connections in particular, essentially an alternative to NET/ROM. A comprehensive listing of all the software for Linux amateur radio users as well as information about how to configure an AX.25 port is - contained in the AX25-HOWTO, available from - <http://www.tldp.org/docs.html#howto>. You also might want to - check out the file <file:Documentation/networking/ax25.txt>. More - information about digital amateur radio in general is on the WWW at - <http://www.tapr.org/tapr/html/pkthome.html>. + contained in the Linux Ham Wiki, available from + <http://www.linux-ax25.org>. You also might want to check out the + file <file:Documentation/networking/ax25.txt>. More information about + digital amateur radio in general is on the WWW at + <http://www.tapr.org/>. To compile this driver as a module, choose M here: the module will be called rose. - menu "AX.25 network device drivers" - depends on HAMRADIO && NET && AX25!=n + depends on HAMRADIO && AX25 source "drivers/net/hamradio/Kconfig" endmenu - diff --git a/net/ax25/TODO b/net/ax25/TODO index 4089c49e45c..69fb4e368d9 100644 --- a/net/ax25/TODO +++ b/net/ax25/TODO @@ -9,10 +9,6 @@ being used. Routes to a device being taken down might be deleted by ax25_rt_device_down but added by somebody else before the device has been deleted fully. -Massive amounts of lock_kernel / unlock_kernel are just a temporary solution to -get around the removal of SOCKOPS_WRAP. A serious locking strategy has to be -implemented. - The ax25_rt_find_route synopsys is pervert but I somehow had to deal with the race caused by the static variable in it's previous implementation. diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index dbf9b47681f..c35c3f48fc0 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -13,7 +13,6 @@ * Copyright (C) Hans Alblas PE1AYX (hans@esrac.ele.tue.nl) * Copyright (C) Frederic Rible F1OAT (frible@teaser.fr) */ -#include <linux/config.h> #include <linux/capability.h> #include <linux/module.h> #include <linux/errno.h> @@ -24,9 +23,9 @@ #include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> -#include <linux/smp_lock.h> #include <linux/sockios.h> #include <linux/net.h> +#include <linux/slab.h> #include <net/ax25.h> #include <linux/inet.h> #include <linux/netdevice.h> @@ -34,7 +33,6 @@ #include <linux/skbuff.h> #include <net/sock.h> #include <asm/uaccess.h> -#include <asm/system.h> #include <linux/fcntl.h> #include <linux/termios.h> /* For TIOCINQ/OUTQ */ #include <linux/mm.h> @@ -46,6 +44,7 @@ #include <linux/sysctl.h> #include <linux/init.h> #include <linux/spinlock.h> +#include <net/net_namespace.h> #include <net/tcp_states.h> #include <net/ip.h> #include <net/arp.h> @@ -82,16 +81,27 @@ static void ax25_kill_by_device(struct net_device *dev) { ax25_dev *ax25_dev; ax25_cb *s; - struct hlist_node *node; if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) return; spin_lock_bh(&ax25_list_lock); - ax25_for_each(s, node, &ax25_list) { +again: + ax25_for_each(s, &ax25_list) { if (s->ax25_dev == ax25_dev) { s->ax25_dev = NULL; + spin_unlock_bh(&ax25_list_lock); ax25_disconnect(s, ENETUNREACH); + spin_lock_bh(&ax25_list_lock); + + /* The entry could have been deleted from the + * list meanwhile and thus the next pointer is + * no longer valid. Play it safe and restart + * the scan. Forward progress is ensured + * because we set s->ax25_dev to NULL and we + * are never passed a NULL 'dev' argument. + */ + goto again; } } spin_unlock_bh(&ax25_list_lock); @@ -101,9 +111,12 @@ static void ax25_kill_by_device(struct net_device *dev) * Handle device status changes. */ static int ax25_device_event(struct notifier_block *this, unsigned long event, - void *ptr) + void *ptr) { - struct net_device *dev = (struct net_device *)ptr; + struct net_device *dev = netdev_notifier_info_to_dev(ptr); + + if (!net_eq(dev_net(dev), &init_net)) + return NOTIFY_DONE; /* Reject non AX.25 devices */ if (dev->type != ARPHRD_AX25) @@ -144,10 +157,9 @@ struct sock *ax25_find_listener(ax25_address *addr, int digi, struct net_device *dev, int type) { ax25_cb *s; - struct hlist_node *node; - spin_lock_bh(&ax25_list_lock); - ax25_for_each(s, node, &ax25_list) { + spin_lock(&ax25_list_lock); + ax25_for_each(s, &ax25_list) { if ((s->iamdigi && !digi) || (!s->iamdigi && digi)) continue; if (s->sk && !ax25cmp(&s->source_addr, addr) && @@ -155,12 +167,12 @@ struct sock *ax25_find_listener(ax25_address *addr, int digi, /* If device is null we match any device */ if (s->ax25_dev == NULL || s->ax25_dev->dev == dev) { sock_hold(s->sk); - spin_unlock_bh(&ax25_list_lock); + spin_unlock(&ax25_list_lock); return s->sk; } } } - spin_unlock_bh(&ax25_list_lock); + spin_unlock(&ax25_list_lock); return NULL; } @@ -173,10 +185,9 @@ struct sock *ax25_get_socket(ax25_address *my_addr, ax25_address *dest_addr, { struct sock *sk = NULL; ax25_cb *s; - struct hlist_node *node; - spin_lock_bh(&ax25_list_lock); - ax25_for_each(s, node, &ax25_list) { + spin_lock(&ax25_list_lock); + ax25_for_each(s, &ax25_list) { if (s->sk && !ax25cmp(&s->source_addr, my_addr) && !ax25cmp(&s->dest_addr, dest_addr) && s->sk->sk_type == type) { @@ -186,7 +197,7 @@ struct sock *ax25_get_socket(ax25_address *my_addr, ax25_address *dest_addr, } } - spin_unlock_bh(&ax25_list_lock); + spin_unlock(&ax25_list_lock); return sk; } @@ -199,10 +210,9 @@ ax25_cb *ax25_find_cb(ax25_address *src_addr, ax25_address *dest_addr, ax25_digi *digi, struct net_device *dev) { ax25_cb *s; - struct hlist_node *node; spin_lock_bh(&ax25_list_lock); - ax25_for_each(s, node, &ax25_list) { + ax25_for_each(s, &ax25_list) { if (s->sk && s->sk->sk_type != SOCK_SEQPACKET) continue; if (s->ax25_dev == NULL) @@ -228,14 +238,15 @@ ax25_cb *ax25_find_cb(ax25_address *src_addr, ax25_address *dest_addr, return NULL; } +EXPORT_SYMBOL(ax25_find_cb); + void ax25_send_to_raw(ax25_address *addr, struct sk_buff *skb, int proto) { ax25_cb *s; struct sk_buff *copy; - struct hlist_node *node; - spin_lock_bh(&ax25_list_lock); - ax25_for_each(s, node, &ax25_list) { + spin_lock(&ax25_list_lock); + ax25_for_each(s, &ax25_list) { if (s->sk != NULL && ax25cmp(&s->source_addr, addr) == 0 && s->sk->sk_type == SOCK_RAW && s->sk->sk_protocol == proto && @@ -247,7 +258,7 @@ void ax25_send_to_raw(ax25_address *addr, struct sk_buff *skb, int proto) kfree_skb(copy); } } - spin_unlock_bh(&ax25_list_lock); + spin_unlock(&ax25_list_lock); } /* @@ -262,9 +273,9 @@ static void ax25_destroy_timer(unsigned long data) { ax25_cb *ax25=(ax25_cb *)data; struct sock *sk; - + sk=ax25->sk; - + bh_lock_sock(sk); sock_hold(sk); ax25_destroy_socket(ax25); @@ -301,6 +312,9 @@ void ax25_destroy_socket(ax25_cb *ax25) /* Queue the unaccepted socket for death */ sock_orphan(skb->sk); + /* 9A4GL: hack to release unaccepted sockets */ + skb->sk->sk_state = TCP_LISTEN; + ax25_start_heartbeat(sax25); sax25->state = AX25_STATE_0; } @@ -311,13 +325,11 @@ void ax25_destroy_socket(ax25_cb *ax25) } if (ax25->sk != NULL) { - if (atomic_read(&ax25->sk->sk_wmem_alloc) || - atomic_read(&ax25->sk->sk_rmem_alloc)) { + if (sk_has_allocations(ax25->sk)) { /* Defer: outstanding buffers */ - init_timer(&ax25->dtimer); + setup_timer(&ax25->dtimer, ax25_destroy_timer, + (unsigned long)ax25); ax25->dtimer.expires = jiffies + 2 * HZ; - ax25->dtimer.function = ax25_destroy_timer; - ax25->dtimer.data = (unsigned long)ax25; add_timer(&ax25->dtimer); } else { struct sock *sk=ax25->sk; @@ -341,6 +353,7 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void __user *arg) ax25_dev *ax25_dev; ax25_cb *ax25; unsigned int k; + int ret = 0; if (copy_from_user(&ax25_ctl, arg, sizeof(ax25_ctl))) return -EFAULT; @@ -351,6 +364,9 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void __user *arg) if (ax25_ctl.digi_count > AX25_MAX_DIGIS) return -EINVAL; + if (ax25_ctl.arg > ULONG_MAX / HZ && ax25_ctl.cmd != AX25_KILL) + return -EINVAL; + digi.ndigi = ax25_ctl.digi_count; for (k = 0; k < digi.ndigi; k++) digi.calls[k] = ax25_ctl.digi_addr[k]; @@ -368,60 +384,87 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void __user *arg) ax25_disconnect(ax25, ENETRESET); break; - case AX25_WINDOW: - if (ax25->modulus == AX25_MODULUS) { - if (ax25_ctl.arg < 1 || ax25_ctl.arg > 7) - return -EINVAL; - } else { - if (ax25_ctl.arg < 1 || ax25_ctl.arg > 63) - return -EINVAL; - } - ax25->window = ax25_ctl.arg; - break; - - case AX25_T1: - if (ax25_ctl.arg < 1) - return -EINVAL; - ax25->rtt = (ax25_ctl.arg * HZ) / 2; - ax25->t1 = ax25_ctl.arg * HZ; - break; - - case AX25_T2: - if (ax25_ctl.arg < 1) - return -EINVAL; - ax25->t2 = ax25_ctl.arg * HZ; - break; - - case AX25_N2: - if (ax25_ctl.arg < 1 || ax25_ctl.arg > 31) - return -EINVAL; - ax25->n2count = 0; - ax25->n2 = ax25_ctl.arg; - break; - - case AX25_T3: - if (ax25_ctl.arg < 0) - return -EINVAL; - ax25->t3 = ax25_ctl.arg * HZ; - break; - - case AX25_IDLE: - if (ax25_ctl.arg < 0) - return -EINVAL; - ax25->idle = ax25_ctl.arg * 60 * HZ; - break; - - case AX25_PACLEN: - if (ax25_ctl.arg < 16 || ax25_ctl.arg > 65535) - return -EINVAL; - ax25->paclen = ax25_ctl.arg; - break; - - default: - return -EINVAL; + case AX25_WINDOW: + if (ax25->modulus == AX25_MODULUS) { + if (ax25_ctl.arg < 1 || ax25_ctl.arg > 7) + goto einval_put; + } else { + if (ax25_ctl.arg < 1 || ax25_ctl.arg > 63) + goto einval_put; + } + ax25->window = ax25_ctl.arg; + break; + + case AX25_T1: + if (ax25_ctl.arg < 1 || ax25_ctl.arg > ULONG_MAX / HZ) + goto einval_put; + ax25->rtt = (ax25_ctl.arg * HZ) / 2; + ax25->t1 = ax25_ctl.arg * HZ; + break; + + case AX25_T2: + if (ax25_ctl.arg < 1 || ax25_ctl.arg > ULONG_MAX / HZ) + goto einval_put; + ax25->t2 = ax25_ctl.arg * HZ; + break; + + case AX25_N2: + if (ax25_ctl.arg < 1 || ax25_ctl.arg > 31) + goto einval_put; + ax25->n2count = 0; + ax25->n2 = ax25_ctl.arg; + break; + + case AX25_T3: + if (ax25_ctl.arg > ULONG_MAX / HZ) + goto einval_put; + ax25->t3 = ax25_ctl.arg * HZ; + break; + + case AX25_IDLE: + if (ax25_ctl.arg > ULONG_MAX / (60 * HZ)) + goto einval_put; + + ax25->idle = ax25_ctl.arg * 60 * HZ; + break; + + case AX25_PACLEN: + if (ax25_ctl.arg < 16 || ax25_ctl.arg > 65535) + goto einval_put; + ax25->paclen = ax25_ctl.arg; + break; + + default: + goto einval_put; } - return 0; +out_put: + ax25_cb_put(ax25); + return ret; + +einval_put: + ret = -EINVAL; + goto out_put; +} + +static void ax25_fillin_cb_from_dev(ax25_cb *ax25, ax25_dev *ax25_dev) +{ + ax25->rtt = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_T1]) / 2; + ax25->t1 = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_T1]); + ax25->t2 = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_T2]); + ax25->t3 = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_T3]); + ax25->n2 = ax25_dev->values[AX25_VALUES_N2]; + ax25->paclen = ax25_dev->values[AX25_VALUES_PACLEN]; + ax25->idle = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_IDLE]); + ax25->backoff = ax25_dev->values[AX25_VALUES_BACKOFF]; + + if (ax25_dev->values[AX25_VALUES_AXDEFMODE]) { + ax25->modulus = AX25_EMODULUS; + ax25->window = ax25_dev->values[AX25_VALUES_EWINDOW]; + } else { + ax25->modulus = AX25_MODULUS; + ax25->window = ax25_dev->values[AX25_VALUES_WINDOW]; + } } /* @@ -433,39 +476,28 @@ void ax25_fillin_cb(ax25_cb *ax25, ax25_dev *ax25_dev) ax25->ax25_dev = ax25_dev; if (ax25->ax25_dev != NULL) { - ax25->rtt = ax25_dev->values[AX25_VALUES_T1] / 2; - ax25->t1 = ax25_dev->values[AX25_VALUES_T1]; - ax25->t2 = ax25_dev->values[AX25_VALUES_T2]; - ax25->t3 = ax25_dev->values[AX25_VALUES_T3]; - ax25->n2 = ax25_dev->values[AX25_VALUES_N2]; - ax25->paclen = ax25_dev->values[AX25_VALUES_PACLEN]; - ax25->idle = ax25_dev->values[AX25_VALUES_IDLE]; - ax25->backoff = ax25_dev->values[AX25_VALUES_BACKOFF]; - - if (ax25_dev->values[AX25_VALUES_AXDEFMODE]) { - ax25->modulus = AX25_EMODULUS; - ax25->window = ax25_dev->values[AX25_VALUES_EWINDOW]; - } else { - ax25->modulus = AX25_MODULUS; - ax25->window = ax25_dev->values[AX25_VALUES_WINDOW]; - } + ax25_fillin_cb_from_dev(ax25, ax25_dev); + return; + } + + /* + * No device, use kernel / AX.25 spec default values + */ + ax25->rtt = msecs_to_jiffies(AX25_DEF_T1) / 2; + ax25->t1 = msecs_to_jiffies(AX25_DEF_T1); + ax25->t2 = msecs_to_jiffies(AX25_DEF_T2); + ax25->t3 = msecs_to_jiffies(AX25_DEF_T3); + ax25->n2 = AX25_DEF_N2; + ax25->paclen = AX25_DEF_PACLEN; + ax25->idle = msecs_to_jiffies(AX25_DEF_IDLE); + ax25->backoff = AX25_DEF_BACKOFF; + + if (AX25_DEF_AXDEFMODE) { + ax25->modulus = AX25_EMODULUS; + ax25->window = AX25_DEF_EWINDOW; } else { - ax25->rtt = AX25_DEF_T1 / 2; - ax25->t1 = AX25_DEF_T1; - ax25->t2 = AX25_DEF_T2; - ax25->t3 = AX25_DEF_T3; - ax25->n2 = AX25_DEF_N2; - ax25->paclen = AX25_DEF_PACLEN; - ax25->idle = AX25_DEF_IDLE; - ax25->backoff = AX25_DEF_BACKOFF; - - if (AX25_DEF_AXDEFMODE) { - ax25->modulus = AX25_EMODULUS; - ax25->window = AX25_DEF_EWINDOW; - } else { - ax25->modulus = AX25_MODULUS; - ax25->window = AX25_DEF_WINDOW; - } + ax25->modulus = AX25_MODULUS; + ax25->window = AX25_DEF_WINDOW; } } @@ -476,10 +508,9 @@ ax25_cb *ax25_create_cb(void) { ax25_cb *ax25; - if ((ax25 = kmalloc(sizeof(*ax25), GFP_ATOMIC)) == NULL) + if ((ax25 = kzalloc(sizeof(*ax25), GFP_ATOMIC)) == NULL) return NULL; - memset(ax25, 0x00, sizeof(*ax25)); atomic_set(&ax25->refcount, 1); skb_queue_head_init(&ax25->write_queue); @@ -487,11 +518,7 @@ ax25_cb *ax25_create_cb(void) skb_queue_head_init(&ax25->ack_queue); skb_queue_head_init(&ax25->reseq_queue); - init_timer(&ax25->timer); - init_timer(&ax25->t1timer); - init_timer(&ax25->t2timer); - init_timer(&ax25->t3timer); - init_timer(&ax25->idletimer); + ax25_setup_timers(ax25); ax25_fillin_cb(ax25, NULL); @@ -506,21 +533,22 @@ ax25_cb *ax25_create_cb(void) */ static int ax25_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; ax25_cb *ax25; struct net_device *dev; char devname[IFNAMSIZ]; - int opt, res = 0; + unsigned long opt; + int res = 0; if (level != SOL_AX25) return -ENOPROTOOPT; - if (optlen < sizeof(int)) + if (optlen < sizeof(unsigned int)) return -EINVAL; - if (get_user(opt, (int __user *)optval)) + if (get_user(opt, (unsigned int __user *)optval)) return -EFAULT; lock_sock(sk); @@ -543,16 +571,16 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname, break; case AX25_T1: - if (opt < 1) { + if (opt < 1 || opt > ULONG_MAX / HZ) { res = -EINVAL; break; } - ax25->rtt = (opt * HZ) / 2; + ax25->rtt = (opt * HZ) >> 1; ax25->t1 = opt * HZ; break; case AX25_T2: - if (opt < 1) { + if (opt < 1 || opt > ULONG_MAX / HZ) { res = -EINVAL; break; } @@ -568,7 +596,7 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname, break; case AX25_T3: - if (opt < 1) { + if (opt < 1 || opt > ULONG_MAX / HZ) { res = -EINVAL; break; } @@ -576,7 +604,7 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname, break; case AX25_IDLE: - if (opt < 0) { + if (opt > ULONG_MAX / (60 * HZ)) { res = -EINVAL; break; } @@ -584,7 +612,7 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname, break; case AX25_BACKOFF: - if (opt < 0 || opt > 2) { + if (opt > 2) { res = -EINVAL; break; } @@ -613,15 +641,10 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname, case SO_BINDTODEVICE: if (optlen > IFNAMSIZ) - optlen=IFNAMSIZ; - if (copy_from_user(devname, optval, optlen)) { - res = -EFAULT; - break; - } + optlen = IFNAMSIZ; - dev = dev_get_by_name(devname); - if (dev == NULL) { - res = -ENODEV; + if (copy_from_user(devname, optval, optlen)) { + res = -EFAULT; break; } @@ -629,12 +652,18 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname, (sock->state != SS_UNCONNECTED || sk->sk_state == TCP_LISTEN)) { res = -EADDRNOTAVAIL; - dev_put(dev); + break; + } + + dev = dev_get_by_name(&init_net, devname); + if (!dev) { + res = -ENODEV; break; } ax25->ax25_dev = ax25_dev_ax25dev(dev); ax25_fillin_cb(ax25, ax25->ax25_dev); + dev_put(dev); break; default: @@ -771,11 +800,15 @@ static struct proto ax25_proto = { .obj_size = sizeof(struct sock), }; -static int ax25_create(struct socket *sock, int protocol) +static int ax25_create(struct net *net, struct socket *sock, int protocol, + int kern) { struct sock *sk; ax25_cb *ax25; + if (!net_eq(net, &init_net)) + return -EAFNOSUPPORT; + switch (sock->type) { case SOCK_DGRAM: if (protocol == 0 || protocol == PF_AX25) @@ -804,6 +837,7 @@ static int ax25_create(struct socket *sock, int protocol) case AX25_P_NETROM: if (ax25_protocol_is_registered(AX25_P_NETROM)) return -ESOCKTNOSUPPORT; + break; #endif #ifdef CONFIG_ROSE_MODULE case AX25_P_ROSE: @@ -821,7 +855,8 @@ static int ax25_create(struct socket *sock, int protocol) return -ESOCKTNOSUPPORT; } - if ((sk = sk_alloc(PF_AX25, GFP_ATOMIC, &ax25_proto, 1)) == NULL) + sk = sk_alloc(net, PF_AX25, GFP_ATOMIC, &ax25_proto); + if (sk == NULL) return -ENOMEM; ax25 = sk->sk_protinfo = ax25_create_cb(); @@ -846,7 +881,8 @@ struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev) struct sock *sk; ax25_cb *ax25, *oax25; - if ((sk = sk_alloc(PF_AX25, GFP_ATOMIC, osk->sk_prot, 1)) == NULL) + sk = sk_alloc(sock_net(osk), PF_AX25, GFP_ATOMIC, osk->sk_prot); + if (sk == NULL) return NULL; if ((ax25 = ax25_create_cb()) == NULL) { @@ -867,15 +903,12 @@ struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev) sock_init_data(NULL, sk); - sk->sk_destruct = ax25_free_sock; sk->sk_type = osk->sk_type; - sk->sk_socket = osk->sk_socket; sk->sk_priority = osk->sk_priority; sk->sk_protocol = osk->sk_protocol; sk->sk_rcvbuf = osk->sk_rcvbuf; sk->sk_sndbuf = osk->sk_sndbuf; sk->sk_state = TCP_ESTABLISHED; - sk->sk_sleep = osk->sk_sleep; sock_copy_flags(sk, osk); oax25 = ax25_sk(osk); @@ -897,16 +930,17 @@ struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev) ax25->source_addr = oax25->source_addr; if (oax25->digipeat != NULL) { - if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { + ax25->digipeat = kmemdup(oax25->digipeat, sizeof(ax25_digi), + GFP_ATOMIC); + if (ax25->digipeat == NULL) { sk_free(sk); ax25_cb_put(ax25); return NULL; } - - memcpy(ax25->digipeat, oax25->digipeat, sizeof(ax25_digi)); } sk->sk_protinfo = ax25; + sk->sk_destruct = ax25_free_sock; ax25->sk = sk; return sk; @@ -1009,21 +1043,18 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) int err = 0; if (addr_len != sizeof(struct sockaddr_ax25) && - addr_len != sizeof(struct full_sockaddr_ax25)) { - /* support for old structure may go away some time */ + addr_len != sizeof(struct full_sockaddr_ax25)) + /* support for old structure may go away some time + * ax25_bind(): uses old (6 digipeater) socket structure. + */ if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) || - (addr_len > sizeof(struct full_sockaddr_ax25))) { + (addr_len > sizeof(struct full_sockaddr_ax25))) return -EINVAL; - } - - printk(KERN_WARNING "ax25_bind(): %s uses old (6 digipeater) socket structure.\n", - current->comm); - } if (addr->fsa_ax25.sax25_family != AF_AX25) return -EINVAL; - user = ax25_findbyuid(current->euid); + user = ax25_findbyuid(current_euid()); if (user) { call = user->call; ax25_uid_put(user); @@ -1073,14 +1104,14 @@ done: out: release_sock(sk); - return 0; + return err; } /* * FIXME: nonblock behaviour looks like it may have a bug. */ -static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, - int addr_len, int flags) +static int __must_check ax25_connect(struct socket *sock, + struct sockaddr *uaddr, int addr_len, int flags) { struct sock *sk = sock->sk; ax25_cb *ax25 = ax25_sk(sk), *ax25t; @@ -1092,21 +1123,19 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, * some sanity checks. code further down depends on this */ - if (addr_len == sizeof(struct sockaddr_ax25)) { - /* support for this will go away in early 2.5.x */ - printk(KERN_WARNING "ax25_connect(): %s uses obsolete socket structure\n", - current->comm); - } - else if (addr_len != sizeof(struct full_sockaddr_ax25)) { - /* support for old structure may go away some time */ + if (addr_len == sizeof(struct sockaddr_ax25)) + /* support for this will go away in early 2.5.x + * ax25_connect(): uses obsolete socket structure + */ + ; + else if (addr_len != sizeof(struct full_sockaddr_ax25)) + /* support for old structure may go away some time + * ax25_connect(): uses old (6 digipeater) socket structure. + */ if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) || - (addr_len > sizeof(struct full_sockaddr_ax25))) { + (addr_len > sizeof(struct full_sockaddr_ax25))) return -EINVAL; - } - printk(KERN_WARNING "ax25_connect(): %s uses old (6 digipeater) socket structure.\n", - current->comm); - } if (fsa->fsa_ax25.sax25_family != AF_AX25) return -EINVAL; @@ -1118,22 +1147,22 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, switch (sk->sk_state) { case TCP_SYN_SENT: /* still trying */ err = -EINPROGRESS; - goto out; + goto out_release; case TCP_ESTABLISHED: /* connection established */ sock->state = SS_CONNECTED; - goto out; + goto out_release; case TCP_CLOSE: /* connection refused */ sock->state = SS_UNCONNECTED; err = -ECONNREFUSED; - goto out; + goto out_release; } } if (sk->sk_state == TCP_ESTABLISHED && sk->sk_type == SOCK_SEQPACKET) { err = -EISCONN; /* No reconnect on a seqpacket socket */ - goto out; + goto out_release; } sk->sk_state = TCP_CLOSE; @@ -1150,12 +1179,12 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, /* Valid number of digipeaters ? */ if (fsa->fsa_ax25.sax25_ndigis < 1 || fsa->fsa_ax25.sax25_ndigis > AX25_MAX_DIGIS) { err = -EINVAL; - goto out; + goto out_release; } if ((digi = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL) { err = -ENOBUFS; - goto out; + goto out_release; } digi->ndigi = fsa->fsa_ax25.sax25_ndigis; @@ -1185,7 +1214,7 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, current->comm); if ((err = ax25_rt_autobind(ax25, &fsa->fsa_ax25.sax25_call)) < 0) { kfree(digi); - goto out; + goto out_release; } ax25_fillin_cb(ax25, ax25->ax25_dev); @@ -1194,17 +1223,17 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, if (ax25->ax25_dev == NULL) { kfree(digi); err = -EHOSTUNREACH; - goto out; + goto out_release; } } if (sk->sk_type == SOCK_SEQPACKET && (ax25t=ax25_find_cb(&ax25->source_addr, &fsa->fsa_ax25.sax25_call, digi, - ax25->ax25_dev->dev))) { + ax25->ax25_dev->dev))) { kfree(digi); err = -EADDRINUSE; /* Already such a connection */ ax25_cb_put(ax25t); - goto out; + goto out_release; } ax25->dest_addr = fsa->fsa_ax25.sax25_call; @@ -1214,7 +1243,7 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, if (sk->sk_type != SOCK_SEQPACKET) { sock->state = SS_CONNECTED; sk->sk_state = TCP_ESTABLISHED; - goto out; + goto out_release; } /* Move to connecting socket, ax.25 lapb WAIT_UA.. */ @@ -1246,55 +1275,53 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, /* Now the loop */ if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) { err = -EINPROGRESS; - goto out; + goto out_release; } if (sk->sk_state == TCP_SYN_SENT) { - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); + DEFINE_WAIT(wait); - add_wait_queue(sk->sk_sleep, &wait); for (;;) { + prepare_to_wait(sk_sleep(sk), &wait, + TASK_INTERRUPTIBLE); if (sk->sk_state != TCP_SYN_SENT) break; - set_current_state(TASK_INTERRUPTIBLE); - release_sock(sk); - if (!signal_pending(tsk)) { + if (!signal_pending(current)) { + release_sock(sk); schedule(); lock_sock(sk); continue; } - current->state = TASK_RUNNING; - remove_wait_queue(sk->sk_sleep, &wait); - return -ERESTARTSYS; + err = -ERESTARTSYS; + break; } - current->state = TASK_RUNNING; - remove_wait_queue(sk->sk_sleep, &wait); + finish_wait(sk_sleep(sk), &wait); + + if (err) + goto out_release; } if (sk->sk_state != TCP_ESTABLISHED) { /* Not in ABM, not in WAIT_UA -> failed */ sock->state = SS_UNCONNECTED; err = sock_error(sk); /* Always set at this point */ - goto out; + goto out_release; } sock->state = SS_CONNECTED; - err=0; -out: + err = 0; +out_release: release_sock(sk); return err; } - static int ax25_accept(struct socket *sock, struct socket *newsock, int flags) { - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); struct sk_buff *skb; struct sock *newsk; + DEFINE_WAIT(wait); struct sock *sk; int err = 0; @@ -1319,39 +1346,36 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags) * The read queue this time is holding sockets ready to use * hooked into the SABM we saved */ - add_wait_queue(sk->sk_sleep, &wait); for (;;) { + prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); skb = skb_dequeue(&sk->sk_receive_queue); if (skb) break; - release_sock(sk); - current->state = TASK_INTERRUPTIBLE; if (flags & O_NONBLOCK) { - current->state = TASK_RUNNING; - remove_wait_queue(sk->sk_sleep, &wait); - return -EWOULDBLOCK; + err = -EWOULDBLOCK; + break; } - if (!signal_pending(tsk)) { + if (!signal_pending(current)) { + release_sock(sk); schedule(); lock_sock(sk); continue; } - current->state = TASK_RUNNING; - remove_wait_queue(sk->sk_sleep, &wait); - return -ERESTARTSYS; + err = -ERESTARTSYS; + break; } - current->state = TASK_RUNNING; - remove_wait_queue(sk->sk_sleep, &wait); + finish_wait(sk_sleep(sk), &wait); + + if (err) + goto out; newsk = skb->sk; - newsk->sk_socket = newsock; - newsk->sk_sleep = &newsock->wait; + sock_graft(newsk, newsock); /* Now attach up the new socket */ kfree_skb(skb); sk->sk_ack_backlog--; - newsock->sk = newsk; newsock->state = SS_CONNECTED; out: @@ -1369,6 +1393,7 @@ static int ax25_getname(struct socket *sock, struct sockaddr *uaddr, ax25_cb *ax25; int err = 0; + memset(fsa, 0, sizeof(*fsa)); lock_sock(sk); ax25 = ax25_sk(sk); @@ -1380,7 +1405,6 @@ static int ax25_getname(struct socket *sock, struct sockaddr *uaddr, fsa->fsa_ax25.sax25_family = AF_AX25; fsa->fsa_ax25.sax25_call = ax25->dest_addr; - fsa->fsa_ax25.sax25_ndigis = 0; if (ax25->digipeat != NULL) { ndigi = ax25->digipeat->ndigi; @@ -1411,12 +1435,11 @@ out: static int ax25_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len) { - struct sockaddr_ax25 *usax = (struct sockaddr_ax25 *)msg->msg_name; + DECLARE_SOCKADDR(struct sockaddr_ax25 *, usax, msg->msg_name); struct sock *sk = sock->sk; struct sockaddr_ax25 sax; struct sk_buff *skb; ax25_digi dtmp, *dp; - unsigned char *asmptr; ax25_cb *ax25; size_t size; int lv, err, addr_len = msg->msg_namelen; @@ -1447,28 +1470,27 @@ static int ax25_sendmsg(struct kiocb *iocb, struct socket *sock, err = -EMSGSIZE; goto out; } - + if (usax != NULL) { if (usax->sax25_family != AF_AX25) { err = -EINVAL; goto out; } - if (addr_len == sizeof(struct sockaddr_ax25)) { - printk(KERN_WARNING "ax25_sendmsg(): %s uses obsolete socket structure\n", - current->comm); - } - else if (addr_len != sizeof(struct full_sockaddr_ax25)) { - /* support for old structure may go away some time */ + if (addr_len == sizeof(struct sockaddr_ax25)) + /* ax25_sendmsg(): uses obsolete socket structure */ + ; + else if (addr_len != sizeof(struct full_sockaddr_ax25)) + /* support for old structure may go away some time + * ax25_sendmsg(): uses old (6 digipeater) + * socket structure. + */ if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) || - (addr_len > sizeof(struct full_sockaddr_ax25))) { - err = -EINVAL; + (addr_len > sizeof(struct full_sockaddr_ax25))) { + err = -EINVAL; goto out; } - printk(KERN_WARNING "ax25_sendmsg(): %s uses old (6 digipeater) socket structure.\n", - current->comm); - } if (addr_len > sizeof(struct sockaddr_ax25) && usax->sax25_ndigis != 0) { int ct = 0; @@ -1516,11 +1538,7 @@ static int ax25_sendmsg(struct kiocb *iocb, struct socket *sock, dp = ax25->digipeat; } - SOCK_DEBUG(sk, "AX.25: sendto: Addresses built.\n"); - /* Build a packet */ - SOCK_DEBUG(sk, "AX.25: sendto: building packet.\n"); - /* Assume the worst case */ size = len + ax25->ax25_dev->dev->hard_header_len; @@ -1530,8 +1548,6 @@ static int ax25_sendmsg(struct kiocb *iocb, struct socket *sock, skb_reserve(skb, size - len); - SOCK_DEBUG(sk, "AX.25: Appending user data\n"); - /* User data follows immediately after the AX.25 data */ if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { err = -EFAULT; @@ -1539,15 +1555,11 @@ static int ax25_sendmsg(struct kiocb *iocb, struct socket *sock, goto out; } - skb->nh.raw = skb->data; + skb_reset_network_header(skb); /* Add the PID if one is not supplied by the user in the skb */ - if (!ax25->pidincl) { - asmptr = skb_push(skb, 1); - *asmptr = sk->sk_protocol; - } - - SOCK_DEBUG(sk, "AX.25: Transmitting buffer\n"); + if (!ax25->pidincl) + *skb_push(skb, 1) = sk->sk_protocol; if (sk->sk_type == SOCK_SEQPACKET) { /* Connected mode sockets go via the LAPB machine */ @@ -1564,25 +1576,17 @@ static int ax25_sendmsg(struct kiocb *iocb, struct socket *sock, goto out; } - asmptr = skb_push(skb, 1 + ax25_addr_size(dp)); - - SOCK_DEBUG(sk, "Building AX.25 Header (dp=%p).\n", dp); + skb_push(skb, 1 + ax25_addr_size(dp)); - if (dp != NULL) - SOCK_DEBUG(sk, "Num digipeaters=%d\n", dp->ndigi); + /* Building AX.25 Header */ /* Build an AX.25 header */ - asmptr += (lv = ax25_addr_build(asmptr, &ax25->source_addr, - &sax.sax25_call, dp, - AX25_COMMAND, AX25_MODULUS)); - - SOCK_DEBUG(sk, "Built header (%d bytes)\n",lv); - - skb->h.raw = asmptr; + lv = ax25_addr_build(skb->data, &ax25->source_addr, &sax.sax25_call, + dp, AX25_COMMAND, AX25_MODULUS); - SOCK_DEBUG(sk, "base=%p pos=%p\n", skb->data, asmptr); + skb_set_transport_header(skb, lv); - *asmptr = AX25_UI; + *skb_transport_header(skb) = AX25_UI; /* Datagram frames go straight out of the door as UI */ ax25_queue_xmit(skb, ax25->ax25_dev->dev); @@ -1615,15 +1619,15 @@ static int ax25_recvmsg(struct kiocb *iocb, struct socket *sock, /* Now we can treat all alike */ skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, - flags & MSG_DONTWAIT, &err); + flags & MSG_DONTWAIT, &err); if (skb == NULL) goto out; if (!ax25_sk(sk)->pidincl) skb_pull(skb, 1); /* Remove PID */ - skb->h.raw = skb->data; - copied = skb->len; + skb_reset_transport_header(skb); + copied = skb->len; if (copied > size) { copied = size; @@ -1632,13 +1636,15 @@ static int ax25_recvmsg(struct kiocb *iocb, struct socket *sock, skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); - if (msg->msg_namelen != 0) { - struct sockaddr_ax25 *sax = (struct sockaddr_ax25 *)msg->msg_name; + if (msg->msg_name) { ax25_digi digi; ax25_address src; + const unsigned char *mac = skb_mac_header(skb); + DECLARE_SOCKADDR(struct sockaddr_ax25 *, sax, msg->msg_name); - ax25_addr_parse(skb->mac.raw+1, skb->data-skb->mac.raw-1, &src, NULL, &digi, NULL, NULL); - + memset(sax, 0, sizeof(struct full_sockaddr_ax25)); + ax25_addr_parse(mac + 1, skb->data - mac - 1, &src, NULL, + &digi, NULL, NULL); sax->sax25_family = AF_AX25; /* We set this correctly, even though we may not let the application know the digi calls further down (because it @@ -1681,7 +1687,8 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) switch (cmd) { case TIOCOUTQ: { long amount; - amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); + + amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk); if (amount < 0) amount = 0; res = put_user(amount, (int __user *)argp); @@ -1702,6 +1709,10 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) res = sock_get_timestamp(sk, argp); break; + case SIOCGSTAMPNS: + res = sock_get_timestampns(sk, argp); + break; + case SIOCAX25ADDUID: /* Add a uid to the uid/call map table */ case SIOCAX25DELUID: /* Delete a uid from the uid/call map table */ case SIOCAX25GETUID: { @@ -1724,7 +1735,7 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) res = -EFAULT; break; } - if (amount > AX25_NOUID_BLOCK) { + if (amount < 0 || amount > AX25_NOUID_BLOCK) { res = -EINVAL; break; } @@ -1767,8 +1778,8 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) ax25_info.idletimer = ax25_display_timer(&ax25->idletimer) / (60 * HZ); ax25_info.n2count = ax25->n2count; ax25_info.state = ax25->state; - ax25_info.rcv_q = atomic_read(&sk->sk_rmem_alloc); - ax25_info.snd_q = atomic_read(&sk->sk_wmem_alloc); + ax25_info.rcv_q = sk_rmem_alloc_get(sk); + ax25_info.snd_q = sk_wmem_alloc_get(sk); ax25_info.vs = ax25->vs; ax25_info.vr = ax25->vr; ax25_info.va = ax25->va; @@ -1839,36 +1850,26 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) #ifdef CONFIG_PROC_FS static void *ax25_info_start(struct seq_file *seq, loff_t *pos) + __acquires(ax25_list_lock) { - struct ax25_cb *ax25; - struct hlist_node *node; - int i = 0; - spin_lock_bh(&ax25_list_lock); - ax25_for_each(ax25, node, &ax25_list) { - if (i == *pos) - return ax25; - ++i; - } - return NULL; + return seq_hlist_start(&ax25_list, *pos); } static void *ax25_info_next(struct seq_file *seq, void *v, loff_t *pos) { - ++*pos; - - return hlist_entry( ((struct ax25_cb *)v)->ax25_node.next, - struct ax25_cb, ax25_node); + return seq_hlist_next(v, &ax25_list, pos); } - + static void ax25_info_stop(struct seq_file *seq, void *v) + __releases(ax25_list_lock) { spin_unlock_bh(&ax25_list_lock); } static int ax25_info_show(struct seq_file *seq, void *v) { - ax25_cb *ax25 = v; + ax25_cb *ax25 = hlist_entry(v, struct ax25_cb, ax25_node); char buf[11]; int k; @@ -1905,19 +1906,17 @@ static int ax25_info_show(struct seq_file *seq, void *v) ax25->paclen); if (ax25->sk != NULL) { - bh_lock_sock(ax25->sk); - seq_printf(seq," %d %d %ld\n", - atomic_read(&ax25->sk->sk_wmem_alloc), - atomic_read(&ax25->sk->sk_rmem_alloc), - ax25->sk->sk_socket != NULL ? SOCK_INODE(ax25->sk->sk_socket)->i_ino : 0L); - bh_unlock_sock(ax25->sk); + seq_printf(seq, " %d %d %lu\n", + sk_wmem_alloc_get(ax25->sk), + sk_rmem_alloc_get(ax25->sk), + sock_i_ino(ax25->sk)); } else { seq_puts(seq, " * * *\n"); } return 0; } -static struct seq_operations ax25_info_seqops = { +static const struct seq_operations ax25_info_seqops = { .start = ax25_info_start, .next = ax25_info_next, .stop = ax25_info_stop, @@ -1929,7 +1928,7 @@ static int ax25_info_open(struct inode *inode, struct file *file) return seq_open(file, &ax25_info_seqops); } -static struct file_operations ax25_info_fops = { +static const struct file_operations ax25_info_fops = { .owner = THIS_MODULE, .open = ax25_info_open, .read = seq_read, @@ -1939,7 +1938,7 @@ static struct file_operations ax25_info_fops = { #endif -static struct net_proto_family ax25_family_ops = { +static const struct net_proto_family ax25_family_ops = { .family = PF_AX25, .create = ax25_create, .owner = THIS_MODULE, @@ -1969,34 +1968,15 @@ static const struct proto_ops ax25_proto_ops = { /* * Called by socket.c on kernel start up */ -static struct packet_type ax25_packet_type = { - .type = __constant_htons(ETH_P_AX25), - .dev = NULL, /* All devices */ +static struct packet_type ax25_packet_type __read_mostly = { + .type = cpu_to_be16(ETH_P_AX25), .func = ax25_kiss_rcv, }; static struct notifier_block ax25_dev_notifier = { - .notifier_call =ax25_device_event, + .notifier_call = ax25_device_event, }; -EXPORT_SYMBOL(ax25_hard_header); -EXPORT_SYMBOL(ax25_rebuild_header); -EXPORT_SYMBOL(ax25_findbyuid); -EXPORT_SYMBOL(ax25_find_cb); -EXPORT_SYMBOL(ax25_linkfail_register); -EXPORT_SYMBOL(ax25_linkfail_release); -EXPORT_SYMBOL(ax25_listen_register); -EXPORT_SYMBOL(ax25_listen_release); -EXPORT_SYMBOL(ax25_protocol_register); -EXPORT_SYMBOL(ax25_protocol_release); -EXPORT_SYMBOL(ax25_send_frame); -EXPORT_SYMBOL(ax25_uid_policy); -EXPORT_SYMBOL(ax25cmp); -EXPORT_SYMBOL(ax2asc); -EXPORT_SYMBOL(asc2ax); -EXPORT_SYMBOL(null_ax25_address); -EXPORT_SYMBOL(ax25_display_timer); - static int __init ax25_init(void) { int rc = proto_register(&ax25_proto, 0); @@ -2007,11 +1987,11 @@ static int __init ax25_init(void) sock_register(&ax25_family_ops); dev_add_pack(&ax25_packet_type); register_netdevice_notifier(&ax25_dev_notifier); - ax25_register_sysctl(); - proc_net_fops_create("ax25_route", S_IRUGO, &ax25_route_fops); - proc_net_fops_create("ax25", S_IRUGO, &ax25_info_fops); - proc_net_fops_create("ax25_calls", S_IRUGO, &ax25_uid_fops); + proc_create("ax25_route", S_IRUGO, init_net.proc_net, + &ax25_route_fops); + proc_create("ax25", S_IRUGO, init_net.proc_net, &ax25_info_fops); + proc_create("ax25_calls", S_IRUGO, init_net.proc_net, &ax25_uid_fops); out: return rc; } @@ -2025,19 +2005,19 @@ MODULE_ALIAS_NETPROTO(PF_AX25); static void __exit ax25_exit(void) { - proc_net_remove("ax25_route"); - proc_net_remove("ax25"); - proc_net_remove("ax25_calls"); - ax25_rt_free(); - ax25_uid_free(); - ax25_dev_free(); + remove_proc_entry("ax25_route", init_net.proc_net); + remove_proc_entry("ax25", init_net.proc_net); + remove_proc_entry("ax25_calls", init_net.proc_net); - ax25_unregister_sysctl(); unregister_netdevice_notifier(&ax25_dev_notifier); dev_remove_pack(&ax25_packet_type); sock_unregister(PF_AX25); proto_unregister(&ax25_proto); + + ax25_rt_free(); + ax25_uid_free(); + ax25_dev_free(); } module_exit(ax25_exit); diff --git a/net/ax25/ax25_addr.c b/net/ax25/ax25_addr.c index 0164a155b8c..e7c9b0ea17a 100644 --- a/net/ax25/ax25_addr.c +++ b/net/ax25/ax25_addr.c @@ -11,7 +11,7 @@ #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> +#include <linux/module.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> @@ -22,21 +22,31 @@ #include <linux/skbuff.h> #include <net/sock.h> #include <asm/uaccess.h> -#include <asm/system.h> #include <linux/fcntl.h> #include <linux/mm.h> #include <linux/interrupt.h> /* - * The null address is defined as a callsign of all spaces with an - * SSID of zero. + * The default broadcast address of an interface is QST-0; the default address + * is LINUX-1. The null address is defined as a callsign of all spaces with + * an SSID of zero. */ -ax25_address null_ax25_address = {{0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00}}; + +const ax25_address ax25_bcast = + {{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, 0 << 1}}; +const ax25_address ax25_defaddr = + {{'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, 1 << 1}}; +const ax25_address null_ax25_address = + {{' ' << 1, ' ' << 1, ' ' << 1, ' ' << 1, ' ' << 1, ' ' << 1, 0 << 1}}; + +EXPORT_SYMBOL_GPL(ax25_bcast); +EXPORT_SYMBOL_GPL(ax25_defaddr); +EXPORT_SYMBOL(null_ax25_address); /* * ax25 -> ascii conversion */ -char *ax2asc(char *buf, ax25_address *a) +char *ax2asc(char *buf, const ax25_address *a) { char c, *s; int n; @@ -64,12 +74,14 @@ char *ax2asc(char *buf, ax25_address *a) } +EXPORT_SYMBOL(ax2asc); + /* * ascii -> ax25 conversion */ -void asc2ax(ax25_address *addr, char *callsign) +void asc2ax(ax25_address *addr, const char *callsign) { - char *s; + const char *s; int n; for (s = callsign, n = 0; n < 6; n++) { @@ -97,10 +109,12 @@ void asc2ax(ax25_address *addr, char *callsign) addr->ax25_call[6] &= 0x1E; } +EXPORT_SYMBOL(asc2ax); + /* * Compare two ax.25 addresses */ -int ax25cmp(ax25_address *a, ax25_address *b) +int ax25cmp(const ax25_address *a, const ax25_address *b) { int ct = 0; @@ -110,16 +124,18 @@ int ax25cmp(ax25_address *a, ax25_address *b) ct++; } - if ((a->ax25_call[ct] & 0x1E) == (b->ax25_call[ct] & 0x1E)) /* SSID without control bit */ - return 0; + if ((a->ax25_call[ct] & 0x1E) == (b->ax25_call[ct] & 0x1E)) /* SSID without control bit */ + return 0; - return 2; /* Partial match */ + return 2; /* Partial match */ } +EXPORT_SYMBOL(ax25cmp); + /* * Compare two AX.25 digipeater paths. */ -int ax25digicmp(ax25_digi *digi1, ax25_digi *digi2) +int ax25digicmp(const ax25_digi *digi1, const ax25_digi *digi2) { int i; @@ -140,7 +156,9 @@ int ax25digicmp(ax25_digi *digi1, ax25_digi *digi2) * Given an AX.25 address pull of to, from, digi list, command/response and the start of data * */ -unsigned char *ax25_addr_parse(unsigned char *buf, int len, ax25_address *src, ax25_address *dest, ax25_digi *digi, int *flags, int *dama) +const unsigned char *ax25_addr_parse(const unsigned char *buf, int len, + ax25_address *src, ax25_address *dest, ax25_digi *digi, int *flags, + int *dama) { int d = 0; @@ -171,8 +189,10 @@ unsigned char *ax25_addr_parse(unsigned char *buf, int len, ax25_address *src, a digi->ndigi = 0; while (!(buf[-1] & AX25_EBIT)) { - if (d >= AX25_MAX_DIGIS) return NULL; /* Max of 6 digis */ - if (len < 7) return NULL; /* Short packet */ + if (d >= AX25_MAX_DIGIS) + return NULL; + if (len < AX25_ADDR_LEN) + return NULL; memcpy(&digi->calls[d], buf, AX25_ADDR_LEN); digi->ndigi = d + 1; @@ -195,7 +215,8 @@ unsigned char *ax25_addr_parse(unsigned char *buf, int len, ax25_address *src, a /* * Assemble an AX.25 header from the bits */ -int ax25_addr_build(unsigned char *buf, ax25_address *src, ax25_address *dest, ax25_digi *d, int flag, int modulus) +int ax25_addr_build(unsigned char *buf, const ax25_address *src, + const ax25_address *dest, const ax25_digi *d, int flag, int modulus) { int len = 0; int ct = 0; @@ -252,7 +273,7 @@ int ax25_addr_build(unsigned char *buf, ax25_address *src, ax25_address *dest, a return len; } -int ax25_addr_size(ax25_digi *dp) +int ax25_addr_size(const ax25_digi *dp) { if (dp == NULL) return 2 * AX25_ADDR_LEN; @@ -263,7 +284,7 @@ int ax25_addr_size(ax25_digi *dp) /* * Reverse Digipeat List. May not pass both parameters as same struct */ -void ax25_digi_invert(ax25_digi *in, ax25_digi *out) +void ax25_digi_invert(const ax25_digi *in, ax25_digi *out) { int ct; diff --git a/net/ax25/ax25_dev.c b/net/ax25/ax25_dev.c index dab77efe34a..3d106767b27 100644 --- a/net/ax25/ax25_dev.c +++ b/net/ax25/ax25_dev.c @@ -6,13 +6,12 @@ * * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) */ -#include <linux/config.h> #include <linux/errno.h> #include <linux/types.h> #include <linux/socket.h> +#include <linux/slab.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> @@ -25,7 +24,6 @@ #include <linux/skbuff.h> #include <net/sock.h> #include <asm/uaccess.h> -#include <asm/system.h> #include <linux/fcntl.h> #include <linux/mm.h> #include <linux/interrupt.h> @@ -56,15 +54,11 @@ void ax25_dev_device_up(struct net_device *dev) { ax25_dev *ax25_dev; - if ((ax25_dev = kmalloc(sizeof(*ax25_dev), GFP_ATOMIC)) == NULL) { + if ((ax25_dev = kzalloc(sizeof(*ax25_dev), GFP_ATOMIC)) == NULL) { printk(KERN_ERR "AX.25: ax25_dev_device_up - out of memory\n"); return; } - ax25_unregister_sysctl(); - - memset(ax25_dev, 0x00, sizeof(*ax25_dev)); - dev->ax25_ptr = ax25_dev; ax25_dev->dev = dev; dev_hold(dev); @@ -86,7 +80,7 @@ void ax25_dev_device_up(struct net_device *dev) ax25_dev->values[AX25_VALUES_DS_TIMEOUT]= AX25_DEF_DS_TIMEOUT; #if defined(CONFIG_AX25_DAMA_SLAVE) || defined(CONFIG_AX25_DAMA_MASTER) - init_timer(&ax25_dev->dama.slave_timer); + ax25_ds_setup_timer(ax25_dev); #endif spin_lock_bh(&ax25_dev_lock); @@ -94,7 +88,7 @@ void ax25_dev_device_up(struct net_device *dev) ax25_dev_list = ax25_dev; spin_unlock_bh(&ax25_dev_lock); - ax25_register_sysctl(); + ax25_register_dev_sysctl(ax25_dev); } void ax25_dev_device_down(struct net_device *dev) @@ -104,7 +98,7 @@ void ax25_dev_device_down(struct net_device *dev) if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) return; - ax25_unregister_sysctl(); + ax25_unregister_dev_sysctl(ax25_dev); spin_lock_bh(&ax25_dev_lock); @@ -124,7 +118,6 @@ void ax25_dev_device_down(struct net_device *dev) spin_unlock_bh(&ax25_dev_lock); dev_put(dev); kfree(ax25_dev); - ax25_register_sysctl(); return; } @@ -134,7 +127,6 @@ void ax25_dev_device_down(struct net_device *dev) spin_unlock_bh(&ax25_dev_lock); dev_put(dev); kfree(ax25_dev); - ax25_register_sysctl(); return; } @@ -142,8 +134,6 @@ void ax25_dev_device_down(struct net_device *dev) } spin_unlock_bh(&ax25_dev_lock); dev->ax25_ptr = NULL; - - ax25_register_sysctl(); } int ax25_fwd_ioctl(unsigned int cmd, struct ax25_fwd_struct *fwd) diff --git a/net/ax25/ax25_ds_in.c b/net/ax25/ax25_ds_in.c index edcaa897027..9bd31e88aec 100644 --- a/net/ax25/ax25_ds_in.c +++ b/net/ax25/ax25_ds_in.c @@ -12,7 +12,6 @@ #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> @@ -24,7 +23,6 @@ #include <net/sock.h> #include <net/tcp_states.h> #include <asm/uaccess.h> -#include <asm/system.h> #include <linux/fcntl.h> #include <linux/mm.h> #include <linux/interrupt.h> @@ -76,7 +74,7 @@ static int ax25_ds_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int framet } ax25_dama_on(ax25); - /* according to DK4EG´s spec we are required to + /* according to DK4EG's spec we are required to * send a RR RESPONSE FINAL NR=0. */ diff --git a/net/ax25/ax25_ds_subr.c b/net/ax25/ax25_ds_subr.c index 1d4ab641f82..e05bd57b5af 100644 --- a/net/ax25/ax25_ds_subr.c +++ b/net/ax25/ax25_ds_subr.c @@ -12,19 +12,18 @@ #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> #include <linux/spinlock.h> #include <linux/net.h> +#include <linux/gfp.h> #include <net/ax25.h> #include <linux/inet.h> #include <linux/netdevice.h> #include <linux/skbuff.h> #include <net/sock.h> #include <asm/uaccess.h> -#include <asm/system.h> #include <linux/fcntl.h> #include <linux/mm.h> #include <linux/interrupt.h> @@ -40,9 +39,8 @@ void ax25_ds_nr_error_recovery(ax25_cb *ax25) void ax25_ds_enquiry_response(ax25_cb *ax25) { ax25_cb *ax25o; - struct hlist_node *node; - /* Please note that neither DK4EG´s nor DG2FEF´s + /* Please note that neither DK4EG's nor DG2FEF's * DAMA spec mention the following behaviour as seen * with TheFirmware: * @@ -80,8 +78,8 @@ void ax25_ds_enquiry_response(ax25_cb *ax25) ax25_start_t3timer(ax25); ax25_ds_set_timer(ax25->ax25_dev); - spin_lock_bh(&ax25_list_lock); - ax25_for_each(ax25o, node, &ax25_list) { + spin_lock(&ax25_list_lock); + ax25_for_each(ax25o, &ax25_list) { if (ax25o == ax25) continue; @@ -106,7 +104,7 @@ void ax25_ds_enquiry_response(ax25_cb *ax25) if (ax25o->state != AX25_STATE_0) ax25_start_t3timer(ax25o); } - spin_unlock_bh(&ax25_list_lock); + spin_unlock(&ax25_list_lock); } void ax25_ds_establish_data_link(ax25_cb *ax25) @@ -137,7 +135,7 @@ static void ax25_kiss_cmd(ax25_dev *ax25_dev, unsigned char cmd, unsigned char p if ((skb = alloc_skb(2, GFP_ATOMIC)) == NULL) return; - skb->nh.raw = skb->data; + skb_reset_network_header(skb); p = skb_put(skb, 2); *p++ = cmd; @@ -160,15 +158,14 @@ static int ax25_check_dama_slave(ax25_dev *ax25_dev) { ax25_cb *ax25; int res = 0; - struct hlist_node *node; - spin_lock_bh(&ax25_list_lock); - ax25_for_each(ax25, node, &ax25_list) + spin_lock(&ax25_list_lock); + ax25_for_each(ax25, &ax25_list) if (ax25->ax25_dev == ax25_dev && (ax25->condition & AX25_COND_DAMA_MODE) && ax25->state > AX25_STATE_1) { res = 1; break; } - spin_unlock_bh(&ax25_list_lock); + spin_unlock(&ax25_list_lock); return res; } diff --git a/net/ax25/ax25_ds_timer.c b/net/ax25/ax25_ds_timer.c index 061083efc1d..951cd57bb07 100644 --- a/net/ax25/ax25_ds_timer.c +++ b/net/ax25/ax25_ds_timer.c @@ -25,7 +25,6 @@ #include <linux/skbuff.h> #include <net/sock.h> #include <asm/uaccess.h> -#include <asm/system.h> #include <linux/fcntl.h> #include <linux/mm.h> #include <linux/interrupt.h> @@ -40,13 +39,10 @@ static void ax25_ds_timeout(unsigned long); * 1/10th of a second. */ -static void ax25_ds_add_timer(ax25_dev *ax25_dev) +void ax25_ds_setup_timer(ax25_dev *ax25_dev) { - struct timer_list *t = &ax25_dev->dama.slave_timer; - t->data = (unsigned long) ax25_dev; - t->function = &ax25_ds_timeout; - t->expires = jiffies + HZ; - add_timer(t); + setup_timer(&ax25_dev->dama.slave_timer, ax25_ds_timeout, + (unsigned long)ax25_dev); } void ax25_ds_del_timer(ax25_dev *ax25_dev) @@ -60,9 +56,9 @@ void ax25_ds_set_timer(ax25_dev *ax25_dev) if (ax25_dev == NULL) /* paranoia */ return; - del_timer(&ax25_dev->dama.slave_timer); - ax25_dev->dama.slave_timeout = ax25_dev->values[AX25_VALUES_DS_TIMEOUT] / 10; - ax25_ds_add_timer(ax25_dev); + ax25_dev->dama.slave_timeout = + msecs_to_jiffies(ax25_dev->values[AX25_VALUES_DS_TIMEOUT]) / 10; + mod_timer(&ax25_dev->dama.slave_timer, jiffies + HZ); } /* @@ -74,7 +70,6 @@ static void ax25_ds_timeout(unsigned long arg) { ax25_dev *ax25_dev = (struct ax25_dev *) arg; ax25_cb *ax25; - struct hlist_node *node; if (ax25_dev == NULL || !ax25_dev->dama.slave) return; /* Yikes! */ @@ -84,15 +79,15 @@ static void ax25_ds_timeout(unsigned long arg) return; } - spin_lock_bh(&ax25_list_lock); - ax25_for_each(ax25, node, &ax25_list) { + spin_lock(&ax25_list_lock); + ax25_for_each(ax25, &ax25_list) { if (ax25->ax25_dev != ax25_dev || !(ax25->condition & AX25_COND_DAMA_MODE)) continue; ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); ax25_disconnect(ax25, ETIMEDOUT); } - spin_unlock_bh(&ax25_list_lock); + spin_unlock(&ax25_list_lock); ax25_dev_dama_off(ax25_dev); } @@ -115,8 +110,8 @@ void ax25_ds_heartbeat_expiry(ax25_cb *ax25) if (sk) { sock_hold(sk); ax25_destroy_socket(ax25); - sock_put(sk); bh_unlock_sock(sk); + sock_put(sk); } else ax25_destroy_socket(ax25); return; @@ -129,7 +124,7 @@ void ax25_ds_heartbeat_expiry(ax25_cb *ax25) */ if (sk != NULL) { if (atomic_read(&sk->sk_rmem_alloc) < - (sk->sk_rcvbuf / 2) && + (sk->sk_rcvbuf >> 1) && (ax25->condition & AX25_COND_OWN_RX_BUSY)) { ax25->condition &= ~AX25_COND_OWN_RX_BUSY; ax25->condition &= ~AX25_COND_ACK_PENDING; diff --git a/net/ax25/ax25_iface.c b/net/ax25/ax25_iface.c index d68aff10072..7f16e8a931b 100644 --- a/net/ax25/ax25_iface.c +++ b/net/ax25/ax25_iface.c @@ -6,40 +6,32 @@ * * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) */ -#include <linux/config.h> #include <linux/errno.h> #include <linux/types.h> #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> +#include <linux/module.h> #include <linux/spinlock.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> #include <linux/net.h> +#include <linux/slab.h> #include <net/ax25.h> #include <linux/inet.h> #include <linux/netdevice.h> #include <linux/skbuff.h> #include <net/sock.h> #include <asm/uaccess.h> -#include <asm/system.h> #include <linux/fcntl.h> #include <linux/mm.h> #include <linux/interrupt.h> -static struct protocol_struct { - struct protocol_struct *next; - unsigned int pid; - int (*func)(struct sk_buff *, ax25_cb *); -} *protocol_list = NULL; +static struct ax25_protocol *protocol_list; static DEFINE_RWLOCK(protocol_list_lock); -static struct linkfail_struct { - struct linkfail_struct *next; - void (*func)(ax25_cb *, int); -} *linkfail_list = NULL; +static HLIST_HEAD(ax25_linkfail_list); static DEFINE_SPINLOCK(linkfail_lock); static struct listen_struct { @@ -49,112 +41,66 @@ static struct listen_struct { } *listen_list = NULL; static DEFINE_SPINLOCK(listen_lock); -int ax25_protocol_register(unsigned int pid, - int (*func)(struct sk_buff *, ax25_cb *)) +/* + * Do not register the internal protocols AX25_P_TEXT, AX25_P_SEGMENT, + * AX25_P_IP or AX25_P_ARP ... + */ +void ax25_register_pid(struct ax25_protocol *ap) { - struct protocol_struct *protocol; - - if (pid == AX25_P_TEXT || pid == AX25_P_SEGMENT) - return 0; -#ifdef CONFIG_INET - if (pid == AX25_P_IP || pid == AX25_P_ARP) - return 0; -#endif - if ((protocol = kmalloc(sizeof(*protocol), GFP_ATOMIC)) == NULL) - return 0; - - protocol->pid = pid; - protocol->func = func; - - write_lock(&protocol_list_lock); - protocol->next = protocol_list; - protocol_list = protocol; - write_unlock(&protocol_list_lock); - - return 1; + write_lock_bh(&protocol_list_lock); + ap->next = protocol_list; + protocol_list = ap; + write_unlock_bh(&protocol_list_lock); } +EXPORT_SYMBOL_GPL(ax25_register_pid); + void ax25_protocol_release(unsigned int pid) { - struct protocol_struct *s, *protocol; + struct ax25_protocol *protocol; - write_lock(&protocol_list_lock); + write_lock_bh(&protocol_list_lock); protocol = protocol_list; - if (protocol == NULL) { - write_unlock(&protocol_list_lock); - return; - } + if (protocol == NULL) + goto out; if (protocol->pid == pid) { protocol_list = protocol->next; - write_unlock(&protocol_list_lock); - kfree(protocol); - return; + goto out; } while (protocol != NULL && protocol->next != NULL) { if (protocol->next->pid == pid) { - s = protocol->next; protocol->next = protocol->next->next; - write_unlock(&protocol_list_lock); - kfree(s); - return; + goto out; } protocol = protocol->next; } - write_unlock(&protocol_list_lock); +out: + write_unlock_bh(&protocol_list_lock); } -int ax25_linkfail_register(void (*func)(ax25_cb *, int)) -{ - struct linkfail_struct *linkfail; - - if ((linkfail = kmalloc(sizeof(*linkfail), GFP_ATOMIC)) == NULL) - return 0; - - linkfail->func = func; +EXPORT_SYMBOL(ax25_protocol_release); +void ax25_linkfail_register(struct ax25_linkfail *lf) +{ spin_lock_bh(&linkfail_lock); - linkfail->next = linkfail_list; - linkfail_list = linkfail; + hlist_add_head(&lf->lf_node, &ax25_linkfail_list); spin_unlock_bh(&linkfail_lock); - - return 1; } -void ax25_linkfail_release(void (*func)(ax25_cb *, int)) -{ - struct linkfail_struct *s, *linkfail; +EXPORT_SYMBOL(ax25_linkfail_register); +void ax25_linkfail_release(struct ax25_linkfail *lf) +{ spin_lock_bh(&linkfail_lock); - linkfail = linkfail_list; - if (linkfail == NULL) { - spin_unlock_bh(&linkfail_lock); - return; - } - - if (linkfail->func == func) { - linkfail_list = linkfail->next; - spin_unlock_bh(&linkfail_lock); - kfree(linkfail); - return; - } - - while (linkfail != NULL && linkfail->next != NULL) { - if (linkfail->next->func == func) { - s = linkfail->next; - linkfail->next = linkfail->next->next; - spin_unlock_bh(&linkfail_lock); - kfree(s); - return; - } - - linkfail = linkfail->next; - } + hlist_del_init(&lf->lf_node); spin_unlock_bh(&linkfail_lock); } +EXPORT_SYMBOL(ax25_linkfail_release); + int ax25_listen_register(ax25_address *callsign, struct net_device *dev) { struct listen_struct *listen; @@ -163,7 +109,7 @@ int ax25_listen_register(ax25_address *callsign, struct net_device *dev) return 0; if ((listen = kmalloc(sizeof(*listen), GFP_ATOMIC)) == NULL) - return 0; + return -ENOMEM; listen->callsign = *callsign; listen->dev = dev; @@ -173,9 +119,11 @@ int ax25_listen_register(ax25_address *callsign, struct net_device *dev) listen_list = listen; spin_unlock_bh(&listen_lock); - return 1; + return 0; } +EXPORT_SYMBOL(ax25_listen_register); + void ax25_listen_release(ax25_address *callsign, struct net_device *dev) { struct listen_struct *s, *listen; @@ -208,10 +156,12 @@ void ax25_listen_release(ax25_address *callsign, struct net_device *dev) spin_unlock_bh(&listen_lock); } +EXPORT_SYMBOL(ax25_listen_release); + int (*ax25_protocol_function(unsigned int pid))(struct sk_buff *, ax25_cb *) { int (*res)(struct sk_buff *, ax25_cb *) = NULL; - struct protocol_struct *protocol; + struct ax25_protocol *protocol; read_lock(&protocol_list_lock); for (protocol = protocol_list; protocol != NULL; protocol = protocol->next) @@ -230,7 +180,8 @@ int ax25_listen_mine(ax25_address *callsign, struct net_device *dev) spin_lock_bh(&listen_lock); for (listen = listen_list; listen != NULL; listen = listen->next) - if (ax25cmp(&listen->callsign, callsign) == 0 && (listen->dev == dev || listen->dev == NULL)) { + if (ax25cmp(&listen->callsign, callsign) == 0 && + (listen->dev == dev || listen->dev == NULL)) { spin_unlock_bh(&listen_lock); return 1; } @@ -241,26 +192,26 @@ int ax25_listen_mine(ax25_address *callsign, struct net_device *dev) void ax25_link_failed(ax25_cb *ax25, int reason) { - struct linkfail_struct *linkfail; + struct ax25_linkfail *lf; spin_lock_bh(&linkfail_lock); - for (linkfail = linkfail_list; linkfail != NULL; linkfail = linkfail->next) - (linkfail->func)(ax25, reason); + hlist_for_each_entry(lf, &ax25_linkfail_list, lf_node) + lf->func(ax25, reason); spin_unlock_bh(&linkfail_lock); } int ax25_protocol_is_registered(unsigned int pid) { - struct protocol_struct *protocol; + struct ax25_protocol *protocol; int res = 0; - read_lock(&protocol_list_lock); + read_lock_bh(&protocol_list_lock); for (protocol = protocol_list; protocol != NULL; protocol = protocol->next) if (protocol->pid == pid) { res = 1; break; } - read_unlock(&protocol_list_lock); + read_unlock_bh(&protocol_list_lock); return res; } diff --git a/net/ax25/ax25_in.c b/net/ax25/ax25_in.c index 4cf87540fb3..7ed8ab72481 100644 --- a/net/ax25/ax25_in.c +++ b/net/ax25/ax25_in.c @@ -14,11 +14,11 @@ #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> #include <linux/net.h> +#include <linux/slab.h> #include <net/ax25.h> #include <linux/inet.h> #include <linux/netdevice.h> @@ -27,7 +27,6 @@ #include <net/sock.h> #include <net/tcp_states.h> #include <asm/uaccess.h> -#include <asm/system.h> #include <linux/fcntl.h> #include <linux/mm.h> #include <linux/interrupt.h> @@ -62,12 +61,14 @@ static int ax25_rx_fragment(ax25_cb *ax25, struct sk_buff *skb) skb_reserve(skbn, AX25_MAX_HEADER_LEN); skbn->dev = ax25->ax25_dev->dev; - skbn->h.raw = skbn->data; - skbn->nh.raw = skbn->data; + skb_reset_network_header(skbn); + skb_reset_transport_header(skbn); /* Copy data from the fragments */ while ((skbo = skb_dequeue(&ax25->frag_queue)) != NULL) { - memcpy(skb_put(skbn, skbo->len), skbo->data, skbo->len); + skb_copy_from_linear_data(skbo, + skb_put(skbn, skbo->len), + skbo->len); kfree_skb(skbo); } @@ -102,8 +103,8 @@ static int ax25_rx_fragment(ax25_cb *ax25, struct sk_buff *skb) int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb) { int (*func)(struct sk_buff *, ax25_cb *); - volatile int queued = 0; unsigned char pid; + int queued = 0; if (skb == NULL) return 0; @@ -123,8 +124,8 @@ int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb) } skb_pull(skb, 1); /* Remove PID */ - skb->mac.raw = skb->nh.raw; - skb->nh.raw = skb->data; + skb->mac_header = skb->network_header; + skb_reset_network_header(skb); skb->dev = ax25->ax25_dev->dev; skb->pkt_type = PACKET_HOST; skb->protocol = htons(ETH_P_IP); @@ -197,21 +198,17 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, * Process the AX.25/LAPB frame. */ - skb->h.raw = skb->data; + skb_reset_transport_header(skb); - if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) { - kfree_skb(skb); - return 0; - } + if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) + goto free; /* * Parse the address header. */ - if (ax25_addr_parse(skb->data, skb->len, &src, &dest, &dp, &type, &dama) == NULL) { - kfree_skb(skb); - return 0; - } + if (ax25_addr_parse(skb->data, skb->len, &src, &dest, &dp, &type, &dama) == NULL) + goto free; /* * Ours perhaps ? @@ -234,21 +231,19 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, /* UI frame - bypass LAPB processing */ if ((*skb->data & ~0x10) == AX25_UI && dp.lastrepeat + 1 == dp.ndigi) { - skb->h.raw = skb->data + 2; /* skip control and pid */ + skb_set_transport_header(skb, 2); /* skip control and pid */ ax25_send_to_raw(&dest, skb, skb->data[1]); - if (!mine && ax25cmp(&dest, (ax25_address *)dev->broadcast) != 0) { - kfree_skb(skb); - return 0; - } + if (!mine && ax25cmp(&dest, (ax25_address *)dev->broadcast) != 0) + goto free; /* Now we are pointing at the pid byte */ switch (skb->data[1]) { case AX25_P_IP: skb_pull(skb,2); /* drop PID/CTRL */ - skb->h.raw = skb->data; - skb->nh.raw = skb->data; + skb_reset_transport_header(skb); + skb_reset_network_header(skb); skb->dev = dev; skb->pkt_type = PACKET_HOST; skb->protocol = htons(ETH_P_IP); @@ -257,8 +252,8 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, case AX25_P_ARP: skb_pull(skb,2); - skb->h.raw = skb->data; - skb->nh.raw = skb->data; + skb_reset_transport_header(skb); + skb_reset_network_header(skb); skb->dev = dev; skb->pkt_type = PACKET_HOST; skb->protocol = htons(ETH_P_ARP); @@ -300,10 +295,8 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, * If not, should we DM the incoming frame (except DMs) or * silently ignore them. For now we stay quiet. */ - if (ax25_dev->values[AX25_VALUES_CONMODE] == 0) { - kfree_skb(skb); - return 0; - } + if (ax25_dev->values[AX25_VALUES_CONMODE] == 0) + goto free; /* LAPB */ @@ -338,8 +331,7 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, if ((*skb->data & ~AX25_PF) != AX25_DM && mine) ax25_return_dm(dev, &src, &dest, &dp); - kfree_skb(skb); - return 0; + goto free; } /* b) received SABM(E) */ @@ -371,15 +363,12 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, sk->sk_ack_backlog++; bh_unlock_sock(sk); } else { - if (!mine) { - kfree_skb(skb); - return 0; - } + if (!mine) + goto free; if ((ax25 = ax25_create_cb()) == NULL) { ax25_return_dm(dev, &src, &dest, &dp); - kfree_skb(skb); - return 0; + goto free; } ax25_fillin_cb(ax25, ax25_dev); @@ -433,11 +422,12 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, if (sk) { if (!sock_flag(sk, SOCK_DEAD)) - sk->sk_data_ready(sk, skb->len); + sk->sk_data_ready(sk); sock_put(sk); - } else + } else { +free: kfree_skb(skb); - + } return 0; } @@ -447,8 +437,12 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, int ax25_kiss_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype, struct net_device *orig_dev) { - skb->sk = NULL; /* Initially we don't know who it's for */ - skb->destructor = NULL; /* Who initializes this, dammit?! */ + skb_orphan(skb); + + if (!net_eq(dev_net(dev), &init_net)) { + kfree_skb(skb); + return 0; + } if ((*skb->data & 0x0F) != 0) { kfree_skb(skb); /* Not a KISS data frame */ diff --git a/net/ax25/ax25_ip.c b/net/ax25/ax25_ip.c index d643dac3ecc..67de6b33f2c 100644 --- a/net/ax25/ax25_ip.c +++ b/net/ax25/ax25_ip.c @@ -6,17 +6,17 @@ * * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) */ -#include <linux/config.h> #include <linux/errno.h> #include <linux/types.h> #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> +#include <linux/module.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> #include <linux/net.h> +#include <linux/slab.h> #include <net/ax25.h> #include <linux/inet.h> #include <linux/netdevice.h> @@ -24,7 +24,6 @@ #include <linux/skbuff.h> #include <net/sock.h> #include <asm/uaccess.h> -#include <asm/system.h> #include <linux/fcntl.h> #include <linux/termios.h> /* For TIOCINQ/OUTQ */ #include <linux/mm.h> @@ -47,7 +46,9 @@ #ifdef CONFIG_INET -int ax25_hard_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len) +int ax25_hard_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, const void *daddr, + const void *saddr, unsigned int len) { unsigned char *buff; @@ -55,46 +56,46 @@ int ax25_hard_header(struct sk_buff *skb, struct net_device *dev, unsigned short if (type == ETH_P_AX25) return 0; - /* header is an AX.25 UI frame from us to them */ - buff = skb_push(skb, AX25_HEADER_LEN); - *buff++ = 0x00; /* KISS DATA */ + /* header is an AX.25 UI frame from us to them */ + buff = skb_push(skb, AX25_HEADER_LEN); + *buff++ = 0x00; /* KISS DATA */ if (daddr != NULL) memcpy(buff, daddr, dev->addr_len); /* Address specified */ - buff[6] &= ~AX25_CBIT; - buff[6] &= ~AX25_EBIT; - buff[6] |= AX25_SSSID_SPARE; - buff += AX25_ADDR_LEN; - - if (saddr != NULL) - memcpy(buff, saddr, dev->addr_len); - else - memcpy(buff, dev->dev_addr, dev->addr_len); - - buff[6] &= ~AX25_CBIT; - buff[6] |= AX25_EBIT; - buff[6] |= AX25_SSSID_SPARE; - buff += AX25_ADDR_LEN; - - *buff++ = AX25_UI; /* UI */ - - /* Append a suitable AX.25 PID */ - switch (type) { - case ETH_P_IP: - *buff++ = AX25_P_IP; - break; - case ETH_P_ARP: - *buff++ = AX25_P_ARP; - break; - default: - printk(KERN_ERR "AX.25: ax25_hard_header - wrong protocol type 0x%2.2x\n", type); - *buff++ = 0; - break; - } + buff[6] &= ~AX25_CBIT; + buff[6] &= ~AX25_EBIT; + buff[6] |= AX25_SSSID_SPARE; + buff += AX25_ADDR_LEN; + + if (saddr != NULL) + memcpy(buff, saddr, dev->addr_len); + else + memcpy(buff, dev->dev_addr, dev->addr_len); + + buff[6] &= ~AX25_CBIT; + buff[6] |= AX25_EBIT; + buff[6] |= AX25_SSSID_SPARE; + buff += AX25_ADDR_LEN; + + *buff++ = AX25_UI; /* UI */ + + /* Append a suitable AX.25 PID */ + switch (type) { + case ETH_P_IP: + *buff++ = AX25_P_IP; + break; + case ETH_P_ARP: + *buff++ = AX25_P_ARP; + break; + default: + printk(KERN_ERR "AX.25: ax25_hard_header - wrong protocol type 0x%2.2x\n", type); + *buff++ = 0; + break; + } if (daddr != NULL) - return AX25_HEADER_LEN; + return AX25_HEADER_LEN; return -AX25_HEADER_LEN; /* Unfinished header */ } @@ -103,30 +104,36 @@ int ax25_rebuild_header(struct sk_buff *skb) { struct sk_buff *ourskb; unsigned char *bp = skb->data; - struct net_device *dev; + ax25_route *route; + struct net_device *dev = NULL; ax25_address *src, *dst; + ax25_digi *digipeat = NULL; ax25_dev *ax25_dev; - ax25_route _route, *route = &_route; ax25_cb *ax25; + char ip_mode = ' '; dst = (ax25_address *)(bp + 1); src = (ax25_address *)(bp + 8); - if (arp_find(bp + 1, skb)) - return 1; + if (arp_find(bp + 1, skb)) + return 1; - route = ax25_rt_find_route(route, dst, NULL); - dev = route->dev; + route = ax25_get_route(dst, NULL); + if (route) { + digipeat = route->digipeat; + dev = route->dev; + ip_mode = route->ip_mode; + } if (dev == NULL) dev = skb->dev; - if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) { - goto put; + if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) { + goto put; } if (bp[16] == AX25_P_IP) { - if (route->ip_mode == 'V' || (route->ip_mode == ' ' && ax25_dev->values[AX25_VALUES_IPDEFMODE])) { + if (ip_mode == 'V' || (ip_mode == ' ' && ax25_dev->values[AX25_VALUES_IPDEFMODE])) { /* * We copy the buffer and release the original thereby * keeping it straight @@ -166,13 +173,13 @@ int ax25_rebuild_header(struct sk_buff *skb) src_c = *(ax25_address *)(bp + 8); skb_pull(ourskb, AX25_HEADER_LEN - 1); /* Keep PID */ - ourskb->nh.raw = ourskb->data; + skb_reset_network_header(ourskb); ax25=ax25_send_frame( - ourskb, - ax25_dev->values[AX25_VALUES_PACLEN], + ourskb, + ax25_dev->values[AX25_VALUES_PACLEN], &src_c, - &dst_c, route->digipeat, dev); + &dst_c, digipeat, dev); if (ax25) { ax25_cb_put(ax25); } @@ -180,17 +187,17 @@ int ax25_rebuild_header(struct sk_buff *skb) } } - bp[7] &= ~AX25_CBIT; - bp[7] &= ~AX25_EBIT; - bp[7] |= AX25_SSSID_SPARE; + bp[7] &= ~AX25_CBIT; + bp[7] &= ~AX25_EBIT; + bp[7] |= AX25_SSSID_SPARE; - bp[14] &= ~AX25_CBIT; - bp[14] |= AX25_EBIT; - bp[14] |= AX25_SSSID_SPARE; + bp[14] &= ~AX25_CBIT; + bp[14] |= AX25_EBIT; + bp[14] |= AX25_SSSID_SPARE; skb_pull(skb, AX25_KISS_HEADER_LEN); - if (route->digipeat != NULL) { + if (digipeat != NULL) { if ((ourskb = ax25_rt_build_path(skb, src, dst, route->digipeat)) == NULL) { kfree_skb(skb); goto put; @@ -202,14 +209,17 @@ int ax25_rebuild_header(struct sk_buff *skb) ax25_queue_xmit(skb, dev); put: - ax25_put_route(route); + if (route) + ax25_put_route(route); - return 1; + return 1; } #else /* INET */ -int ax25_hard_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len) +int ax25_hard_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, const void *daddr, + const void *saddr, unsigned int len) { return -AX25_HEADER_LEN; } @@ -221,3 +231,12 @@ int ax25_rebuild_header(struct sk_buff *skb) #endif +const struct header_ops ax25_header_ops = { + .create = ax25_hard_header, + .rebuild = ax25_rebuild_header, +}; + +EXPORT_SYMBOL(ax25_hard_header); +EXPORT_SYMBOL(ax25_rebuild_header); +EXPORT_SYMBOL(ax25_header_ops); + diff --git a/net/ax25/ax25_out.c b/net/ax25/ax25_out.c index 5fc048dcd39..be2acab9be9 100644 --- a/net/ax25/ax25_out.c +++ b/net/ax25/ax25_out.c @@ -8,18 +8,18 @@ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de) */ -#include <linux/config.h> #include <linux/errno.h> #include <linux/types.h> #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> +#include <linux/module.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> #include <linux/spinlock.h> #include <linux/net.h> +#include <linux/slab.h> #include <net/ax25.h> #include <linux/inet.h> #include <linux/netdevice.h> @@ -27,7 +27,6 @@ #include <linux/netfilter.h> #include <net/sock.h> #include <asm/uaccess.h> -#include <asm/system.h> #include <linux/fcntl.h> #include <linux/mm.h> #include <linux/interrupt.h> @@ -70,11 +69,11 @@ ax25_cb *ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax2 ax25->dest_addr = *dest; if (digi != NULL) { - if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { + ax25->digipeat = kmemdup(digi, sizeof(*digi), GFP_ATOMIC); + if (ax25->digipeat == NULL) { ax25_cb_put(ax25); return NULL; } - memcpy(ax25->digipeat, digi, sizeof(ax25_digi)); } switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { @@ -93,6 +92,12 @@ ax25_cb *ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax2 #endif } + /* + * There is one ref for the state machine; a caller needs + * one more to put it back, just like with the existing one. + */ + ax25_cb_hold(ax25); + ax25_cb_add(ax25); ax25->state = AX25_STATE_1; @@ -104,6 +109,8 @@ ax25_cb *ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax2 return ax25; /* We had to create it */ } +EXPORT_SYMBOL(ax25_send_frame); + /* * All outgoing AX.25 I frames pass via this routine. Therefore this is * where the fragmentation of frames takes place. If fragment is set to @@ -116,6 +123,12 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb) unsigned char *p; int frontlen, len, fragno, ka9qfrag, first = 1; + if (paclen < 16) { + WARN_ON_ONCE(1); + kfree_skb(skb); + return; + } + if ((skb->len - 1) > paclen) { if (*skb->data == AX25_P_TEXT) { skb_pull(skb, 1); /* skip PID */ @@ -147,8 +160,9 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb) if (ka9qfrag == 1) { skb_reserve(skbn, frontlen + 2); - skbn->nh.raw = skbn->data + (skb->nh.raw - skb->data); - memcpy(skb_put(skbn, len), skb->data, len); + skb_set_network_header(skbn, + skb_network_offset(skb)); + skb_copy_from_linear_data(skb, skb_put(skbn, len), len); p = skb_push(skbn, 2); *p++ = AX25_P_SEGMENT; @@ -160,8 +174,9 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb) } } else { skb_reserve(skbn, frontlen + 1); - skbn->nh.raw = skbn->data + (skb->nh.raw - skb->data); - memcpy(skb_put(skbn, len), skb->data, len); + skb_set_network_header(skbn, + skb_network_offset(skb)); + skb_copy_from_linear_data(skb, skb_put(skbn, len), len); p = skb_push(skbn, 1); *p = AX25_P_TEXT; } @@ -204,7 +219,7 @@ static void ax25_send_iframe(ax25_cb *ax25, struct sk_buff *skb, int poll_bit) if (skb == NULL) return; - skb->nh.raw = skb->data; + skb_reset_network_header(skb); if (ax25->modulus == AX25_MODULUS) { frame = skb_push(skb, 1); @@ -248,8 +263,6 @@ void ax25_kick(ax25_cb *ax25) if (start == end) return; - ax25->vs = start; - /* * Transmit data until either we're out of data to send or * the window is full. Send a poll on the final I frame if @@ -258,8 +271,13 @@ void ax25_kick(ax25_cb *ax25) /* * Dequeue the frame and copy it. + * Check for race with ax25_clear_queues(). */ skb = skb_dequeue(&ax25->write_queue); + if (!skb) + return; + + ax25->vs = start; do { if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) { @@ -332,7 +350,7 @@ void ax25_transmit_buffer(ax25_cb *ax25, struct sk_buff *skb, int type) if (skb->sk != NULL) skb_set_owner_w(skbn, skb->sk); - kfree_skb(skb); + consume_skb(skb); skb = skbn; } diff --git a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c index f04f8630fd2..d39097737e3 100644 --- a/net/ax25/ax25_route.c +++ b/net/ax25/ax25_route.c @@ -23,6 +23,7 @@ #include <linux/string.h> #include <linux/sockios.h> #include <linux/net.h> +#include <linux/slab.h> #include <net/ax25.h> #include <linux/inet.h> #include <linux/netdevice.h> @@ -31,23 +32,21 @@ #include <linux/spinlock.h> #include <net/sock.h> #include <asm/uaccess.h> -#include <asm/system.h> #include <linux/fcntl.h> #include <linux/mm.h> #include <linux/interrupt.h> #include <linux/init.h> #include <linux/seq_file.h> +#include <linux/export.h> static ax25_route *ax25_route_list; static DEFINE_RWLOCK(ax25_route_lock); -static ax25_route *ax25_get_route(ax25_address *, struct net_device *); - void ax25_rt_device_down(struct net_device *dev) { ax25_route *s, *t, *ax25_rt; - write_lock(&ax25_route_lock); + write_lock_bh(&ax25_route_lock); ax25_rt = ax25_route_list; while (ax25_rt != NULL) { s = ax25_rt; @@ -70,10 +69,10 @@ void ax25_rt_device_down(struct net_device *dev) } } } - write_unlock(&ax25_route_lock); + write_unlock_bh(&ax25_route_lock); } -static int ax25_rt_add(struct ax25_routes_struct *route) +static int __must_check ax25_rt_add(struct ax25_routes_struct *route) { ax25_route *ax25_rt; ax25_dev *ax25_dev; @@ -84,17 +83,17 @@ static int ax25_rt_add(struct ax25_routes_struct *route) if (route->digi_count > AX25_MAX_DIGIS) return -EINVAL; - write_lock(&ax25_route_lock); + write_lock_bh(&ax25_route_lock); ax25_rt = ax25_route_list; while (ax25_rt != NULL) { if (ax25cmp(&ax25_rt->callsign, &route->dest_addr) == 0 && - ax25_rt->dev == ax25_dev->dev) { + ax25_rt->dev == ax25_dev->dev) { kfree(ax25_rt->digipeat); ax25_rt->digipeat = NULL; if (route->digi_count != 0) { if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { - write_unlock(&ax25_route_lock); + write_unlock_bh(&ax25_route_lock); return -ENOMEM; } ax25_rt->digipeat->lastrepeat = -1; @@ -104,25 +103,25 @@ static int ax25_rt_add(struct ax25_routes_struct *route) ax25_rt->digipeat->calls[i] = route->digi_addr[i]; } } - write_unlock(&ax25_route_lock); + write_unlock_bh(&ax25_route_lock); return 0; } ax25_rt = ax25_rt->next; } if ((ax25_rt = kmalloc(sizeof(ax25_route), GFP_ATOMIC)) == NULL) { - write_unlock(&ax25_route_lock); + write_unlock_bh(&ax25_route_lock); return -ENOMEM; } - atomic_set(&ax25_rt->ref, 0); + atomic_set(&ax25_rt->refcount, 1); ax25_rt->callsign = route->dest_addr; ax25_rt->dev = ax25_dev->dev; ax25_rt->digipeat = NULL; ax25_rt->ip_mode = ' '; if (route->digi_count != 0) { if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { - write_unlock(&ax25_route_lock); + write_unlock_bh(&ax25_route_lock); kfree(ax25_rt); return -ENOMEM; } @@ -135,28 +134,15 @@ static int ax25_rt_add(struct ax25_routes_struct *route) } ax25_rt->next = ax25_route_list; ax25_route_list = ax25_rt; - write_unlock(&ax25_route_lock); + write_unlock_bh(&ax25_route_lock); return 0; } -static void ax25_rt_destroy(ax25_route *ax25_rt) +void __ax25_put_route(ax25_route *ax25_rt) { - if (atomic_read(&ax25_rt->ref) == 0) { - kfree(ax25_rt->digipeat); - kfree(ax25_rt); - return; - } - - /* - * Uh... Route is still in use; we can't yet destroy it. Retry later. - */ - init_timer(&ax25_rt->timer); - ax25_rt->timer.data = (unsigned long) ax25_rt; - ax25_rt->timer.function = (void *) ax25_rt_destroy; - ax25_rt->timer.expires = jiffies + 5 * HZ; - - add_timer(&ax25_rt->timer); + kfree(ax25_rt->digipeat); + kfree(ax25_rt); } static int ax25_rt_del(struct ax25_routes_struct *route) @@ -167,7 +153,7 @@ static int ax25_rt_del(struct ax25_routes_struct *route) if ((ax25_dev = ax25_addr_ax25dev(&route->port_addr)) == NULL) return -EINVAL; - write_lock(&ax25_route_lock); + write_lock_bh(&ax25_route_lock); ax25_rt = ax25_route_list; while (ax25_rt != NULL) { @@ -177,19 +163,19 @@ static int ax25_rt_del(struct ax25_routes_struct *route) ax25cmp(&route->dest_addr, &s->callsign) == 0) { if (ax25_route_list == s) { ax25_route_list = s->next; - ax25_rt_destroy(s); + ax25_put_route(s); } else { for (t = ax25_route_list; t != NULL; t = t->next) { if (t->next == s) { t->next = s->next; - ax25_rt_destroy(s); + ax25_put_route(s); break; } } } } } - write_unlock(&ax25_route_lock); + write_unlock_bh(&ax25_route_lock); return 0; } @@ -203,7 +189,7 @@ static int ax25_rt_opt(struct ax25_route_opt_struct *rt_option) if ((ax25_dev = ax25_addr_ax25dev(&rt_option->port_addr)) == NULL) return -EINVAL; - write_lock(&ax25_route_lock); + write_lock_bh(&ax25_route_lock); ax25_rt = ax25_route_list; while (ax25_rt != NULL) { @@ -231,7 +217,7 @@ static int ax25_rt_opt(struct ax25_route_opt_struct *rt_option) } out: - write_unlock(&ax25_route_lock); + write_unlock_bh(&ax25_route_lock); return err; } @@ -264,11 +250,12 @@ int ax25_rt_ioctl(unsigned int cmd, void __user *arg) #ifdef CONFIG_PROC_FS static void *ax25_rt_seq_start(struct seq_file *seq, loff_t *pos) + __acquires(ax25_route_lock) { struct ax25_route *ax25_rt; int i = 1; - - read_lock(&ax25_route_lock); + + read_lock(&ax25_route_lock); if (*pos == 0) return SEQ_START_TOKEN; @@ -284,11 +271,12 @@ static void *ax25_rt_seq_start(struct seq_file *seq, loff_t *pos) static void *ax25_rt_seq_next(struct seq_file *seq, void *v, loff_t *pos) { ++*pos; - return (v == SEQ_START_TOKEN) ? ax25_route_list : + return (v == SEQ_START_TOKEN) ? ax25_route_list : ((struct ax25_route *) v)->next; } static void ax25_rt_seq_stop(struct seq_file *seq, void *v) + __releases(ax25_route_lock) { read_unlock(&ax25_route_lock); } @@ -335,7 +323,7 @@ static int ax25_rt_seq_show(struct seq_file *seq, void *v) return 0; } -static struct seq_operations ax25_rt_seqops = { +static const struct seq_operations ax25_rt_seqops = { .start = ax25_rt_seq_start, .next = ax25_rt_seq_next, .stop = ax25_rt_seq_stop, @@ -347,7 +335,7 @@ static int ax25_rt_info_open(struct inode *inode, struct file *file) return seq_open(file, &ax25_rt_seqops); } -struct file_operations ax25_route_fops = { +const struct file_operations ax25_route_fops = { .owner = THIS_MODULE, .open = ax25_rt_info_open, .read = seq_read, @@ -360,9 +348,9 @@ struct file_operations ax25_route_fops = { /* * Find AX.25 route * - * Only routes with a refernce rout of zero can be destroyed. + * Only routes with a reference count of zero can be destroyed. */ -static ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev) +ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev) { ax25_route *ax25_spe_rt = NULL; ax25_route *ax25_def_rt = NULL; @@ -392,7 +380,7 @@ static ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev) ax25_rt = ax25_spe_rt; if (ax25_rt != NULL) - atomic_inc(&ax25_rt->ref); + ax25_hold_route(ax25_rt); read_unlock(&ax25_route_lock); @@ -424,7 +412,7 @@ int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr) { ax25_uid_assoc *user; ax25_route *ax25_rt; - int err; + int err = 0; if ((ax25_rt = ax25_get_route(addr, NULL)) == NULL) return -EHOSTUNREACH; @@ -434,7 +422,7 @@ int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr) goto put; } - user = ax25_findbyuid(current->euid); + user = ax25_findbyuid(current_euid()); if (user) { ax25->source_addr = user->call; ax25_uid_put(user); @@ -447,11 +435,12 @@ int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr) } if (ax25_rt->digipeat != NULL) { - if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { + ax25->digipeat = kmemdup(ax25_rt->digipeat, sizeof(ax25_digi), + GFP_ATOMIC); + if (ax25->digipeat == NULL) { err = -ENOMEM; goto put; } - memcpy(ax25->digipeat, ax25_rt->digipeat, sizeof(ax25_digi)); ax25_adjust_path(addr, ax25->digipeat); } @@ -464,25 +453,7 @@ int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr) put: ax25_put_route(ax25_rt); - return 0; -} - -ax25_route *ax25_rt_find_route(ax25_route * route, ax25_address *addr, - struct net_device *dev) -{ - ax25_route *ax25_rt; - - if ((ax25_rt = ax25_get_route(addr, dev))) - return ax25_rt; - - route->next = NULL; - atomic_set(&route->ref, 1); - route->callsign = *addr; - route->dev = dev; - route->digipeat = NULL; - route->ip_mode = ' '; - - return route; + return err; } struct sk_buff *ax25_rt_build_path(struct sk_buff *skb, ax25_address *src, @@ -503,7 +474,7 @@ struct sk_buff *ax25_rt_build_path(struct sk_buff *skb, ax25_address *src, if (skb->sk != NULL) skb_set_owner_w(skbn, skb->sk); - kfree_skb(skb); + consume_skb(skb); skb = skbn; } @@ -522,7 +493,7 @@ void __exit ax25_rt_free(void) { ax25_route *s, *ax25_rt = ax25_route_list; - write_lock(&ax25_route_lock); + write_lock_bh(&ax25_route_lock); while (ax25_rt != NULL) { s = ax25_rt; ax25_rt = ax25_rt->next; @@ -530,5 +501,5 @@ void __exit ax25_rt_free(void) kfree(s->digipeat); kfree(s); } - write_unlock(&ax25_route_lock); + write_unlock_bh(&ax25_route_lock); } diff --git a/net/ax25/ax25_std_in.c b/net/ax25/ax25_std_in.c index f6ed283e9de..3fbf8f7b2cf 100644 --- a/net/ax25/ax25_std_in.c +++ b/net/ax25/ax25_std_in.c @@ -19,7 +19,6 @@ #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> @@ -31,7 +30,6 @@ #include <net/sock.h> #include <net/tcp_states.h> #include <asm/uaccess.h> -#include <asm/system.h> #include <linux/fcntl.h> #include <linux/mm.h> #include <linux/interrupt.h> diff --git a/net/ax25/ax25_std_subr.c b/net/ax25/ax25_std_subr.c index 2b3c801ae48..8b66a41e538 100644 --- a/net/ax25/ax25_std_subr.c +++ b/net/ax25/ax25_std_subr.c @@ -11,7 +11,6 @@ #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> @@ -22,7 +21,6 @@ #include <linux/skbuff.h> #include <net/sock.h> #include <asm/uaccess.h> -#include <asm/system.h> #include <linux/fcntl.h> #include <linux/mm.h> #include <linux/interrupt.h> diff --git a/net/ax25/ax25_std_timer.c b/net/ax25/ax25_std_timer.c index a29c480a4dc..004467c9e6e 100644 --- a/net/ax25/ax25_std_timer.c +++ b/net/ax25/ax25_std_timer.c @@ -14,7 +14,6 @@ #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> @@ -26,15 +25,14 @@ #include <net/sock.h> #include <net/tcp_states.h> #include <asm/uaccess.h> -#include <asm/system.h> #include <linux/fcntl.h> #include <linux/mm.h> #include <linux/interrupt.h> void ax25_std_heartbeat_expiry(ax25_cb *ax25) { - struct sock *sk=ax25->sk; - + struct sock *sk = ax25->sk; + if (sk) bh_lock_sock(sk); @@ -63,7 +61,7 @@ void ax25_std_heartbeat_expiry(ax25_cb *ax25) */ if (sk != NULL) { if (atomic_read(&sk->sk_rmem_alloc) < - (sk->sk_rcvbuf / 2) && + (sk->sk_rcvbuf >> 1) && (ax25->condition & AX25_COND_OWN_RX_BUSY)) { ax25->condition &= ~AX25_COND_OWN_RX_BUSY; ax25->condition &= ~AX25_COND_ACK_PENDING; diff --git a/net/ax25/ax25_subr.c b/net/ax25/ax25_subr.c index c41dbe5fade..1997538a5d2 100644 --- a/net/ax25/ax25_subr.c +++ b/net/ax25/ax25_subr.c @@ -14,11 +14,11 @@ #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> #include <linux/net.h> +#include <linux/slab.h> #include <net/ax25.h> #include <linux/inet.h> #include <linux/netdevice.h> @@ -26,7 +26,6 @@ #include <net/sock.h> #include <net/tcp_states.h> #include <asm/uaccess.h> -#include <asm/system.h> #include <linux/fcntl.h> #include <linux/mm.h> #include <linux/interrupt.h> @@ -56,7 +55,7 @@ void ax25_frames_acked(ax25_cb *ax25, unsigned short nr) */ if (ax25->va != nr) { while (skb_peek(&ax25->ack_queue) != NULL && ax25->va != nr) { - skb = skb_dequeue(&ax25->ack_queue); + skb = skb_dequeue(&ax25->ack_queue); kfree_skb(skb); ax25->va = (ax25->va + 1) % ax25->modulus; } @@ -65,20 +64,15 @@ void ax25_frames_acked(ax25_cb *ax25, unsigned short nr) void ax25_requeue_frames(ax25_cb *ax25) { - struct sk_buff *skb, *skb_prev = NULL; + struct sk_buff *skb; /* * Requeue all the un-ack-ed frames on the output queue to be picked * up by ax25_kick called from the timer. This arrangement handles the * possibility of an empty output queue. */ - while ((skb = skb_dequeue(&ax25->ack_queue)) != NULL) { - if (skb_prev == NULL) - skb_queue_head(&ax25->write_queue, skb); - else - skb_append(skb_prev, skb, &ax25->write_queue); - skb_prev = skb; - } + while ((skb = skb_dequeue_tail(&ax25->ack_queue)) != NULL) + skb_queue_head(&ax25->write_queue, skb); } /* @@ -163,7 +157,7 @@ void ax25_send_control(ax25_cb *ax25, int frametype, int poll_bit, int type) skb_reserve(skb, ax25->ax25_dev->dev->hard_header_len); - skb->nh.raw = skb->data; + skb_reset_network_header(skb); /* Assume a response - address structure for DTE */ if (ax25->modulus == AX25_MODULUS) { @@ -206,7 +200,7 @@ void ax25_return_dm(struct net_device *dev, ax25_address *src, ax25_address *des return; /* Next SABM will get DM'd */ skb_reserve(skb, dev->hard_header_len); - skb->nh.raw = skb->data; + skb_reset_network_header(skb); ax25_digi_invert(digi, &retdigi); @@ -280,6 +274,7 @@ void ax25_disconnect(ax25_cb *ax25, int reason) ax25_link_failed(ax25, reason); if (ax25->sk != NULL) { + local_bh_disable(); bh_lock_sock(ax25->sk); ax25->sk->sk_state = TCP_CLOSE; ax25->sk->sk_err = reason; @@ -289,5 +284,6 @@ void ax25_disconnect(ax25_cb *ax25, int reason) sock_set_flag(ax25->sk, SOCK_DEAD); } bh_unlock_sock(ax25->sk); + local_bh_enable(); } } diff --git a/net/ax25/ax25_timer.c b/net/ax25/ax25_timer.c index 7a6b50a1455..c3cffa79baf 100644 --- a/net/ax25/ax25_timer.c +++ b/net/ax25/ax25_timer.c @@ -12,12 +12,12 @@ * Copyright (C) Frederic Rible F1OAT (frible@teaser.fr) * Copyright (C) 2002 Ralf Baechle DO1GRB (ralf@gnu.org) */ -#include <linux/config.h> #include <linux/errno.h> #include <linux/types.h> #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> +#include <linux/module.h> #include <linux/jiffies.h> #include <linux/timer.h> #include <linux/string.h> @@ -29,7 +29,6 @@ #include <linux/skbuff.h> #include <net/sock.h> #include <asm/uaccess.h> -#include <asm/system.h> #include <linux/fcntl.h> #include <linux/mm.h> #include <linux/interrupt.h> @@ -40,63 +39,45 @@ static void ax25_t2timer_expiry(unsigned long); static void ax25_t3timer_expiry(unsigned long); static void ax25_idletimer_expiry(unsigned long); -void ax25_start_heartbeat(ax25_cb *ax25) +void ax25_setup_timers(ax25_cb *ax25) { - del_timer(&ax25->timer); - - ax25->timer.data = (unsigned long)ax25; - ax25->timer.function = &ax25_heartbeat_expiry; - ax25->timer.expires = jiffies + 5 * HZ; + setup_timer(&ax25->timer, ax25_heartbeat_expiry, (unsigned long)ax25); + setup_timer(&ax25->t1timer, ax25_t1timer_expiry, (unsigned long)ax25); + setup_timer(&ax25->t2timer, ax25_t2timer_expiry, (unsigned long)ax25); + setup_timer(&ax25->t3timer, ax25_t3timer_expiry, (unsigned long)ax25); + setup_timer(&ax25->idletimer, ax25_idletimer_expiry, + (unsigned long)ax25); +} - add_timer(&ax25->timer); +void ax25_start_heartbeat(ax25_cb *ax25) +{ + mod_timer(&ax25->timer, jiffies + 5 * HZ); } void ax25_start_t1timer(ax25_cb *ax25) { - del_timer(&ax25->t1timer); - - ax25->t1timer.data = (unsigned long)ax25; - ax25->t1timer.function = &ax25_t1timer_expiry; - ax25->t1timer.expires = jiffies + ax25->t1; - - add_timer(&ax25->t1timer); + mod_timer(&ax25->t1timer, jiffies + ax25->t1); } void ax25_start_t2timer(ax25_cb *ax25) { - del_timer(&ax25->t2timer); - - ax25->t2timer.data = (unsigned long)ax25; - ax25->t2timer.function = &ax25_t2timer_expiry; - ax25->t2timer.expires = jiffies + ax25->t2; - - add_timer(&ax25->t2timer); + mod_timer(&ax25->t2timer, jiffies + ax25->t2); } void ax25_start_t3timer(ax25_cb *ax25) { - del_timer(&ax25->t3timer); - - if (ax25->t3 > 0) { - ax25->t3timer.data = (unsigned long)ax25; - ax25->t3timer.function = &ax25_t3timer_expiry; - ax25->t3timer.expires = jiffies + ax25->t3; - - add_timer(&ax25->t3timer); - } + if (ax25->t3 > 0) + mod_timer(&ax25->t3timer, jiffies + ax25->t3); + else + del_timer(&ax25->t3timer); } void ax25_start_idletimer(ax25_cb *ax25) { - del_timer(&ax25->idletimer); - - if (ax25->idle > 0) { - ax25->idletimer.data = (unsigned long)ax25; - ax25->idletimer.function = &ax25_idletimer_expiry; - ax25->idletimer.expires = jiffies + ax25->idle; - - add_timer(&ax25->idletimer); - } + if (ax25->idle > 0) + mod_timer(&ax25->idletimer, jiffies + ax25->idle); + else + del_timer(&ax25->idletimer); } void ax25_stop_heartbeat(ax25_cb *ax25) @@ -137,6 +118,8 @@ unsigned long ax25_display_timer(struct timer_list *timer) return timer->expires - jiffies; } +EXPORT_SYMBOL(ax25_display_timer); + static void ax25_heartbeat_expiry(unsigned long param) { int proto = AX25_PROTO_STD_SIMPLEX; diff --git a/net/ax25/ax25_uid.c b/net/ax25/ax25_uid.c index b8b5854bce9..71c4badbc80 100644 --- a/net/ax25/ax25_uid.c +++ b/net/ax25/ax25_uid.c @@ -13,12 +13,12 @@ #include <linux/socket.h> #include <linux/in.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> #include <linux/net.h> #include <linux/spinlock.h> +#include <linux/slab.h> #include <net/ax25.h> #include <linux/inet.h> #include <linux/netdevice.h> @@ -26,7 +26,6 @@ #include <linux/skbuff.h> #include <net/sock.h> #include <asm/uaccess.h> -#include <asm/system.h> #include <linux/fcntl.h> #include <linux/mm.h> #include <linux/interrupt.h> @@ -37,6 +36,7 @@ #include <linux/stat.h> #include <linux/netfilter.h> #include <linux/sysctl.h> +#include <linux/export.h> #include <net/ip.h> #include <net/arp.h> @@ -44,19 +44,20 @@ * Callsign/UID mapper. This is in kernel space for security on multi-amateur machines. */ -HLIST_HEAD(ax25_uid_list); +static HLIST_HEAD(ax25_uid_list); static DEFINE_RWLOCK(ax25_uid_lock); -int ax25_uid_policy = 0; +int ax25_uid_policy; -ax25_uid_assoc *ax25_findbyuid(uid_t uid) +EXPORT_SYMBOL(ax25_uid_policy); + +ax25_uid_assoc *ax25_findbyuid(kuid_t uid) { ax25_uid_assoc *ax25_uid, *res = NULL; - struct hlist_node *node; read_lock(&ax25_uid_lock); - ax25_uid_for_each(ax25_uid, node, &ax25_uid_list) { - if (ax25_uid->uid == uid) { + ax25_uid_for_each(ax25_uid, &ax25_uid_list) { + if (uid_eq(ax25_uid->uid, uid)) { ax25_uid_hold(ax25_uid); res = ax25_uid; break; @@ -67,10 +68,11 @@ ax25_uid_assoc *ax25_findbyuid(uid_t uid) return res; } +EXPORT_SYMBOL(ax25_findbyuid); + int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax) { ax25_uid_assoc *ax25_uid; - struct hlist_node *node; ax25_uid_assoc *user; unsigned long res; @@ -78,9 +80,9 @@ int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax) case SIOCAX25GETUID: res = -ENOENT; read_lock(&ax25_uid_lock); - ax25_uid_for_each(ax25_uid, node, &ax25_uid_list) { + ax25_uid_for_each(ax25_uid, &ax25_uid_list) { if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) { - res = ax25_uid->uid; + res = from_kuid_munged(current_user_ns(), ax25_uid->uid); break; } } @@ -89,9 +91,14 @@ int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax) return res; case SIOCAX25ADDUID: + { + kuid_t sax25_kuid; if (!capable(CAP_NET_ADMIN)) return -EPERM; - user = ax25_findbyuid(sax->sax25_uid); + sax25_kuid = make_kuid(current_user_ns(), sax->sax25_uid); + if (!uid_valid(sax25_kuid)) + return -EINVAL; + user = ax25_findbyuid(sax25_kuid); if (user) { ax25_uid_put(user); return -EEXIST; @@ -102,7 +109,7 @@ int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax) return -ENOMEM; atomic_set(&ax25_uid->refcount, 1); - ax25_uid->uid = sax->sax25_uid; + ax25_uid->uid = sax25_kuid; ax25_uid->call = sax->sax25_call; write_lock(&ax25_uid_lock); @@ -110,14 +117,14 @@ int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax) write_unlock(&ax25_uid_lock); return 0; - + } case SIOCAX25DELUID: if (!capable(CAP_NET_ADMIN)) return -EPERM; ax25_uid = NULL; write_lock(&ax25_uid_lock); - ax25_uid_for_each(ax25_uid, node, &ax25_uid_list) { + ax25_uid_for_each(ax25_uid, &ax25_uid_list) { if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) break; } @@ -141,29 +148,19 @@ int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax) #ifdef CONFIG_PROC_FS static void *ax25_uid_seq_start(struct seq_file *seq, loff_t *pos) + __acquires(ax25_uid_lock) { - struct ax25_uid_assoc *pt; - struct hlist_node *node; - int i = 0; - read_lock(&ax25_uid_lock); - ax25_uid_for_each(pt, node, &ax25_uid_list) { - if (i == *pos) - return pt; - ++i; - } - return NULL; + return seq_hlist_start_head(&ax25_uid_list, *pos); } static void *ax25_uid_seq_next(struct seq_file *seq, void *v, loff_t *pos) { - ++*pos; - - return hlist_entry(((ax25_uid_assoc *)v)->uid_node.next, - ax25_uid_assoc, uid_node); + return seq_hlist_next(v, &ax25_uid_list, pos); } static void ax25_uid_seq_stop(struct seq_file *seq, void *v) + __releases(ax25_uid_lock) { read_unlock(&ax25_uid_lock); } @@ -175,14 +172,17 @@ static int ax25_uid_seq_show(struct seq_file *seq, void *v) if (v == SEQ_START_TOKEN) seq_printf(seq, "Policy: %d\n", ax25_uid_policy); else { - struct ax25_uid_assoc *pt = v; + struct ax25_uid_assoc *pt; - seq_printf(seq, "%6d %s\n", pt->uid, ax2asc(buf, &pt->call)); + pt = hlist_entry(v, struct ax25_uid_assoc, uid_node); + seq_printf(seq, "%6d %s\n", + from_kuid_munged(seq_user_ns(seq), pt->uid), + ax2asc(buf, &pt->call)); } return 0; } -static struct seq_operations ax25_uid_seqops = { +static const struct seq_operations ax25_uid_seqops = { .start = ax25_uid_seq_start, .next = ax25_uid_seq_next, .stop = ax25_uid_seq_stop, @@ -194,7 +194,7 @@ static int ax25_uid_info_open(struct inode *inode, struct file *file) return seq_open(file, &ax25_uid_seqops); } -struct file_operations ax25_uid_fops = { +const struct file_operations ax25_uid_fops = { .owner = THIS_MODULE, .open = ax25_uid_info_open, .read = seq_read, @@ -210,12 +210,13 @@ struct file_operations ax25_uid_fops = { void __exit ax25_uid_free(void) { ax25_uid_assoc *ax25_uid; - struct hlist_node *node; write_lock(&ax25_uid_lock); - ax25_uid_for_each(ax25_uid, node, &ax25_uid_list) { +again: + ax25_uid_for_each(ax25_uid, &ax25_uid_list) { hlist_del_init(&ax25_uid->uid_node); ax25_uid_put(ax25_uid); + goto again; } write_unlock(&ax25_uid_lock); } diff --git a/net/ax25/sysctl_net_ax25.c b/net/ax25/sysctl_net_ax25.c index f67711f2ee9..919a5ce4751 100644 --- a/net/ax25/sysctl_net_ax25.c +++ b/net/ax25/sysctl_net_ax25.c @@ -6,8 +6,8 @@ * * Copyright (C) 1996 Mike Shaver (shaver@zeroknowledge.com) */ -#include <linux/config.h> #include <linux/mm.h> +#include <linux/slab.h> #include <linux/sysctl.h> #include <linux/spinlock.h> #include <net/ax25.h> @@ -18,245 +18,167 @@ static int min_backoff[1], max_backoff[] = {2}; static int min_conmode[1], max_conmode[] = {2}; static int min_window[] = {1}, max_window[] = {7}; static int min_ewindow[] = {1}, max_ewindow[] = {63}; -static int min_t1[] = {1}, max_t1[] = {30 * HZ}; -static int min_t2[] = {1}, max_t2[] = {20 * HZ}; -static int min_t3[1], max_t3[] = {3600 * HZ}; -static int min_idle[1], max_idle[] = {65535 * HZ}; +static int min_t1[] = {1}, max_t1[] = {30000}; +static int min_t2[] = {1}, max_t2[] = {20000}; +static int min_t3[1], max_t3[] = {3600000}; +static int min_idle[1], max_idle[] = {65535000}; static int min_n2[] = {1}, max_n2[] = {31}; static int min_paclen[] = {1}, max_paclen[] = {512}; -static int min_proto[1], max_proto[] = {3}; -static int min_ds_timeout[1], max_ds_timeout[] = {65535 * HZ}; - -static struct ctl_table_header *ax25_table_header; - -static ctl_table *ax25_table; -static int ax25_table_size; - -static ctl_table ax25_dir_table[] = { - { - .ctl_name = NET_AX25, - .procname = "ax25", - .mode = 0555, - }, - { .ctl_name = 0 } -}; - -static ctl_table ax25_root_table[] = { - { - .ctl_name = CTL_NET, - .procname = "net", - .mode = 0555, - .child = ax25_dir_table - }, - { .ctl_name = 0 } -}; +static int min_proto[1], max_proto[] = { AX25_PROTO_MAX }; +#ifdef CONFIG_AX25_DAMA_SLAVE +static int min_ds_timeout[1], max_ds_timeout[] = {65535000}; +#endif -static const ctl_table ax25_param_table[] = { +static const struct ctl_table ax25_param_table[] = { { - .ctl_name = NET_AX25_IP_DEFAULT_MODE, .procname = "ip_default_mode", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, .extra1 = &min_ipdefmode, .extra2 = &max_ipdefmode }, { - .ctl_name = NET_AX25_DEFAULT_MODE, .procname = "ax25_default_mode", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, .extra1 = &min_axdefmode, .extra2 = &max_axdefmode }, { - .ctl_name = NET_AX25_BACKOFF_TYPE, .procname = "backoff_type", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, .extra1 = &min_backoff, .extra2 = &max_backoff }, { - .ctl_name = NET_AX25_CONNECT_MODE, .procname = "connect_mode", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, .extra1 = &min_conmode, .extra2 = &max_conmode }, { - .ctl_name = NET_AX25_STANDARD_WINDOW, .procname = "standard_window_size", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, .extra1 = &min_window, .extra2 = &max_window }, { - .ctl_name = NET_AX25_EXTENDED_WINDOW, .procname = "extended_window_size", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, .extra1 = &min_ewindow, .extra2 = &max_ewindow }, { - .ctl_name = NET_AX25_T1_TIMEOUT, .procname = "t1_timeout", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, .extra1 = &min_t1, .extra2 = &max_t1 }, { - .ctl_name = NET_AX25_T2_TIMEOUT, .procname = "t2_timeout", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, .extra1 = &min_t2, .extra2 = &max_t2 }, { - .ctl_name = NET_AX25_T3_TIMEOUT, .procname = "t3_timeout", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, .extra1 = &min_t3, .extra2 = &max_t3 }, { - .ctl_name = NET_AX25_IDLE_TIMEOUT, .procname = "idle_timeout", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, .extra1 = &min_idle, .extra2 = &max_idle }, { - .ctl_name = NET_AX25_N2, .procname = "maximum_retry_count", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, .extra1 = &min_n2, .extra2 = &max_n2 }, { - .ctl_name = NET_AX25_PACLEN, .procname = "maximum_packet_length", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, .extra1 = &min_paclen, .extra2 = &max_paclen }, { - .ctl_name = NET_AX25_PROTOCOL, .procname = "protocol", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, .extra1 = &min_proto, .extra2 = &max_proto }, +#ifdef CONFIG_AX25_DAMA_SLAVE { - .ctl_name = NET_AX25_DAMA_SLAVE_TIMEOUT, .procname = "dama_slave_timeout", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, .extra1 = &min_ds_timeout, .extra2 = &max_ds_timeout }, - { .ctl_name = 0 } /* that's all, folks! */ -}; - -void ax25_register_sysctl(void) -{ - ax25_dev *ax25_dev; - int n, k; - - spin_lock_bh(&ax25_dev_lock); - for (ax25_table_size = sizeof(ctl_table), ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next) - ax25_table_size += sizeof(ctl_table); - - if ((ax25_table = kmalloc(ax25_table_size, GFP_ATOMIC)) == NULL) { - spin_unlock_bh(&ax25_dev_lock); - return; - } - - memset(ax25_table, 0x00, ax25_table_size); - - for (n = 0, ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next) { - ctl_table *child = kmalloc(sizeof(ax25_param_table), GFP_ATOMIC); - if (!child) { - while (n--) - kfree(ax25_table[n].child); - kfree(ax25_table); - spin_unlock_bh(&ax25_dev_lock); - return; - } - memcpy(child, ax25_param_table, sizeof(ax25_param_table)); - ax25_table[n].child = ax25_dev->systable = child; - ax25_table[n].ctl_name = n + 1; - ax25_table[n].procname = ax25_dev->dev->name; - ax25_table[n].mode = 0555; - -#ifndef CONFIG_AX25_DAMA_SLAVE - /* - * We do not wish to have a representation of this parameter - * in /proc/sys/ when configured *not* to include the - * AX.25 DAMA slave code, do we? - */ - - child[AX25_VALUES_DS_TIMEOUT].procname = NULL; #endif - child[AX25_MAX_VALUES].ctl_name = 0; /* just in case... */ - - for (k = 0; k < AX25_MAX_VALUES; k++) - child[k].data = &ax25_dev->values[k]; + { } /* that's all, folks! */ +}; - n++; +int ax25_register_dev_sysctl(ax25_dev *ax25_dev) +{ + char path[sizeof("net/ax25/") + IFNAMSIZ]; + int k; + struct ctl_table *table; + + table = kmemdup(ax25_param_table, sizeof(ax25_param_table), GFP_KERNEL); + if (!table) + return -ENOMEM; + + for (k = 0; k < AX25_MAX_VALUES; k++) + table[k].data = &ax25_dev->values[k]; + + snprintf(path, sizeof(path), "net/ax25/%s", ax25_dev->dev->name); + ax25_dev->sysheader = register_net_sysctl(&init_net, path, table); + if (!ax25_dev->sysheader) { + kfree(table); + return -ENOMEM; } - spin_unlock_bh(&ax25_dev_lock); - - ax25_dir_table[0].child = ax25_table; - - ax25_table_header = register_sysctl_table(ax25_root_table, 1); + return 0; } -void ax25_unregister_sysctl(void) +void ax25_unregister_dev_sysctl(ax25_dev *ax25_dev) { - ctl_table *p; - unregister_sysctl_table(ax25_table_header); - - ax25_dir_table[0].child = NULL; - for (p = ax25_table; p->ctl_name; p++) - kfree(p->child); - kfree(ax25_table); + struct ctl_table_header *header = ax25_dev->sysheader; + struct ctl_table *table; + + if (header) { + ax25_dev->sysheader = NULL; + table = header->ctl_table_arg; + unregister_net_sysctl_table(header); + kfree(table); + } } |
