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 {
};
struct x25_neigh {
struct x25_neigh *next;
struct list_head node;
struct net_device *dev;
unsigned int state;
unsigned int extended;
......@@ -126,6 +126,7 @@ struct x25_neigh {
unsigned long t20;
struct timer_list t20timer;
unsigned long global_facil_mask;
atomic_t refcnt;
};
struct x25_opt {
......@@ -199,6 +200,18 @@ extern int x25_subscr_ioctl(unsigned int, void *);
extern struct x25_neigh *x25_get_neigh(struct net_device *);
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 */
extern int x25_output(struct sock *, struct sk_buff *);
extern void x25_kick(struct sock *);
......
......@@ -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)
{
struct net_device *dev = ptr;
struct x25_neigh *neigh;
struct x25_neigh *nb;
if (dev->type == ARPHRD_X25
#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
x25_link_device_up(dev);
break;
case NETDEV_GOING_DOWN:
if ((neigh = x25_get_neigh(dev)))
x25_terminate_link(neigh);
nb = x25_get_neigh(dev);
if (nb) {
x25_terminate_link(nb);
x25_neigh_put(nb);
}
break;
case NETDEV_DOWN:
x25_kill_by_device(dev);
......@@ -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.
*/
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;
unsigned long flags;
......@@ -264,7 +267,7 @@ struct sock *x25_find_socket(unsigned int lci, struct x25_neigh *neigh)
cli();
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;
restore_flags(flags);
......@@ -274,11 +277,11 @@ struct sock *x25_find_socket(unsigned int lci, struct x25_neigh *neigh)
/*
* 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;
while (x25_find_socket(lci, neigh))
while (x25_find_socket(lci, nb))
if (++lci == 4096) {
lci = 0;
break;
......@@ -631,11 +634,11 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len
x25->lci = x25_new_lci(x25->neighbour);
if (!x25->lci)
goto out_put_route;
goto out_put_neigh;
rc = -EINVAL;
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))
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
/* Now the loop */
rc = -EINPROGRESS;
if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
goto out_put_route;
goto out_put_neigh;
cli(); /* To avoid races on the sleep */
......@@ -681,6 +684,9 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len
rc = 0;
out_unlock:
sti();
out_put_neigh:
if (rc)
x25_neigh_put(x25->neighbour);
out_put_route:
x25_route_put(rt);
out:
......@@ -758,7 +764,7 @@ static int x25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_l
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 *make;
......@@ -800,7 +806,7 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned i
* on certain facilties
*/
x25_limit_facilities(&facilities,neigh);
x25_limit_facilities(&facilities, nb);
/*
* 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
makex25->lci = lci;
makex25->dest_addr = dest_addr;
makex25->source_addr = source_addr;
makex25->neighbour = neigh;
makex25->neighbour = nb;
makex25->facilities = facilities;
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
return rc;
out_clear_request:
rc = 0;
x25_transmit_clear_request(neigh, lci, 0x01);
x25_transmit_clear_request(nb, lci, 0x01);
goto out;
}
......@@ -1358,12 +1364,12 @@ struct notifier_block x25_dev_notifier = {
.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;
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);
}
......
......@@ -44,7 +44,7 @@
#include <linux/if_arp.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;
unsigned short frametype;
......@@ -58,14 +58,14 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *neigh)
* frame.
*/
if (lci == 0) {
x25_link_control(skb, neigh, frametype);
x25_link_control(skb, nb, frametype);
return 0;
}
/*
* Find an existing socket.
*/
if ((sk = x25_find_socket(lci, neigh)) != NULL) {
if ((sk = x25_find_socket(lci, nb)) != NULL) {
int queued = 1;
skb->h.raw = skb->data;
......@@ -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.
*/
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.
* 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);
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;
int queued;
struct x25_neigh *nb;
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);
kfree_skb(skb);
return 0;
goto drop;
}
switch (skb->data[0]) {
case 0x00:
skb_pull(skb, 1);
queued = x25_receive_data(skb, neigh);
if( ! queued )
/* We need to free the skb ourselves because
* net_bh() won't care about our return code.
*/
kfree_skb(skb);
return 0;
if (x25_receive_data(skb, nb)) {
x25_neigh_put(nb);
goto out;
}
break;
case 0x01:
x25_link_established(neigh);
kfree_skb(skb);
return 0;
x25_link_established(nb);
break;
case 0x02:
x25_link_terminated(neigh);
kfree_skb(skb);
return 0;
case 0x03:
kfree_skb(skb);
return 0;
default:
kfree_skb(skb);
return 0;
x25_link_terminated(nb);
break;
}
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;
/*
* 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);
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;
unsigned char *ptr;
switch (neigh->dev->type) {
switch (nb->dev->type) {
case ARPHRD_X25:
if ((skb = alloc_skb(1, GFP_ATOMIC)) == NULL) {
printk(KERN_ERR "x25_dev: out of memory\n");
......@@ -186,47 +182,44 @@ void x25_establish_link(struct x25_neigh *neigh)
}
skb->protocol = htons(ETH_P_X25);
skb->dev = neigh->dev;
skb->dev = nb->dev;
dev_queue_xmit(skb);
}
void x25_terminate_link(struct x25_neigh *neigh)
void x25_terminate_link(struct x25_neigh *nb)
{
struct sk_buff *skb;
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)
case ARPHRD_ETHER:
return;
if (nb->dev->type == ARPHRD_ETHER)
return;
#endif
default:
return;
if (nb->dev->type != ARPHRD_X25)
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);
skb->dev = neigh->dev;
ptr = skb_put(skb, 1);
*ptr = 0x02;
skb->protocol = htons(ETH_P_X25);
skb->dev = nb->dev;
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;
skb->nh.raw = skb->data;
switch (neigh->dev->type) {
switch (nb->dev->type) {
case ARPHRD_X25:
dptr = skb_push(skb, 1);
*dptr = 0x00;
......@@ -243,7 +236,7 @@ void x25_send_frame(struct sk_buff *skb, struct x25_neigh *neigh)
}
skb->protocol = htons(ETH_P_X25);
skb->dev = neigh->dev;
skb->dev = nb->dev;
dev_queue_xmit(skb);
}
......@@ -229,10 +229,10 @@ int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk,
* currently attached x25 link.
*/
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) {
printk(KERN_DEBUG "X.25: incoming winsize limited to 7\n");
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