Commit 92acfab5 authored by Arnaldo Carvalho de Melo's avatar Arnaldo Carvalho de Melo Committed by David S. Miller

o X25: use refcounts and protect x25_route list

Also rename untypedefed x25_cb, renaming it to x25_opt, to make
it look like the other protocols.

Added some kerneldoc comments.
parent 7da34c58
...@@ -101,11 +101,20 @@ enum { ...@@ -101,11 +101,20 @@ enum {
#define X25_MAX_FAC_LEN 20 /* Plenty to spare */ #define X25_MAX_FAC_LEN 20 /* Plenty to spare */
#define X25_MAX_CUD_LEN 128 #define X25_MAX_CUD_LEN 128
/**
* struct x25_route - x25 routing entry
* @node - entry in x25_list_lock
* @address - Start of address range
* @sigdigits - Number of sig digits
* @dev - More than one for MLP
* @refcnt - reference counter
*/
struct x25_route { struct x25_route {
struct x25_route *next; struct list_head node;
struct x25_address address; /* Start of address range */ struct x25_address address;
unsigned int sigdigits; /* Number of sig digits */ unsigned int sigdigits;
struct net_device *dev; /* More than one for MLP */ struct net_device *dev;
atomic_t refcnt;
}; };
struct x25_neigh { struct x25_neigh {
...@@ -119,7 +128,7 @@ struct x25_neigh { ...@@ -119,7 +128,7 @@ struct x25_neigh {
unsigned long global_facil_mask; unsigned long global_facil_mask;
}; };
typedef struct { struct x25_opt {
struct x25_address source_addr, dest_addr; struct x25_address source_addr, dest_addr;
struct x25_neigh *neighbour; struct x25_neigh *neighbour;
unsigned int lci; unsigned int lci;
...@@ -137,9 +146,9 @@ typedef struct { ...@@ -137,9 +146,9 @@ typedef struct {
struct x25_facilities facilities; struct x25_facilities facilities;
struct x25_calluserdata calluserdata; struct x25_calluserdata calluserdata;
unsigned long vc_facil_mask; /* inc_call facilities mask */ unsigned long vc_facil_mask; /* inc_call facilities mask */
} x25_cb; };
#define x25_sk(__sk) ((x25_cb *)(__sk)->protinfo) #define x25_sk(__sk) ((struct x25_opt *)(__sk)->protinfo)
/* af_x25.c */ /* af_x25.c */
extern int sysctl_x25_restart_request_timeout; extern int sysctl_x25_restart_request_timeout;
...@@ -196,13 +205,24 @@ extern void x25_kick(struct sock *); ...@@ -196,13 +205,24 @@ extern void x25_kick(struct sock *);
extern void x25_enquiry_response(struct sock *); extern void x25_enquiry_response(struct sock *);
/* x25_route.c */ /* x25_route.c */
extern struct net_device *x25_get_route(struct x25_address *); extern struct x25_route *x25_get_route(struct x25_address *addr);
extern struct net_device *x25_dev_get(char *); extern struct net_device *x25_dev_get(char *);
extern void x25_route_device_down(struct net_device *); extern void x25_route_device_down(struct net_device *);
extern int x25_route_ioctl(unsigned int, void *); extern int x25_route_ioctl(unsigned int, void *);
extern int x25_routes_get_info(char *, char **, off_t, int); extern int x25_routes_get_info(char *, char **, off_t, int);
extern void x25_route_free(void); extern void x25_route_free(void);
static __inline__ void x25_route_hold(struct x25_route *rt)
{
atomic_inc(&rt->refcnt);
}
static __inline__ void x25_route_put(struct x25_route *rt)
{
if (atomic_dec_and_test(&rt->refcnt))
kfree(rt);
}
/* x25_subr.c */ /* x25_subr.c */
extern void x25_clear_queues(struct sock *); extern void x25_clear_queues(struct sock *);
extern void x25_frames_acked(struct sock *, unsigned short); extern void x25_frames_acked(struct sock *, unsigned short);
......
...@@ -421,7 +421,7 @@ static int x25_listen(struct socket *sock, int backlog) ...@@ -421,7 +421,7 @@ static int x25_listen(struct socket *sock, int backlog)
static struct sock *x25_alloc_socket(void) static struct sock *x25_alloc_socket(void)
{ {
struct sock *sk; struct sock *sk;
x25_cb *x25; struct x25_opt *x25;
MOD_INC_USE_COUNT; MOD_INC_USE_COUNT;
...@@ -455,7 +455,7 @@ static struct sock *x25_alloc_socket(void) ...@@ -455,7 +455,7 @@ static struct sock *x25_alloc_socket(void)
static int x25_create(struct socket *sock, int protocol) static int x25_create(struct socket *sock, int protocol)
{ {
struct sock *sk; struct sock *sk;
x25_cb *x25; struct x25_opt *x25;
int rc = -ESOCKTNOSUPPORT; int rc = -ESOCKTNOSUPPORT;
if (sock->type != SOCK_SEQPACKET || protocol) if (sock->type != SOCK_SEQPACKET || protocol)
...@@ -495,7 +495,7 @@ static int x25_create(struct socket *sock, int protocol) ...@@ -495,7 +495,7 @@ static int x25_create(struct socket *sock, int protocol)
static struct sock *x25_make_new(struct sock *osk) static struct sock *x25_make_new(struct sock *osk)
{ {
struct sock *sk = NULL; struct sock *sk = NULL;
x25_cb *x25, *ox25; struct x25_opt *x25, *ox25;
if (osk->type != SOCK_SEQPACKET) if (osk->type != SOCK_SEQPACKET)
goto out; goto out;
...@@ -533,7 +533,7 @@ static struct sock *x25_make_new(struct sock *osk) ...@@ -533,7 +533,7 @@ static struct sock *x25_make_new(struct sock *osk)
static int x25_release(struct socket *sock) static int x25_release(struct socket *sock)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
x25_cb *x25; struct x25_opt *x25;
if (!sk) if (!sk)
goto out; goto out;
...@@ -590,9 +590,9 @@ static int x25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) ...@@ -590,9 +590,9 @@ static int x25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags) static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
x25_cb *x25 = x25_sk(sk); struct x25_opt *x25 = x25_sk(sk);
struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr; struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr;
struct net_device *dev; struct x25_route *rt;
int rc = 0; int rc = 0;
if (sk->state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) { if (sk->state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) {
...@@ -619,23 +619,23 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len ...@@ -619,23 +619,23 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len
goto out; goto out;
rc = -ENETUNREACH; rc = -ENETUNREACH;
dev = x25_get_route(&addr->sx25_addr); rt = x25_get_route(&addr->sx25_addr);
if (!dev) if (!rt)
goto out; goto out;
x25->neighbour = x25_get_neigh(dev); x25->neighbour = x25_get_neigh(rt->dev);
if (!x25->neighbour) if (!x25->neighbour)
goto out; goto out_put_route;
x25_limit_facilities(&x25->facilities, x25->neighbour); x25_limit_facilities(&x25->facilities, x25->neighbour);
x25->lci = x25_new_lci(x25->neighbour); x25->lci = x25_new_lci(x25->neighbour);
if (!x25->lci) if (!x25->lci)
goto out; goto out_put_route;
rc = -EINVAL; rc = -EINVAL;
if (sk->zapped) /* Must bind first - autobinding does not work */ if (sk->zapped) /* Must bind first - autobinding does not work */
goto out; goto out_put_route;
if (!strcmp(x25->source_addr.x25_addr, null_x25_address.x25_addr)) if (!strcmp(x25->source_addr.x25_addr, null_x25_address.x25_addr))
memset(&x25->source_addr, '\0', X25_ADDR_LEN); memset(&x25->source_addr, '\0', X25_ADDR_LEN);
...@@ -656,7 +656,7 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len ...@@ -656,7 +656,7 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len
/* Now the loop */ /* Now the loop */
rc = -EINPROGRESS; rc = -EINPROGRESS;
if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
goto out; goto out_put_route;
cli(); /* To avoid races on the sleep */ cli(); /* To avoid races on the sleep */
...@@ -681,6 +681,8 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len ...@@ -681,6 +681,8 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len
rc = 0; rc = 0;
out_unlock: out_unlock:
sti(); sti();
out_put_route:
x25_route_put(rt);
out: out:
return rc; return rc;
} }
...@@ -741,7 +743,7 @@ static int x25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_l ...@@ -741,7 +743,7 @@ static int x25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_l
{ {
struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)uaddr; struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)uaddr;
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
x25_cb *x25 = x25_sk(sk); struct x25_opt *x25 = x25_sk(sk);
if (peer) { if (peer) {
if (sk->state != TCP_ESTABLISHED) if (sk->state != TCP_ESTABLISHED)
...@@ -760,7 +762,7 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned i ...@@ -760,7 +762,7 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned i
{ {
struct sock *sk; struct sock *sk;
struct sock *make; struct sock *make;
x25_cb *makex25; struct x25_opt *makex25;
struct x25_address source_addr, dest_addr; struct x25_address source_addr, dest_addr;
struct x25_facilities facilities; struct x25_facilities facilities;
int len, rc; int len, rc;
...@@ -858,7 +860,7 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned i ...@@ -858,7 +860,7 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned i
static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm) static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
x25_cb *x25 = x25_sk(sk); struct x25_opt *x25 = x25_sk(sk);
struct sockaddr_x25 *usx25 = (struct sockaddr_x25 *)msg->msg_name; struct sockaddr_x25 *usx25 = (struct sockaddr_x25 *)msg->msg_name;
struct sockaddr_x25 sx25; struct sockaddr_x25 sx25;
struct sk_buff *skb; struct sk_buff *skb;
...@@ -1033,7 +1035,7 @@ static int x25_recvmsg(struct socket *sock, struct msghdr *msg, int size, ...@@ -1033,7 +1035,7 @@ static int x25_recvmsg(struct socket *sock, struct msghdr *msg, int size,
int flags, struct scm_cookie *scm) int flags, struct scm_cookie *scm)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
x25_cb *x25 = x25_sk(sk); struct x25_opt *x25 = x25_sk(sk);
struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)msg->msg_name; struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)msg->msg_name;
int copied, qbit; int copied, qbit;
struct sk_buff *skb; struct sk_buff *skb;
...@@ -1119,7 +1121,7 @@ static int x25_recvmsg(struct socket *sock, struct msghdr *msg, int size, ...@@ -1119,7 +1121,7 @@ static int x25_recvmsg(struct socket *sock, struct msghdr *msg, int size,
static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
x25_cb *x25 = x25_sk(sk); struct x25_opt *x25 = x25_sk(sk);
int rc; int rc;
switch (cmd) { switch (cmd) {
...@@ -1266,7 +1268,7 @@ static int x25_get_info(char *buffer, char **start, off_t offset, int length) ...@@ -1266,7 +1268,7 @@ static int x25_get_info(char *buffer, char **start, off_t offset, int length)
"t t2 t21 t22 t23 Snd-Q Rcv-Q inode\n"); "t t2 t21 t22 t23 Snd-Q Rcv-Q inode\n");
for (s = x25_list; s; s = s->next) { for (s = x25_list; s; s = s->next) {
x25_cb *x25 = x25_sk(s); struct x25_opt *x25 = x25_sk(s);
if (!x25->neighbour || (dev = x25->neighbour->dev) == NULL) if (!x25->neighbour || (dev = x25->neighbour->dev) == NULL)
devname = "???"; devname = "???";
......
...@@ -172,7 +172,7 @@ int x25_create_facilities(unsigned char *buffer, ...@@ -172,7 +172,7 @@ int x25_create_facilities(unsigned char *buffer,
int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk, int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk,
struct x25_facilities *new) struct x25_facilities *new)
{ {
x25_cb *x25 = x25_sk(sk); struct x25_opt *x25 = x25_sk(sk);
struct x25_facilities *ours = &x25->facilities; struct x25_facilities *ours = &x25->facilities;
struct x25_facilities theirs; struct x25_facilities theirs;
int len; int len;
......
...@@ -48,7 +48,7 @@ ...@@ -48,7 +48,7 @@
static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more) static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
{ {
struct sk_buff *skbo, *skbn = skb; struct sk_buff *skbo, *skbn = skb;
x25_cb *x25 = x25_sk(sk); struct x25_opt *x25 = x25_sk(sk);
if (more) { if (more) {
x25->fraglen += skb->len; x25->fraglen += skb->len;
...@@ -103,7 +103,7 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp ...@@ -103,7 +103,7 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp
switch (frametype) { switch (frametype) {
case X25_CALL_ACCEPTED: { case X25_CALL_ACCEPTED: {
x25_cb *x25 = x25_sk(sk); struct x25_opt *x25 = x25_sk(sk);
x25_stop_timer(sk); x25_stop_timer(sk);
x25->condition = 0x00; x25->condition = 0x00;
...@@ -179,7 +179,7 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp ...@@ -179,7 +179,7 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
{ {
int queued = 0; int queued = 0;
int modulus; int modulus;
x25_cb *x25 = x25_sk(sk); struct x25_opt *x25 = x25_sk(sk);
modulus = (x25->neighbour->extended) ? X25_EMODULUS : X25_SMODULUS; modulus = (x25->neighbour->extended) ? X25_EMODULUS : X25_SMODULUS;
...@@ -308,7 +308,7 @@ static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametyp ...@@ -308,7 +308,7 @@ static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametyp
case X25_RESET_REQUEST: case X25_RESET_REQUEST:
x25_write_internal(sk, X25_RESET_CONFIRMATION); x25_write_internal(sk, X25_RESET_CONFIRMATION);
case X25_RESET_CONFIRMATION: { case X25_RESET_CONFIRMATION: {
x25_cb *x25 = x25_sk(sk); struct x25_opt *x25 = x25_sk(sk);
x25_stop_timer(sk); x25_stop_timer(sk);
x25->condition = 0x00; x25->condition = 0x00;
...@@ -335,7 +335,7 @@ static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametyp ...@@ -335,7 +335,7 @@ static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametyp
/* Higher level upcall for a LAPB frame */ /* Higher level upcall for a LAPB frame */
int x25_process_rx_frame(struct sock *sk, struct sk_buff *skb) int x25_process_rx_frame(struct sock *sk, struct sk_buff *skb)
{ {
x25_cb *x25 = x25_sk(sk); struct x25_opt *x25 = x25_sk(sk);
int queued = 0, frametype, ns, nr, q, d, m; int queued = 0, frametype, ns, nr, q, d, m;
if (x25->state == X25_STATE_0) if (x25->state == X25_STATE_0)
......
...@@ -67,7 +67,7 @@ int x25_output(struct sock *sk, struct sk_buff *skb) ...@@ -67,7 +67,7 @@ int x25_output(struct sock *sk, struct sk_buff *skb)
unsigned char header[X25_EXT_MIN_LEN]; unsigned char header[X25_EXT_MIN_LEN];
int err, frontlen, len; int err, frontlen, len;
int sent=0, noblock = X25_SKB_CB(skb)->flags & MSG_DONTWAIT; int sent=0, noblock = X25_SKB_CB(skb)->flags & MSG_DONTWAIT;
x25_cb *x25 = x25_sk(sk); struct x25_opt *x25 = x25_sk(sk);
int header_len = x25->neighbour->extended ? X25_EXT_MIN_LEN : int header_len = x25->neighbour->extended ? X25_EXT_MIN_LEN :
X25_STD_MIN_LEN; X25_STD_MIN_LEN;
int max_len = x25_pacsize_to_bytes(x25->facilities.pacsize_out); int max_len = x25_pacsize_to_bytes(x25->facilities.pacsize_out);
...@@ -129,7 +129,7 @@ int x25_output(struct sock *sk, struct sk_buff *skb) ...@@ -129,7 +129,7 @@ int x25_output(struct sock *sk, struct sk_buff *skb)
*/ */
static void x25_send_iframe(struct sock *sk, struct sk_buff *skb) static void x25_send_iframe(struct sock *sk, struct sk_buff *skb)
{ {
x25_cb *x25 = x25_sk(sk); struct x25_opt *x25 = x25_sk(sk);
if (!skb) if (!skb)
return; return;
...@@ -152,7 +152,7 @@ void x25_kick(struct sock *sk) ...@@ -152,7 +152,7 @@ void x25_kick(struct sock *sk)
struct sk_buff *skb, *skbn; struct sk_buff *skb, *skbn;
unsigned short start, end; unsigned short start, end;
int modulus; int modulus;
x25_cb *x25 = x25_sk(sk); struct x25_opt *x25 = x25_sk(sk);
if (x25->state != X25_STATE_3) if (x25->state != X25_STATE_3)
return; return;
...@@ -224,7 +224,7 @@ void x25_kick(struct sock *sk) ...@@ -224,7 +224,7 @@ void x25_kick(struct sock *sk)
void x25_enquiry_response(struct sock *sk) void x25_enquiry_response(struct sock *sk)
{ {
x25_cb *x25 = x25_sk(sk); struct x25_opt *x25 = x25_sk(sk);
if (x25->condition & X25_COND_OWN_RX_BUSY) if (x25->condition & X25_COND_OWN_RX_BUSY)
x25_write_internal(sk, X25_RNR); x25_write_internal(sk, X25_RNR);
......
...@@ -44,7 +44,8 @@ ...@@ -44,7 +44,8 @@
#include <linux/init.h> #include <linux/init.h>
#include <net/x25.h> #include <net/x25.h>
static struct x25_route *x25_route_list; /* = NULL initially */ static struct list_head x25_route_list = LIST_HEAD_INIT(x25_route_list);
static rwlock_t x25_route_list_lock = RW_LOCK_UNLOCKED;
/* /*
* Add a new route. * Add a new route.
...@@ -52,80 +53,75 @@ static struct x25_route *x25_route_list; /* = NULL initially */ ...@@ -52,80 +53,75 @@ static struct x25_route *x25_route_list; /* = NULL initially */
static int x25_add_route(struct x25_address *address, unsigned int sigdigits, static int x25_add_route(struct x25_address *address, unsigned int sigdigits,
struct net_device *dev) struct net_device *dev)
{ {
struct x25_route *x25_route; struct x25_route *rt;
unsigned long flags; struct list_head *entry;
int rc = -EINVAL; int rc = -EINVAL;
for (x25_route = x25_route_list; x25_route; x25_route = x25_route->next) write_lock_bh(&x25_route_list_lock);
if (!memcmp(&x25_route->address, address, sigdigits) &&
x25_route->sigdigits == sigdigits) list_for_each(entry, &x25_route_list) {
rt = list_entry(entry, struct x25_route, node);
if (!memcmp(&rt->address, address, sigdigits) &&
rt->sigdigits == sigdigits)
goto out; goto out;
}
x25_route = kmalloc(sizeof(*x25_route), GFP_ATOMIC); rt = kmalloc(sizeof(*rt), GFP_ATOMIC);
rc = -ENOMEM; rc = -ENOMEM;
if (!x25_route) if (!rt)
goto out; goto out;
strcpy(x25_route->address.x25_addr, "000000000000000"); strcpy(rt->address.x25_addr, "000000000000000");
memcpy(x25_route->address.x25_addr, address->x25_addr, sigdigits); memcpy(rt->address.x25_addr, address->x25_addr, sigdigits);
x25_route->sigdigits = sigdigits; rt->sigdigits = sigdigits;
x25_route->dev = dev; rt->dev = dev;
atomic_set(&rt->refcnt, 1);
save_flags(flags); cli(); list_add(&rt->node, &x25_route_list);
x25_route->next = x25_route_list;
x25_route_list = x25_route;
restore_flags(flags);
rc = 0; rc = 0;
out: out:
write_unlock_bh(&x25_route_list_lock);
return rc; return rc;
} }
static void x25_remove_route(struct x25_route *x25_route) /**
* __x25_remove_route - remove route from x25_route_list
* @rt - route to remove
*
* Remove route from x25_route_list. If it was there.
* Caller must hold x25_route_list_lock.
*/
static void __x25_remove_route(struct x25_route *rt)
{ {
struct x25_route *s; if (rt->node.next) {
unsigned long flags; list_del(&rt->node);
x25_route_put(rt);
save_flags(flags);
cli();
if ((s = x25_route_list) == x25_route) {
x25_route_list = x25_route->next;
restore_flags(flags);
return;
} }
while (s && s->next) {
if (s->next == x25_route) {
s->next = x25_route->next;
goto out_kfree_route;
}
s = s->next;
}
out:
restore_flags(flags);
return;
out_kfree_route:
kfree(x25_route);
goto out;
} }
static int x25_del_route(struct x25_address *address, unsigned int sigdigits, static int x25_del_route(struct x25_address *address, unsigned int sigdigits,
struct net_device *dev) struct net_device *dev)
{ {
struct x25_route *x25_route = x25_route_list; struct x25_route *rt;
struct list_head *entry;
int rc = -EINVAL; int rc = -EINVAL;
for (; x25_route; x25_route = x25_route->next) write_lock_bh(&x25_route_list_lock);
if (!memcmp(&x25_route->address, address, sigdigits) &&
x25_route->sigdigits == sigdigits && list_for_each(entry, &x25_route_list) {
x25_route->dev == dev) { rt = list_entry(entry, struct x25_route, node);
x25_remove_route(x25_route);
if (!memcmp(&rt->address, address, sigdigits) &&
rt->sigdigits == sigdigits && rt->dev == dev) {
__x25_remove_route(rt);
rc = 0; rc = 0;
break; break;
} }
}
write_unlock_bh(&x25_route_list_lock);
return rc; return rc;
} }
...@@ -134,15 +130,18 @@ static int x25_del_route(struct x25_address *address, unsigned int sigdigits, ...@@ -134,15 +130,18 @@ static int x25_del_route(struct x25_address *address, unsigned int sigdigits,
*/ */
void x25_route_device_down(struct net_device *dev) void x25_route_device_down(struct net_device *dev)
{ {
struct x25_route *route, *x25_route = x25_route_list; struct x25_route *rt;
struct list_head *entry, *tmp;
while (x25_route) { write_lock_bh(&x25_route_list_lock);
route = x25_route;
x25_route = x25_route->next;
if (route->dev == dev) list_for_each_safe(entry, tmp, &x25_route_list) {
x25_remove_route(route); rt = list_entry(entry, struct x25_route, node);
if (rt->dev == dev)
__x25_remove_route(rt);
} }
write_unlock_bh(&x25_route_list_lock);
} }
/* /*
...@@ -163,22 +162,35 @@ struct net_device *x25_dev_get(char *devname) ...@@ -163,22 +162,35 @@ struct net_device *x25_dev_get(char *devname)
return dev; return dev;
} }
/* /**
* Find a device given an X.25 address. * x25_get_route - Find a route given an X.25 address.
* @addr - address to find a route for
*
* Find a route given an X.25 address.
*/ */
struct net_device *x25_get_route(struct x25_address *addr) struct x25_route *x25_get_route(struct x25_address *addr)
{ {
struct x25_route *route, *use = NULL; struct x25_route *rt, *use = NULL;
struct list_head *entry;
for (route = x25_route_list; route; route = route->next) read_lock_bh(&x25_route_list_lock);
if (!memcmp(&route->address, addr, route->sigdigits)) {
list_for_each(entry, &x25_route_list) {
rt = list_entry(entry, struct x25_route, node);
if (!memcmp(&rt->address, addr, rt->sigdigits)) {
if (!use) if (!use)
use = route; use = rt;
else if (route->sigdigits > use->sigdigits) else if (rt->sigdigits > use->sigdigits)
use = route; use = rt;
}
} }
return use ? use->dev : NULL; if (use)
x25_route_hold(use);
read_unlock_bh(&x25_route_list_lock);
return use;
} }
/* /*
...@@ -186,7 +198,7 @@ struct net_device *x25_get_route(struct x25_address *addr) ...@@ -186,7 +198,7 @@ struct net_device *x25_get_route(struct x25_address *addr)
*/ */
int x25_route_ioctl(unsigned int cmd, void *arg) int x25_route_ioctl(unsigned int cmd, void *arg)
{ {
struct x25_route_struct x25_route; struct x25_route_struct rt;
struct net_device *dev; struct net_device *dev;
int rc = -EINVAL; int rc = -EINVAL;
...@@ -194,21 +206,21 @@ int x25_route_ioctl(unsigned int cmd, void *arg) ...@@ -194,21 +206,21 @@ int x25_route_ioctl(unsigned int cmd, void *arg)
goto out; goto out;
rc = -EFAULT; rc = -EFAULT;
if (copy_from_user(&x25_route, arg, sizeof(x25_route))) if (copy_from_user(&rt, arg, sizeof(rt)))
goto out; goto out;
rc = -EINVAL; rc = -EINVAL;
if (x25_route.sigdigits < 0 || x25_route.sigdigits > 15) if (rt.sigdigits < 0 || rt.sigdigits > 15)
goto out; goto out;
dev = x25_dev_get(x25_route.device); dev = x25_dev_get(rt.device);
if (!dev) if (!dev)
goto out; goto out;
if (cmd == SIOCADDRT) if (cmd == SIOCADDRT)
rc = x25_add_route(&x25_route.address, x25_route.sigdigits, dev); rc = x25_add_route(&rt.address, rt.sigdigits, dev);
else else
rc = x25_del_route(&x25_route.address, x25_route.sigdigits, dev); rc = x25_del_route(&rt.address, rt.sigdigits, dev);
dev_put(dev); dev_put(dev);
out: out:
return rc; return rc;
...@@ -216,20 +228,20 @@ int x25_route_ioctl(unsigned int cmd, void *arg) ...@@ -216,20 +228,20 @@ int x25_route_ioctl(unsigned int cmd, void *arg)
int x25_routes_get_info(char *buffer, char **start, off_t offset, int length) int x25_routes_get_info(char *buffer, char **start, off_t offset, int length)
{ {
struct x25_route *x25_route; struct x25_route *rt;
int len; struct list_head *entry;
off_t pos = 0; off_t pos = 0;
off_t begin = 0; off_t begin = 0;
int len = sprintf(buffer, "address digits device\n");
cli(); read_lock_bh(&x25_route_list_lock);
len = sprintf(buffer, "address digits device\n");
for (x25_route = x25_route_list; x25_route; x25_route = x25_route->next) { list_for_each(entry, &x25_route_list) {
rt = list_entry(entry, struct x25_route, node);
len += sprintf(buffer + len, "%-15s %-6d %-5s\n", len += sprintf(buffer + len, "%-15s %-6d %-5s\n",
x25_route->address.x25_addr, rt->address.x25_addr,
x25_route->sigdigits, rt->sigdigits,
x25_route->dev ? x25_route->dev->name : "???"); rt->dev ? rt->dev->name : "???");
pos = begin + len; pos = begin + len;
...@@ -242,7 +254,7 @@ int x25_routes_get_info(char *buffer, char **start, off_t offset, int length) ...@@ -242,7 +254,7 @@ int x25_routes_get_info(char *buffer, char **start, off_t offset, int length)
break; break;
} }
sti(); read_unlock_bh(&x25_route_list_lock);
*start = buffer + (offset - begin); *start = buffer + (offset - begin);
len -= (offset - begin); len -= (offset - begin);
...@@ -258,12 +270,13 @@ int x25_routes_get_info(char *buffer, char **start, off_t offset, int length) ...@@ -258,12 +270,13 @@ int x25_routes_get_info(char *buffer, char **start, off_t offset, int length)
*/ */
void __exit x25_route_free(void) void __exit x25_route_free(void)
{ {
struct x25_route *route, *x25_route = x25_route_list; struct x25_route *rt;
struct list_head *entry, *tmp;
while (x25_route) {
route = x25_route;
x25_route = x25_route->next;
x25_remove_route(route); write_lock_bh(&x25_route_list_lock);
list_for_each_safe(entry, tmp, &x25_route_list) {
rt = list_entry(entry, struct x25_route, node);
__x25_remove_route(rt);
} }
write_unlock_bh(&x25_route_list_lock);
} }
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
*/ */
void x25_clear_queues(struct sock *sk) void x25_clear_queues(struct sock *sk)
{ {
x25_cb *x25 = x25_sk(sk); struct x25_opt *x25 = x25_sk(sk);
skb_queue_purge(&sk->write_queue); skb_queue_purge(&sk->write_queue);
skb_queue_purge(&x25->ack_queue); skb_queue_purge(&x25->ack_queue);
...@@ -65,7 +65,7 @@ void x25_clear_queues(struct sock *sk) ...@@ -65,7 +65,7 @@ void x25_clear_queues(struct sock *sk)
void x25_frames_acked(struct sock *sk, unsigned short nr) void x25_frames_acked(struct sock *sk, unsigned short nr)
{ {
struct sk_buff *skb; struct sk_buff *skb;
x25_cb *x25 = x25_sk(sk); struct x25_opt *x25 = x25_sk(sk);
int modulus = x25->neighbour->extended ? X25_EMODULUS : X25_SMODULUS; int modulus = x25->neighbour->extended ? X25_EMODULUS : X25_SMODULUS;
/* /*
...@@ -103,7 +103,7 @@ void x25_requeue_frames(struct sock *sk) ...@@ -103,7 +103,7 @@ void x25_requeue_frames(struct sock *sk)
*/ */
int x25_validate_nr(struct sock *sk, unsigned short nr) int x25_validate_nr(struct sock *sk, unsigned short nr)
{ {
x25_cb *x25 = x25_sk(sk); struct x25_opt *x25 = x25_sk(sk);
unsigned short vc = x25->va; unsigned short vc = x25->va;
int modulus = x25->neighbour->extended ? X25_EMODULUS : X25_SMODULUS; int modulus = x25->neighbour->extended ? X25_EMODULUS : X25_SMODULUS;
...@@ -122,7 +122,7 @@ int x25_validate_nr(struct sock *sk, unsigned short nr) ...@@ -122,7 +122,7 @@ int x25_validate_nr(struct sock *sk, unsigned short nr)
*/ */
void x25_write_internal(struct sock *sk, int frametype) void x25_write_internal(struct sock *sk, int frametype)
{ {
x25_cb *x25 = x25_sk(sk); struct x25_opt *x25 = x25_sk(sk);
struct sk_buff *skb; struct sk_buff *skb;
unsigned char *dptr; unsigned char *dptr;
unsigned char facilities[X25_MAX_FAC_LEN]; unsigned char facilities[X25_MAX_FAC_LEN];
...@@ -262,7 +262,7 @@ void x25_write_internal(struct sock *sk, int frametype) ...@@ -262,7 +262,7 @@ void x25_write_internal(struct sock *sk, int frametype)
int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q, int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q,
int *d, int *m) int *d, int *m)
{ {
x25_cb *x25 = x25_sk(sk); struct x25_opt *x25 = x25_sk(sk);
unsigned char *frame = skb->data; unsigned char *frame = skb->data;
*ns = *nr = *q = *d = *m = 0; *ns = *nr = *q = *d = *m = 0;
...@@ -329,7 +329,7 @@ int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q, ...@@ -329,7 +329,7 @@ int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q,
void x25_disconnect(struct sock *sk, int reason, unsigned char cause, void x25_disconnect(struct sock *sk, int reason, unsigned char cause,
unsigned char diagnostic) unsigned char diagnostic)
{ {
x25_cb *x25 = x25_sk(sk); struct x25_opt *x25 = x25_sk(sk);
x25_clear_queues(sk); x25_clear_queues(sk);
x25_stop_timer(sk); x25_stop_timer(sk);
...@@ -356,7 +356,7 @@ void x25_disconnect(struct sock *sk, int reason, unsigned char cause, ...@@ -356,7 +356,7 @@ void x25_disconnect(struct sock *sk, int reason, unsigned char cause,
*/ */
void x25_check_rbuf(struct sock *sk) void x25_check_rbuf(struct sock *sk)
{ {
x25_cb *x25 = x25_sk(sk); struct x25_opt *x25 = x25_sk(sk);
if (atomic_read(&sk->rmem_alloc) < (sk->rcvbuf / 2) && if (atomic_read(&sk->rmem_alloc) < (sk->rcvbuf / 2) &&
(x25->condition & X25_COND_OWN_RX_BUSY)) { (x25->condition & X25_COND_OWN_RX_BUSY)) {
......
...@@ -61,7 +61,7 @@ void x25_stop_heartbeat(struct sock *sk) ...@@ -61,7 +61,7 @@ void x25_stop_heartbeat(struct sock *sk)
void x25_start_t2timer(struct sock *sk) void x25_start_t2timer(struct sock *sk)
{ {
x25_cb *x25 = x25_sk(sk); struct x25_opt *x25 = x25_sk(sk);
del_timer(&x25->timer); del_timer(&x25->timer);
...@@ -74,7 +74,7 @@ void x25_start_t2timer(struct sock *sk) ...@@ -74,7 +74,7 @@ void x25_start_t2timer(struct sock *sk)
void x25_start_t21timer(struct sock *sk) void x25_start_t21timer(struct sock *sk)
{ {
x25_cb *x25 = x25_sk(sk); struct x25_opt *x25 = x25_sk(sk);
del_timer(&x25->timer); del_timer(&x25->timer);
...@@ -87,7 +87,7 @@ void x25_start_t21timer(struct sock *sk) ...@@ -87,7 +87,7 @@ void x25_start_t21timer(struct sock *sk)
void x25_start_t22timer(struct sock *sk) void x25_start_t22timer(struct sock *sk)
{ {
x25_cb *x25 = x25_sk(sk); struct x25_opt *x25 = x25_sk(sk);
del_timer(&x25->timer); del_timer(&x25->timer);
...@@ -100,7 +100,7 @@ void x25_start_t22timer(struct sock *sk) ...@@ -100,7 +100,7 @@ void x25_start_t22timer(struct sock *sk)
void x25_start_t23timer(struct sock *sk) void x25_start_t23timer(struct sock *sk)
{ {
x25_cb *x25 = x25_sk(sk); struct x25_opt *x25 = x25_sk(sk);
del_timer(&x25->timer); del_timer(&x25->timer);
...@@ -118,7 +118,7 @@ void x25_stop_timer(struct sock *sk) ...@@ -118,7 +118,7 @@ void x25_stop_timer(struct sock *sk)
unsigned long x25_display_timer(struct sock *sk) unsigned long x25_display_timer(struct sock *sk)
{ {
x25_cb *x25 = x25_sk(sk); struct x25_opt *x25 = x25_sk(sk);
if (!timer_pending(&x25->timer)) if (!timer_pending(&x25->timer))
return 0; return 0;
...@@ -164,7 +164,7 @@ static void x25_heartbeat_expiry(unsigned long param) ...@@ -164,7 +164,7 @@ static void x25_heartbeat_expiry(unsigned long param)
*/ */
static inline void x25_do_timer_expiry(struct sock * sk) static inline void x25_do_timer_expiry(struct sock * sk)
{ {
x25_cb *x25 = x25_sk(sk); struct x25_opt *x25 = x25_sk(sk);
switch (x25->state) { switch (x25->state) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment