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

o X25: use refcnts and protect x25_neigh structs and list

Simplify some other code.
parent 92acfab5
...@@ -118,7 +118,7 @@ struct x25_route { ...@@ -118,7 +118,7 @@ struct x25_route {
}; };
struct x25_neigh { struct x25_neigh {
struct x25_neigh *next; struct list_head node;
struct net_device *dev; struct net_device *dev;
unsigned int state; unsigned int state;
unsigned int extended; unsigned int extended;
...@@ -126,6 +126,7 @@ struct x25_neigh { ...@@ -126,6 +126,7 @@ struct x25_neigh {
unsigned long t20; unsigned long t20;
struct timer_list t20timer; struct timer_list t20timer;
unsigned long global_facil_mask; unsigned long global_facil_mask;
atomic_t refcnt;
}; };
struct x25_opt { struct x25_opt {
...@@ -199,6 +200,18 @@ extern int x25_subscr_ioctl(unsigned int, void *); ...@@ -199,6 +200,18 @@ extern int x25_subscr_ioctl(unsigned int, void *);
extern struct x25_neigh *x25_get_neigh(struct net_device *); extern struct x25_neigh *x25_get_neigh(struct net_device *);
extern void x25_link_free(void); extern void x25_link_free(void);
/* x25_neigh.c */
static __inline__ void x25_neigh_hold(struct x25_neigh *nb)
{
atomic_inc(&nb->refcnt);
}
static __inline__ void x25_neigh_put(struct x25_neigh *nb)
{
if (atomic_dec_and_test(&nb->refcnt))
kfree(nb);
}
/* x25_out.c */ /* x25_out.c */
extern int x25_output(struct sock *, struct sk_buff *); extern int x25_output(struct sock *, struct sk_buff *);
extern void x25_kick(struct sock *); extern void x25_kick(struct sock *);
......
...@@ -188,7 +188,7 @@ static void x25_kill_by_device(struct net_device *dev) ...@@ -188,7 +188,7 @@ static void x25_kill_by_device(struct net_device *dev)
static int x25_device_event(struct notifier_block *this, unsigned long event, void *ptr) static int x25_device_event(struct notifier_block *this, unsigned long event, void *ptr)
{ {
struct net_device *dev = ptr; struct net_device *dev = ptr;
struct x25_neigh *neigh; struct x25_neigh *nb;
if (dev->type == ARPHRD_X25 if (dev->type == ARPHRD_X25
#if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE) #if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE)
...@@ -200,8 +200,11 @@ static int x25_device_event(struct notifier_block *this, unsigned long event, vo ...@@ -200,8 +200,11 @@ static int x25_device_event(struct notifier_block *this, unsigned long event, vo
x25_link_device_up(dev); x25_link_device_up(dev);
break; break;
case NETDEV_GOING_DOWN: case NETDEV_GOING_DOWN:
if ((neigh = x25_get_neigh(dev))) nb = x25_get_neigh(dev);
x25_terminate_link(neigh); if (nb) {
x25_terminate_link(nb);
x25_neigh_put(nb);
}
break; break;
case NETDEV_DOWN: case NETDEV_DOWN:
x25_kill_by_device(dev); x25_kill_by_device(dev);
...@@ -255,7 +258,7 @@ static struct sock *x25_find_listener(struct x25_address *addr) ...@@ -255,7 +258,7 @@ static struct sock *x25_find_listener(struct x25_address *addr)
/* /*
* Find a connected X.25 socket given my LCI and neighbour. * Find a connected X.25 socket given my LCI and neighbour.
*/ */
struct sock *x25_find_socket(unsigned int lci, struct x25_neigh *neigh) struct sock *x25_find_socket(unsigned int lci, struct x25_neigh *nb)
{ {
struct sock *s; struct sock *s;
unsigned long flags; unsigned long flags;
...@@ -264,7 +267,7 @@ struct sock *x25_find_socket(unsigned int lci, struct x25_neigh *neigh) ...@@ -264,7 +267,7 @@ struct sock *x25_find_socket(unsigned int lci, struct x25_neigh *neigh)
cli(); cli();
for (s = x25_list; s; s = s->next) for (s = x25_list; s; s = s->next)
if (x25_sk(s)->lci == lci && x25_sk(s)->neighbour == neigh) if (x25_sk(s)->lci == lci && x25_sk(s)->neighbour == nb)
break; break;
restore_flags(flags); restore_flags(flags);
...@@ -274,11 +277,11 @@ struct sock *x25_find_socket(unsigned int lci, struct x25_neigh *neigh) ...@@ -274,11 +277,11 @@ struct sock *x25_find_socket(unsigned int lci, struct x25_neigh *neigh)
/* /*
* Find a unique LCI for a given device. * Find a unique LCI for a given device.
*/ */
unsigned int x25_new_lci(struct x25_neigh *neigh) unsigned int x25_new_lci(struct x25_neigh *nb)
{ {
unsigned int lci = 1; unsigned int lci = 1;
while (x25_find_socket(lci, neigh)) while (x25_find_socket(lci, nb))
if (++lci == 4096) { if (++lci == 4096) {
lci = 0; lci = 0;
break; break;
...@@ -631,11 +634,11 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len ...@@ -631,11 +634,11 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len
x25->lci = x25_new_lci(x25->neighbour); x25->lci = x25_new_lci(x25->neighbour);
if (!x25->lci) if (!x25->lci)
goto out_put_route; goto out_put_neigh;
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_put_route; goto out_put_neigh;
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 +659,7 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len ...@@ -656,7 +659,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_put_route; goto out_put_neigh;
cli(); /* To avoid races on the sleep */ cli(); /* To avoid races on the sleep */
...@@ -681,6 +684,9 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len ...@@ -681,6 +684,9 @@ 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_neigh:
if (rc)
x25_neigh_put(x25->neighbour);
out_put_route: out_put_route:
x25_route_put(rt); x25_route_put(rt);
out: out:
...@@ -758,7 +764,7 @@ static int x25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_l ...@@ -758,7 +764,7 @@ static int x25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_l
return 0; return 0;
} }
int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned int lci) int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb, unsigned int lci)
{ {
struct sock *sk; struct sock *sk;
struct sock *make; struct sock *make;
...@@ -800,7 +806,7 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned i ...@@ -800,7 +806,7 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned i
* on certain facilties * on certain facilties
*/ */
x25_limit_facilities(&facilities,neigh); x25_limit_facilities(&facilities, nb);
/* /*
* Try to create a new socket. * Try to create a new socket.
...@@ -821,7 +827,7 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned i ...@@ -821,7 +827,7 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned i
makex25->lci = lci; makex25->lci = lci;
makex25->dest_addr = dest_addr; makex25->dest_addr = dest_addr;
makex25->source_addr = source_addr; makex25->source_addr = source_addr;
makex25->neighbour = neigh; makex25->neighbour = nb;
makex25->facilities = facilities; makex25->facilities = facilities;
makex25->vc_facil_mask = x25_sk(sk)->vc_facil_mask; makex25->vc_facil_mask = x25_sk(sk)->vc_facil_mask;
...@@ -853,7 +859,7 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned i ...@@ -853,7 +859,7 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned i
return rc; return rc;
out_clear_request: out_clear_request:
rc = 0; rc = 0;
x25_transmit_clear_request(neigh, lci, 0x01); x25_transmit_clear_request(nb, lci, 0x01);
goto out; goto out;
} }
...@@ -1358,12 +1364,12 @@ struct notifier_block x25_dev_notifier = { ...@@ -1358,12 +1364,12 @@ struct notifier_block x25_dev_notifier = {
.notifier_call = x25_device_event, .notifier_call = x25_device_event,
}; };
void x25_kill_by_neigh(struct x25_neigh *neigh) void x25_kill_by_neigh(struct x25_neigh *nb)
{ {
struct sock *s; struct sock *s;
for (s = x25_list; s; s = s->next) for (s = x25_list; s; s = s->next)
if (x25_sk(s)->neighbour == neigh) if (x25_sk(s)->neighbour == nb)
x25_disconnect(s, ENETUNREACH, 0, 0); x25_disconnect(s, ENETUNREACH, 0, 0);
} }
......
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <net/x25.h> #include <net/x25.h>
static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *neigh) static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *nb)
{ {
struct sock *sk; struct sock *sk;
unsigned short frametype; unsigned short frametype;
...@@ -58,14 +58,14 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *neigh) ...@@ -58,14 +58,14 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *neigh)
* frame. * frame.
*/ */
if (lci == 0) { if (lci == 0) {
x25_link_control(skb, neigh, frametype); x25_link_control(skb, nb, frametype);
return 0; return 0;
} }
/* /*
* Find an existing socket. * Find an existing socket.
*/ */
if ((sk = x25_find_socket(lci, neigh)) != NULL) { if ((sk = x25_find_socket(lci, nb)) != NULL) {
int queued = 1; int queued = 1;
skb->h.raw = skb->data; skb->h.raw = skb->data;
...@@ -83,91 +83,87 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *neigh) ...@@ -83,91 +83,87 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *neigh)
* Is is a Call Request ? if so process it. * Is is a Call Request ? if so process it.
*/ */
if (frametype == X25_CALL_REQUEST) if (frametype == X25_CALL_REQUEST)
return x25_rx_call_request(skb, neigh, lci); return x25_rx_call_request(skb, nb, lci);
/* /*
* Its not a Call Request, nor is it a control frame. * Its not a Call Request, nor is it a control frame.
* Let caller throw it away. * Let caller throw it away.
*/ */
/* /*
x25_transmit_clear_request(neigh, lci, 0x0D); x25_transmit_clear_request(nb, lci, 0x0D);
*/ */
printk(KERN_DEBUG "x25_receive_data(): unknown frame type %2x\n",frametype); printk(KERN_DEBUG "x25_receive_data(): unknown frame type %2x\n",frametype);
return 0; return 0;
} }
int x25_lapb_receive_frame(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype) int x25_lapb_receive_frame(struct sk_buff *skb, struct net_device *dev,
struct packet_type *ptype)
{ {
struct x25_neigh *neigh; struct x25_neigh *nb;
int queued;
skb->sk = NULL; skb->sk = NULL;
/* /*
* Packet received from unrecognised device, throw it away. * Packet received from unrecognised device, throw it away.
*/ */
if ((neigh = x25_get_neigh(dev)) == NULL) { nb = x25_get_neigh(dev);
if (!nb) {
printk(KERN_DEBUG "X.25: unknown neighbour - %s\n", dev->name); printk(KERN_DEBUG "X.25: unknown neighbour - %s\n", dev->name);
kfree_skb(skb); goto drop;
return 0;
} }
switch (skb->data[0]) { switch (skb->data[0]) {
case 0x00: case 0x00:
skb_pull(skb, 1); skb_pull(skb, 1);
queued = x25_receive_data(skb, neigh); if (x25_receive_data(skb, nb)) {
if( ! queued ) x25_neigh_put(nb);
/* We need to free the skb ourselves because goto out;
* net_bh() won't care about our return code. }
*/ break;
kfree_skb(skb);
return 0;
case 0x01: case 0x01:
x25_link_established(neigh); x25_link_established(nb);
kfree_skb(skb); break;
return 0;
case 0x02: case 0x02:
x25_link_terminated(neigh); x25_link_terminated(nb);
kfree_skb(skb); break;
return 0;
case 0x03:
kfree_skb(skb);
return 0;
default:
kfree_skb(skb);
return 0;
} }
x25_neigh_put(nb);
drop:
kfree_skb(skb);
out:
return 0;
} }
int x25_llc_receive_frame(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype) int x25_llc_receive_frame(struct sk_buff *skb, struct net_device *dev,
struct packet_type *ptype)
{ {
struct x25_neigh *neigh; struct x25_neigh *nb;
int rc = 0;
skb->sk = NULL; skb->sk = NULL;
/* /*
* Packet received from unrecognised device, throw it away. * Packet received from unrecognised device, throw it away.
*/ */
if ((neigh = x25_get_neigh(dev)) == NULL) { nb = x25_get_neigh(dev);
if (!nb) {
printk(KERN_DEBUG "X.25: unknown_neighbour - %s\n", dev->name); printk(KERN_DEBUG "X.25: unknown_neighbour - %s\n", dev->name);
kfree_skb(skb); kfree_skb(skb);
return 0; } else {
rc = x25_receive_data(skb, nb);
x25_neigh_put(nb);
} }
return x25_receive_data(skb, neigh); return rc;
} }
void x25_establish_link(struct x25_neigh *neigh) void x25_establish_link(struct x25_neigh *nb)
{ {
struct sk_buff *skb; struct sk_buff *skb;
unsigned char *ptr; unsigned char *ptr;
switch (neigh->dev->type) { switch (nb->dev->type) {
case ARPHRD_X25: case ARPHRD_X25:
if ((skb = alloc_skb(1, GFP_ATOMIC)) == NULL) { if ((skb = alloc_skb(1, GFP_ATOMIC)) == NULL) {
printk(KERN_ERR "x25_dev: out of memory\n"); printk(KERN_ERR "x25_dev: out of memory\n");
...@@ -186,47 +182,44 @@ void x25_establish_link(struct x25_neigh *neigh) ...@@ -186,47 +182,44 @@ void x25_establish_link(struct x25_neigh *neigh)
} }
skb->protocol = htons(ETH_P_X25); skb->protocol = htons(ETH_P_X25);
skb->dev = neigh->dev; skb->dev = nb->dev;
dev_queue_xmit(skb); dev_queue_xmit(skb);
} }
void x25_terminate_link(struct x25_neigh *neigh) void x25_terminate_link(struct x25_neigh *nb)
{ {
struct sk_buff *skb; struct sk_buff *skb;
unsigned char *ptr; unsigned char *ptr;
switch (neigh->dev->type) {
case ARPHRD_X25:
if ((skb = alloc_skb(1, GFP_ATOMIC)) == NULL) {
printk(KERN_ERR "x25_dev: out of memory\n");
return;
}
ptr = skb_put(skb, 1);
*ptr = 0x02;
break;
#if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE) #if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE)
case ARPHRD_ETHER: if (nb->dev->type == ARPHRD_ETHER)
return; return;
#endif #endif
default: if (nb->dev->type != ARPHRD_X25)
return; return;
skb = alloc_skb(1, GFP_ATOMIC);
if (!skb) {
printk(KERN_ERR "x25_dev: out of memory\n");
return;
} }
skb->protocol = htons(ETH_P_X25); ptr = skb_put(skb, 1);
skb->dev = neigh->dev; *ptr = 0x02;
skb->protocol = htons(ETH_P_X25);
skb->dev = nb->dev;
dev_queue_xmit(skb); dev_queue_xmit(skb);
} }
void x25_send_frame(struct sk_buff *skb, struct x25_neigh *neigh) void x25_send_frame(struct sk_buff *skb, struct x25_neigh *nb)
{ {
unsigned char *dptr; unsigned char *dptr;
skb->nh.raw = skb->data; skb->nh.raw = skb->data;
switch (neigh->dev->type) { switch (nb->dev->type) {
case ARPHRD_X25: case ARPHRD_X25:
dptr = skb_push(skb, 1); dptr = skb_push(skb, 1);
*dptr = 0x00; *dptr = 0x00;
...@@ -243,7 +236,7 @@ void x25_send_frame(struct sk_buff *skb, struct x25_neigh *neigh) ...@@ -243,7 +236,7 @@ void x25_send_frame(struct sk_buff *skb, struct x25_neigh *neigh)
} }
skb->protocol = htons(ETH_P_X25); skb->protocol = htons(ETH_P_X25);
skb->dev = neigh->dev; skb->dev = nb->dev;
dev_queue_xmit(skb); dev_queue_xmit(skb);
} }
...@@ -229,10 +229,10 @@ int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk, ...@@ -229,10 +229,10 @@ int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk,
* currently attached x25 link. * currently attached x25 link.
*/ */
void x25_limit_facilities(struct x25_facilities *facilities, void x25_limit_facilities(struct x25_facilities *facilities,
struct x25_neigh *neighbour) struct x25_neigh *nb)
{ {
if (!neighbour->extended) { if (!nb->extended) {
if (facilities->winsize_in > 7) { if (facilities->winsize_in > 7) {
printk(KERN_DEBUG "X.25: incoming winsize limited to 7\n"); printk(KERN_DEBUG "X.25: incoming winsize limited to 7\n");
facilities->winsize_in = 7; facilities->winsize_in = 7;
......
This diff is collapsed.
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