Commit 5c0fbae1 authored by Arnaldo Carvalho de Melo's avatar Arnaldo Carvalho de Melo

Merge hera.kernel.org:/home/acme/BK/x25-2.5.old

into hera.kernel.org:/home/acme/BK/x25-2.5
parents 536ce362 004ffedc
...@@ -44,42 +44,63 @@ ...@@ -44,42 +44,63 @@
#include <linux/lapb.h> #include <linux/lapb.h>
#include <linux/init.h> #include <linux/init.h>
static char bcast_addr[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; static char bcast_addr[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
/* If this number is made larger, check that the temporary string buffer /* If this number is made larger, check that the temporary string buffer
* in lapbeth_new_device is large enough to store the probe device name.*/ * in lapbeth_new_device is large enough to store the probe device name.*/
#define MAXLAPBDEV 100 #define MAXLAPBDEV 100
static struct lapbethdev { struct lapbethdev {
struct lapbethdev *next; struct list_head node;
char ethname[14]; /* ether device name */ char ethname[14]; /* ether device name */
struct net_device *ethdev; /* link to ethernet device */ struct net_device *ethdev; /* link to ethernet device */
struct net_device axdev; /* lapbeth device (lapb#) */ struct net_device axdev; /* lapbeth device (lapb#) */
struct net_device_stats stats; /* some statistics */ struct net_device_stats stats; /* some statistics */
} *lapbeth_devices /* = NULL initially */; atomic_t refcnt;
};
static struct list_head lapbeth_devices = LIST_HEAD_INIT(lapbeth_devices);
static rwlock_t lapbeth_devices_lock = RW_LOCK_UNLOCKED;
static __inline__ void lapbeth_hold(struct lapbethdev *lapbeth)
{
atomic_inc(&lapbeth->refcnt);
}
static __inline__ void lapbeth_put(struct lapbethdev *lapbeth)
{
if (atomic_dec_and_test(&lapbeth->refcnt))
kfree(lapbeth);
}
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
/* /*
* Get the LAPB device for the ethernet device * Get the LAPB device for the ethernet device
*/ */
static inline struct net_device *lapbeth_get_x25_dev(struct net_device *dev) static __inline__ struct lapbethdev *lapbeth_get_x25_dev(struct net_device *dev)
{ {
struct lapbethdev *lapbeth; struct list_head *entry;
struct lapbethdev *lapbeth, *use = NULL;
read_lock(&lapbeth_devices_lock);
for (lapbeth = lapbeth_devices; lapbeth != NULL; lapbeth = lapbeth->next) list_for_each(entry, &lapbeth_devices) {
if (lapbeth->ethdev == dev) lapbeth = list_entry(entry, struct lapbethdev, node);
return &lapbeth->axdev; if (lapbeth->ethdev == dev) {
use = lapbeth;
break;
}
}
if (use)
lapbeth_hold(use);
return NULL; read_unlock(&lapbeth_devices_lock);
return use;
} }
static inline int dev_is_ethdev(struct net_device *dev) static __inline__ int dev_is_ethdev(struct net_device *dev)
{ {
return ( return dev->type == ARPHRD_ETHER && strncmp(dev->name, "dummy", 5);
dev->type == ARPHRD_ETHER
&& strncmp(dev->name, "dummy", 5)
);
} }
/* /*
...@@ -88,35 +109,26 @@ static inline int dev_is_ethdev(struct net_device *dev) ...@@ -88,35 +109,26 @@ static inline int dev_is_ethdev(struct net_device *dev)
*/ */
static int lapbeth_check_devices(struct net_device *dev) static int lapbeth_check_devices(struct net_device *dev)
{ {
struct lapbethdev *lapbeth, *lapbeth_prev, *lapbeth_next; struct lapbethdev *lapbeth;
struct list_head *entry, *tmp;
int result = 0; int result = 0;
unsigned long flags;
save_flags(flags); write_lock(&lapbeth_devices_lock);
cli();
lapbeth_prev = NULL; list_for_each_safe(entry, tmp, &lapbeth_devices) {
lapbeth = list_entry(entry, struct lapbethdev, node);
for (lapbeth = lapbeth_devices; lapbeth != NULL; lapbeth = lapbeth_next) {
lapbeth_next = lapbeth->next;
if (!dev_get(lapbeth->ethname)) { if (!dev_get(lapbeth->ethname)) {
if (lapbeth_prev)
lapbeth_prev->next = lapbeth->next;
else
lapbeth_devices = lapbeth->next;
if (&lapbeth->axdev == dev) if (&lapbeth->axdev == dev)
result = 1; result = 1;
unregister_netdev(&lapbeth->axdev); unregister_netdev(&lapbeth->axdev);
dev_put(lapbeth->ethdev); dev_put(lapbeth->ethdev);
kfree(lapbeth); list_del(&lapbeth->node);
lapbeth_put(lapbeth);
} }
else
lapbeth_prev = lapbeth;
} }
write_unlock(&lapbeth_devices_lock);
restore_flags(flags);
return result; return result;
} }
...@@ -133,14 +145,12 @@ static int lapbeth_rcv(struct sk_buff *skb, struct net_device *dev, struct packe ...@@ -133,14 +145,12 @@ static int lapbeth_rcv(struct sk_buff *skb, struct net_device *dev, struct packe
skb->sk = NULL; /* Initially we don't know who it's for */ skb->sk = NULL; /* Initially we don't know who it's for */
dev = lapbeth_get_x25_dev(dev); lapbeth = lapbeth_get_x25_dev(dev);
if (dev == NULL || !netif_running(dev)) { if (!lapbeth)
kfree_skb(skb); goto drop;
return 0; if (!netif_running(&lapbeth->axdev))
} goto put_drop;
lapbeth = (struct lapbethdev *) dev->priv;
lapbeth->stats.rx_packets++; lapbeth->stats.rx_packets++;
...@@ -150,16 +160,22 @@ static int lapbeth_rcv(struct sk_buff *skb, struct net_device *dev, struct packe ...@@ -150,16 +160,22 @@ static int lapbeth_rcv(struct sk_buff *skb, struct net_device *dev, struct packe
skb_trim(skb, len); /* Set the length of the data */ skb_trim(skb, len); /* Set the length of the data */
if ((err = lapb_data_received(lapbeth, skb)) != LAPB_OK) { if ((err = lapb_data_received(lapbeth, skb)) != LAPB_OK) {
kfree_skb(skb);
printk(KERN_DEBUG "lapbether: lapb_data_received err - %d\n", err); printk(KERN_DEBUG "lapbether: lapb_data_received err - %d\n", err);
goto put_drop;
} }
lapbeth_put(lapbeth);
out:
return 0; return 0;
put_drop:
lapbeth_put(lapbeth);
drop:
kfree_skb(skb);
goto out;
} }
static int lapbeth_data_indication(void *token, struct sk_buff *skb) static int lapbeth_data_indication(void *token, struct sk_buff *skb)
{ {
struct lapbethdev *lapbeth = (struct lapbethdev *) token; struct lapbethdev *lapbeth = (struct lapbethdev *)token;
unsigned char *ptr; unsigned char *ptr;
ptr = skb_push(skb, 1); ptr = skb_push(skb, 1);
...@@ -178,8 +194,8 @@ static int lapbeth_data_indication(void *token, struct sk_buff *skb) ...@@ -178,8 +194,8 @@ static int lapbeth_data_indication(void *token, struct sk_buff *skb)
*/ */
static int lapbeth_xmit(struct sk_buff *skb, struct net_device *dev) static int lapbeth_xmit(struct sk_buff *skb, struct net_device *dev)
{ {
struct lapbethdev *lapbeth = (struct lapbethdev *) dev->priv; struct lapbethdev *lapbeth = (struct lapbethdev *)dev->priv;
int err; int err = -ENODEV;
/* /*
* Just to be *really* sure not to send anything if the interface * Just to be *really* sure not to send anything if the interface
...@@ -187,50 +203,53 @@ static int lapbeth_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -187,50 +203,53 @@ static int lapbeth_xmit(struct sk_buff *skb, struct net_device *dev)
*/ */
if (!netif_running(dev)) { if (!netif_running(dev)) {
lapbeth_check_devices(dev); lapbeth_check_devices(dev);
kfree_skb(skb); goto drop;
return -ENODEV;
} }
switch (skb->data[0]) { switch (skb->data[0]) {
case 0x00: case 0x00:
break; err = 0;
case 0x01: break;
if ((err = lapb_connect_request(lapbeth)) != LAPB_OK) case 0x01:
printk(KERN_ERR "lapbeth: lapb_connect_request error - %d\n", err); if ((err = lapb_connect_request(lapbeth)) != LAPB_OK)
kfree_skb(skb); printk(KERN_ERR "lapbeth: lapb_connect_request "
return 0; "error: %d\n", err);
case 0x02: goto drop_ok;
if ((err = lapb_disconnect_request(lapbeth)) != LAPB_OK) case 0x02:
printk(KERN_ERR "lapbeth: lapb_disconnect_request err - %d\n", err); if ((err = lapb_disconnect_request(lapbeth)) != LAPB_OK)
kfree_skb(skb); printk(KERN_ERR "lapbeth: lapb_disconnect_request "
return 0; "err: %d\n", err);
default: /* Fall thru */
kfree_skb(skb); default:
return 0; goto drop_ok;
} }
skb_pull(skb, 1); skb_pull(skb, 1);
if ((err = lapb_data_request(lapbeth, skb)) != LAPB_OK) { if ((err = lapb_data_request(lapbeth, skb)) != LAPB_OK) {
printk(KERN_ERR "lapbeth: lapb_data_request error - %d\n", err); printk(KERN_ERR "lapbeth: lapb_data_request error - %d\n", err);
kfree_skb(skb); err = -ENOMEM;
return -ENOMEM; goto drop;
} }
err = 0;
return 0; out:
return err;
drop_ok:
err = 0;
drop:
kfree_skb(skb);
goto out;
} }
static void lapbeth_data_transmit(void *token, struct sk_buff *skb) static void lapbeth_data_transmit(void *token, struct sk_buff *skb)
{ {
struct lapbethdev *lapbeth = (struct lapbethdev *) token; struct lapbethdev *lapbeth = (struct lapbethdev *)token;
unsigned char *ptr; unsigned char *ptr;
struct net_device *dev; struct net_device *dev;
int size; int size = skb->len;
skb->protocol = htons(ETH_P_X25); skb->protocol = htons(ETH_P_X25);
size = skb->len;
ptr = skb_push(skb, 2); ptr = skb_push(skb, 2);
*ptr++ = size % 256; *ptr++ = size % 256;
...@@ -247,11 +266,11 @@ static void lapbeth_data_transmit(void *token, struct sk_buff *skb) ...@@ -247,11 +266,11 @@ static void lapbeth_data_transmit(void *token, struct sk_buff *skb)
static void lapbeth_connected(void *token, int reason) static void lapbeth_connected(void *token, int reason)
{ {
struct lapbethdev *lapbeth = (struct lapbethdev *) token; struct lapbethdev *lapbeth = (struct lapbethdev *)token;
struct sk_buff *skb;
unsigned char *ptr; unsigned char *ptr;
struct sk_buff *skb = dev_alloc_skb(1);
if ((skb = dev_alloc_skb(1)) == NULL) { if (!skb) {
printk(KERN_ERR "lapbeth: out of memory\n"); printk(KERN_ERR "lapbeth: out of memory\n");
return; return;
} }
...@@ -269,11 +288,11 @@ static void lapbeth_connected(void *token, int reason) ...@@ -269,11 +288,11 @@ static void lapbeth_connected(void *token, int reason)
static void lapbeth_disconnected(void *token, int reason) static void lapbeth_disconnected(void *token, int reason)
{ {
struct lapbethdev *lapbeth = (struct lapbethdev *) token; struct lapbethdev *lapbeth = (struct lapbethdev *)token;
struct sk_buff *skb;
unsigned char *ptr; unsigned char *ptr;
struct sk_buff *skb = dev_alloc_skb(1);
if ((skb = dev_alloc_skb(1)) == NULL) { if (!skb) {
printk(KERN_ERR "lapbeth: out of memory\n"); printk(KERN_ERR "lapbeth: out of memory\n");
return; return;
} }
...@@ -294,7 +313,7 @@ static void lapbeth_disconnected(void *token, int reason) ...@@ -294,7 +313,7 @@ static void lapbeth_disconnected(void *token, int reason)
*/ */
static struct net_device_stats *lapbeth_get_stats(struct net_device *dev) static struct net_device_stats *lapbeth_get_stats(struct net_device *dev)
{ {
struct lapbethdev *lapbeth = (struct lapbethdev *) dev->priv; struct lapbethdev *lapbeth = (struct lapbethdev *)dev->priv;
return &lapbeth->stats; return &lapbeth->stats;
} }
...@@ -303,9 +322,9 @@ static struct net_device_stats *lapbeth_get_stats(struct net_device *dev) ...@@ -303,9 +322,9 @@ static struct net_device_stats *lapbeth_get_stats(struct net_device *dev)
*/ */
static int lapbeth_set_mac_address(struct net_device *dev, void *addr) static int lapbeth_set_mac_address(struct net_device *dev, void *addr)
{ {
struct sockaddr *sa = (struct sockaddr *) addr; struct sockaddr *sa = (struct sockaddr *)addr;
memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
return 0; return 0;
} }
/* /*
...@@ -320,7 +339,7 @@ static int lapbeth_open(struct net_device *dev) ...@@ -320,7 +339,7 @@ static int lapbeth_open(struct net_device *dev)
if (lapbeth_check_devices(dev)) if (lapbeth_check_devices(dev))
return -ENODEV; /* oops, it's gone */ return -ENODEV; /* oops, it's gone */
lapbeth = (struct lapbethdev *) dev->priv; lapbeth = (struct lapbethdev *)dev->priv;
lapbeth_callbacks.connect_confirmation = lapbeth_connected; lapbeth_callbacks.connect_confirmation = lapbeth_connected;
lapbeth_callbacks.connect_indication = lapbeth_connected; lapbeth_callbacks.connect_indication = lapbeth_connected;
...@@ -340,7 +359,7 @@ static int lapbeth_open(struct net_device *dev) ...@@ -340,7 +359,7 @@ static int lapbeth_open(struct net_device *dev)
static int lapbeth_close(struct net_device *dev) static int lapbeth_close(struct net_device *dev)
{ {
struct lapbethdev *lapbeth = (struct lapbethdev *) dev->priv; struct lapbethdev *lapbeth = (struct lapbethdev *)dev->priv;
int err; int err;
netif_stop_queue(dev); netif_stop_queue(dev);
...@@ -358,20 +377,21 @@ static int lapbeth_close(struct net_device *dev) ...@@ -358,20 +377,21 @@ static int lapbeth_close(struct net_device *dev)
*/ */
static int lapbeth_new_device(struct net_device *dev) static int lapbeth_new_device(struct net_device *dev)
{ {
int k;
unsigned char buf[14]; unsigned char buf[14];
struct lapbethdev *lapbeth, *lapbeth2; struct lapbethdev *lapbeth;
int k, rc = -ENOMEM;
if ((lapbeth = kmalloc(sizeof(struct lapbethdev), GFP_KERNEL)) == NULL) if ((lapbeth = kmalloc(sizeof(struct lapbethdev), GFP_ATOMIC)) == NULL)
return -ENOMEM; goto out;
memset(lapbeth, 0, sizeof(struct lapbethdev)); memset(lapbeth, 0, sizeof(struct lapbethdev));
dev_hold(dev); dev_hold(dev);
lapbeth->ethdev = dev; lapbeth->ethdev = dev;
lapbeth->ethname[sizeof(lapbeth->ethname)-1] = '\0'; strncpy(lapbeth->ethname, dev->name, sizeof(lapbeth->ethname) - 1);
strncpy(lapbeth->ethname, dev->name, sizeof(lapbeth->ethname)-1); lapbeth->ethname[sizeof(lapbeth->ethname) - 1] = '\0';
atomic_set(&lapbeth->refcnt, 1);
dev = &lapbeth->axdev; dev = &lapbeth->axdev;
SET_MODULE_OWNER(dev); SET_MODULE_OWNER(dev);
...@@ -381,24 +401,21 @@ static int lapbeth_new_device(struct net_device *dev) ...@@ -381,24 +401,21 @@ static int lapbeth_new_device(struct net_device *dev)
sprintf(buf, "lapb%d", k); sprintf(buf, "lapb%d", k);
if ((odev = __dev_get_by_name(buf)) == NULL || lapbeth_check_devices(odev)) if ((odev = __dev_get_by_name(buf)) == NULL ||
lapbeth_check_devices(odev))
break; break;
} }
if (k == MAXLAPBDEV) { rc = -ENODEV;
dev_put(dev); if (k == MAXLAPBDEV)
kfree(lapbeth); goto fail;
return -ENODEV;
}
dev->priv = (void *)lapbeth; /* pointer back */ dev->priv = (void *)lapbeth; /* pointer back */
strcpy(dev->name, buf); strcpy(dev->name, buf);
if (register_netdev(dev) != 0) { rc = -EIO;
dev_put(dev); if (register_netdev(dev))
kfree(lapbeth); goto fail;
return -EIO;
}
dev->hard_start_xmit = lapbeth_xmit; dev->hard_start_xmit = lapbeth_xmit;
dev->open = lapbeth_open; dev->open = lapbeth_open;
...@@ -410,26 +427,27 @@ static int lapbeth_new_device(struct net_device *dev) ...@@ -410,26 +427,27 @@ static int lapbeth_new_device(struct net_device *dev)
dev->mtu = 1000; dev->mtu = 1000;
dev->addr_len = 0; dev->addr_len = 0;
cli(); write_lock(&lapbeth_devices_lock);
list_add(&lapbeth->node, &lapbeth_devices);
if (lapbeth_devices == NULL) { lapbeth_hold(lapbeth);
lapbeth_devices = lapbeth; write_unlock(&lapbeth_devices_lock);
} else { rc = 0;
for (lapbeth2 = lapbeth_devices; lapbeth2->next != NULL; lapbeth2 = lapbeth2->next); out:
lapbeth2->next = lapbeth; return rc;
} fail:
dev_put(dev);
sti(); kfree(lapbeth);
goto out;
return 0;
} }
/* /*
* Handle device status changes. * Handle device status changes.
*/ */
static int lapbeth_device_event(struct notifier_block *this, unsigned long event, void *ptr) static int lapbeth_device_event(struct notifier_block *this,
unsigned long event, void *ptr)
{ {
struct net_device *dev = (struct net_device *) ptr; struct lapbethdev *lapbeth;
struct net_device *dev = (struct net_device *)ptr;
if (!dev_is_ethdev(dev)) if (!dev_is_ethdev(dev))
return NOTIFY_DONE; return NOTIFY_DONE;
...@@ -437,19 +455,26 @@ static int lapbeth_device_event(struct notifier_block *this, unsigned long event ...@@ -437,19 +455,26 @@ static int lapbeth_device_event(struct notifier_block *this, unsigned long event
lapbeth_check_devices(NULL); lapbeth_check_devices(NULL);
switch (event) { switch (event) {
case NETDEV_UP: /* new ethernet device -> new LAPB interface */ case NETDEV_UP:
if (lapbeth_get_x25_dev(dev) == NULL) /*
lapbeth_new_device(dev); * New ethernet device -> new LAPB interface
break; */
lapbeth = lapbeth_get_x25_dev(dev);
case NETDEV_GOING_DOWN:
case NETDEV_DOWN: /* ethernet device closed -> close LAPB interface */ if (lapbeth)
if ((dev = lapbeth_get_x25_dev(dev)) != NULL) lapbeth_put(lapbeth);
dev_close(dev); else
break; lapbeth_new_device(dev);
break;
default: case NETDEV_GOING_DOWN:
break; case NETDEV_DOWN: /* ethernet device closed -> close LAPB interface */
lapbeth = lapbeth_get_x25_dev(dev);
if (lapbeth) {
dev_close(lapbeth->ethdev);
lapbeth_put(lapbeth);
}
break;
} }
return NOTIFY_DONE; return NOTIFY_DONE;
...@@ -458,15 +483,15 @@ static int lapbeth_device_event(struct notifier_block *this, unsigned long event ...@@ -458,15 +483,15 @@ static int lapbeth_device_event(struct notifier_block *this, unsigned long event
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
static struct packet_type lapbeth_packet_type = { static struct packet_type lapbeth_packet_type = {
.type = __constant_htons(ETH_P_DEC), .type = __constant_htons(ETH_P_DEC),
.func = lapbeth_rcv, .func = lapbeth_rcv,
}; };
static struct notifier_block lapbeth_dev_notifier = { static struct notifier_block lapbeth_dev_notifier = {
.notifier_call = lapbeth_device_event, .notifier_call = lapbeth_device_event,
}; };
static char banner[] __initdata = KERN_INFO "LAPB Ethernet driver version 0.01\n"; static char banner[] __initdata = KERN_INFO "LAPB Ethernet driver version 0.02\n";
static int __init lapbeth_init_driver(void) static int __init lapbeth_init_driver(void)
{ {
...@@ -479,7 +504,7 @@ static int __init lapbeth_init_driver(void) ...@@ -479,7 +504,7 @@ static int __init lapbeth_init_driver(void)
printk(banner); printk(banner);
read_lock_bh(&dev_base_lock); read_lock_bh(&dev_base_lock);
for (dev = dev_base; dev != NULL; dev = dev->next) { for (dev = dev_base; dev; dev = dev->next) {
if (dev_is_ethdev(dev)) { if (dev_is_ethdev(dev)) {
read_unlock_bh(&dev_base_lock); read_unlock_bh(&dev_base_lock);
lapbeth_new_device(dev); lapbeth_new_device(dev);
...@@ -495,18 +520,24 @@ module_init(lapbeth_init_driver); ...@@ -495,18 +520,24 @@ module_init(lapbeth_init_driver);
static void __exit lapbeth_cleanup_driver(void) static void __exit lapbeth_cleanup_driver(void)
{ {
struct lapbethdev *lapbeth; struct lapbethdev *lapbeth;
struct list_head *entry, *tmp;
dev_remove_pack(&lapbeth_packet_type); dev_remove_pack(&lapbeth_packet_type);
unregister_netdevice_notifier(&lapbeth_dev_notifier); unregister_netdevice_notifier(&lapbeth_dev_notifier);
for (lapbeth = lapbeth_devices; lapbeth != NULL; lapbeth = lapbeth->next) write_lock(&lapbeth_devices_lock);
list_for_each_safe(entry, tmp, &lapbeth_devices) {
lapbeth = list_entry(entry, struct lapbethdev, node);
unregister_netdev(&lapbeth->axdev); unregister_netdev(&lapbeth->axdev);
list_del(&lapbeth->node);
lapbeth_put(lapbeth);
}
write_unlock(&lapbeth_devices_lock);
} }
module_exit(lapbeth_cleanup_driver); module_exit(lapbeth_cleanup_driver);
MODULE_AUTHOR("Jonathan Naylor <g4klx@g4klx.demon.co.uk>"); MODULE_AUTHOR("Jonathan Naylor <g4klx@g4klx.demon.co.uk>");
MODULE_DESCRIPTION("The unofficial LAPB over Ethernet driver"); MODULE_DESCRIPTION("The unofficial LAPB over Ethernet driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -39,16 +39,16 @@ ...@@ -39,16 +39,16 @@
* An X.121 address, it is held as ASCII text, null terminated, up to 15 * An X.121 address, it is held as ASCII text, null terminated, up to 15
* digits and a null terminator. * digits and a null terminator.
*/ */
typedef struct { struct x25_address {
char x25_addr[16]; char x25_addr[16];
} x25_address; };
/* /*
* Linux X.25 Address structure, used for bind, and connect mostly. * Linux X.25 Address structure, used for bind, and connect mostly.
*/ */
struct sockaddr_x25 { struct sockaddr_x25 {
sa_family_t sx25_family; /* Must be AF_X25 */ sa_family_t sx25_family; /* Must be AF_X25 */
x25_address sx25_addr; /* X.121 Address */ struct x25_address sx25_addr; /* X.121 Address */
}; };
/* /*
...@@ -78,9 +78,9 @@ struct x25_subscrip_struct { ...@@ -78,9 +78,9 @@ struct x25_subscrip_struct {
* Routing table control structure. * Routing table control structure.
*/ */
struct x25_route_struct { struct x25_route_struct {
x25_address address; struct x25_address address;
unsigned int sigdigits; unsigned int sigdigits;
char device[200]; char device[200];
}; };
/* /*
......
...@@ -78,8 +78,8 @@ struct lapb_frame { ...@@ -78,8 +78,8 @@ struct lapb_frame {
/* /*
* The per LAPB connection control structure. * The per LAPB connection control structure.
*/ */
typedef struct lapb_cb { struct lapb_cb {
struct lapb_cb *next; struct list_head node;
void *token; void *token;
/* Link status fields */ /* Link status fields */
...@@ -100,43 +100,45 @@ typedef struct lapb_cb { ...@@ -100,43 +100,45 @@ typedef struct lapb_cb {
/* FRMR control information */ /* FRMR control information */
struct lapb_frame frmr_data; struct lapb_frame frmr_data;
unsigned char frmr_type; unsigned char frmr_type;
} lapb_cb;
atomic_t refcnt;
};
/* lapb_iface.c */ /* lapb_iface.c */
extern void lapb_connect_confirmation(lapb_cb *, int); extern void lapb_connect_confirmation(struct lapb_cb *lapb, int);
extern void lapb_connect_indication(lapb_cb *, int); extern void lapb_connect_indication(struct lapb_cb *lapb, int);
extern void lapb_disconnect_confirmation(lapb_cb *, int); extern void lapb_disconnect_confirmation(struct lapb_cb *lapb, int);
extern void lapb_disconnect_indication(lapb_cb *, int); extern void lapb_disconnect_indication(struct lapb_cb *lapb, int);
extern int lapb_data_indication(lapb_cb *, struct sk_buff *); extern int lapb_data_indication(struct lapb_cb *lapb, struct sk_buff *);
extern int lapb_data_transmit(lapb_cb *, struct sk_buff *); extern int lapb_data_transmit(struct lapb_cb *lapb, struct sk_buff *);
/* lapb_in.c */ /* lapb_in.c */
extern void lapb_data_input(lapb_cb *, struct sk_buff *); extern void lapb_data_input(struct lapb_cb *lapb, struct sk_buff *);
/* lapb_out.c */ /* lapb_out.c */
extern void lapb_kick(lapb_cb *); extern void lapb_kick(struct lapb_cb *lapb);
extern void lapb_transmit_buffer(lapb_cb *, struct sk_buff *, int); extern void lapb_transmit_buffer(struct lapb_cb *lapb, struct sk_buff *, int);
extern void lapb_establish_data_link(lapb_cb *); extern void lapb_establish_data_link(struct lapb_cb *lapb);
extern void lapb_enquiry_response(lapb_cb *); extern void lapb_enquiry_response(struct lapb_cb *lapb);
extern void lapb_timeout_response(lapb_cb *); extern void lapb_timeout_response(struct lapb_cb *lapb);
extern void lapb_check_iframes_acked(lapb_cb *, unsigned short); extern void lapb_check_iframes_acked(struct lapb_cb *lapb, unsigned short);
extern void lapb_check_need_response(lapb_cb *, int, int); extern void lapb_check_need_response(struct lapb_cb *lapb, int, int);
/* lapb_subr.c */ /* lapb_subr.c */
extern void lapb_clear_queues(lapb_cb *); extern void lapb_clear_queues(struct lapb_cb *lapb);
extern void lapb_frames_acked(lapb_cb *, unsigned short); extern void lapb_frames_acked(struct lapb_cb *lapb, unsigned short);
extern void lapb_requeue_frames(lapb_cb *); extern void lapb_requeue_frames(struct lapb_cb *lapb);
extern int lapb_validate_nr(lapb_cb *, unsigned short); extern int lapb_validate_nr(struct lapb_cb *lapb, unsigned short);
extern void lapb_decode(lapb_cb *, struct sk_buff *, struct lapb_frame *); extern void lapb_decode(struct lapb_cb *lapb, struct sk_buff *, struct lapb_frame *);
extern void lapb_send_control(lapb_cb *, int, int, int); extern void lapb_send_control(struct lapb_cb *lapb, int, int, int);
extern void lapb_transmit_frmr(lapb_cb *); extern void lapb_transmit_frmr(struct lapb_cb *lapb);
/* lapb_timer.c */ /* lapb_timer.c */
extern void lapb_start_t1timer(lapb_cb *); extern void lapb_start_t1timer(struct lapb_cb *lapb);
extern void lapb_start_t2timer(lapb_cb *); extern void lapb_start_t2timer(struct lapb_cb *lapb);
extern void lapb_stop_t1timer(lapb_cb *); extern void lapb_stop_t1timer(struct lapb_cb *lapb);
extern void lapb_stop_t2timer(lapb_cb *); extern void lapb_stop_t2timer(struct lapb_cb *lapb);
extern int lapb_t1timer_running(lapb_cb *); extern int lapb_t1timer_running(struct lapb_cb *lapb);
/* /*
* Debug levels. * Debug levels.
......
...@@ -101,26 +101,36 @@ enum { ...@@ -101,26 +101,36 @@ 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;
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 {
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;
struct sk_buff_head queue; struct sk_buff_head queue;
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;
}; };
typedef struct { struct x25_opt {
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;
unsigned char state, condition, qbitincl, intflag; unsigned char state, condition, qbitincl, intflag;
...@@ -137,9 +147,9 @@ typedef struct { ...@@ -137,9 +147,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;
...@@ -148,8 +158,10 @@ extern int sysctl_x25_reset_request_timeout; ...@@ -148,8 +158,10 @@ extern int sysctl_x25_reset_request_timeout;
extern int sysctl_x25_clear_request_timeout; extern int sysctl_x25_clear_request_timeout;
extern int sysctl_x25_ack_holdback_timeout; extern int sysctl_x25_ack_holdback_timeout;
extern int x25_addr_ntoa(unsigned char *, x25_address *, x25_address *); extern int x25_addr_ntoa(unsigned char *, struct x25_address *,
extern int x25_addr_aton(unsigned char *, x25_address *, x25_address *); struct x25_address *);
extern int x25_addr_aton(unsigned char *, struct x25_address *,
struct x25_address *);
extern unsigned int x25_new_lci(struct x25_neigh *); extern unsigned int x25_new_lci(struct x25_neigh *);
extern struct sock *x25_find_socket(unsigned int, struct x25_neigh *); extern struct sock *x25_find_socket(unsigned int, struct x25_neigh *);
extern void x25_destroy_socket(struct sock *); extern void x25_destroy_socket(struct sock *);
...@@ -188,19 +200,42 @@ extern int x25_subscr_ioctl(unsigned int, void *); ...@@ -188,19 +200,42 @@ 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 *);
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(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);
......
...@@ -39,87 +39,93 @@ ...@@ -39,87 +39,93 @@
#include <linux/init.h> #include <linux/init.h>
#include <net/lapb.h> #include <net/lapb.h>
static lapb_cb *volatile lapb_list /* = NULL initially */; static struct list_head lapb_list = LIST_HEAD_INIT(lapb_list);
static rwlock_t lapb_list_lock = RW_LOCK_UNLOCKED;
/* /*
* Free an allocated lapb control block. This is done to centralise * Free an allocated lapb control block. This is done to centralise
* the MOD count code. * the MOD count code.
*/ */
static void lapb_free_cb(lapb_cb *lapb) static void lapb_free_cb(struct lapb_cb *lapb)
{ {
kfree(lapb); kfree(lapb);
MOD_DEC_USE_COUNT; MOD_DEC_USE_COUNT;
} }
static __inline__ void lapb_hold(struct lapb_cb *lapb)
{
atomic_inc(&lapb->refcnt);
}
static __inline__ void lapb_put(struct lapb_cb *lapb)
{
if (atomic_dec_and_test(&lapb->refcnt))
lapb_free_cb(lapb);
}
/* /*
* Socket removal during an interrupt is now safe. * Socket removal during an interrupt is now safe.
*/ */
static void lapb_remove_cb(lapb_cb *lapb) static void __lapb_remove_cb(struct lapb_cb *lapb)
{ {
lapb_cb *s; if (lapb->node.next) {
unsigned long flags; list_del(&lapb->node);
lapb_put(lapb);
save_flags(flags); cli();
if ((s = lapb_list) == lapb) {
lapb_list = s->next;
restore_flags(flags);
return;
} }
while (s != NULL && s->next != NULL) {
if (s->next == lapb) {
s->next = lapb->next;
restore_flags(flags);
return;
}
s = s->next;
}
restore_flags(flags);
} }
/* /*
* Add a socket to the bound sockets list. * Add a socket to the bound sockets list.
*/ */
static void lapb_insert_cb(lapb_cb *lapb) static void __lapb_insert_cb(struct lapb_cb *lapb)
{ {
unsigned long flags; list_add(&lapb->node, &lapb_list);
lapb_hold(lapb);
save_flags(flags); cli();
lapb->next = lapb_list;
lapb_list = lapb;
restore_flags(flags);
} }
/* /*
* Convert the integer token used by the device driver into a pointer * Convert the integer token used by the device driver into a pointer
* to a LAPB control structure. * to a LAPB control structure.
*/ */
static lapb_cb *lapb_tokentostruct(void *token) static struct lapb_cb *__lapb_tokentostruct(void *token)
{ {
lapb_cb *lapb; struct list_head *entry;
struct lapb_cb *lapb, *use = NULL;
list_for_each(entry, &lapb_list) {
lapb = list_entry(entry, struct lapb_cb, node);
if (lapb->token == token) {
use = lapb;
break;
}
}
for (lapb = lapb_list; lapb != NULL; lapb = lapb->next) if (use)
if (lapb->token == token) lapb_hold(use);
return lapb;
return NULL; return use;
} }
static struct lapb_cb *lapb_tokentostruct(void *token)
{
struct lapb_cb *rc;
read_lock_bh(&lapb_list_lock);
rc = __lapb_tokentostruct(token);
read_unlock_bh(&lapb_list_lock);
return rc;
}
/* /*
* Create an empty LAPB control block. * Create an empty LAPB control block.
*/ */
static lapb_cb *lapb_create_cb(void) static struct lapb_cb *lapb_create_cb(void)
{ {
lapb_cb *lapb; struct lapb_cb *lapb = kmalloc(sizeof(*lapb), GFP_ATOMIC);
if ((lapb = kmalloc(sizeof(*lapb), GFP_ATOMIC)) == NULL) if (!lapb)
return NULL; goto out;
MOD_INC_USE_COUNT; MOD_INC_USE_COUNT;
...@@ -137,55 +143,73 @@ static lapb_cb *lapb_create_cb(void) ...@@ -137,55 +143,73 @@ static lapb_cb *lapb_create_cb(void)
lapb->mode = LAPB_DEFAULT_MODE; lapb->mode = LAPB_DEFAULT_MODE;
lapb->window = LAPB_DEFAULT_WINDOW; lapb->window = LAPB_DEFAULT_WINDOW;
lapb->state = LAPB_STATE_0; lapb->state = LAPB_STATE_0;
atomic_set(&lapb->refcnt, 1);
out:
return lapb; return lapb;
} }
int lapb_register(void *token, struct lapb_register_struct *callbacks) int lapb_register(void *token, struct lapb_register_struct *callbacks)
{ {
lapb_cb *lapb; struct lapb_cb *lapb;
int rc = LAPB_BADTOKEN;
write_lock_bh(&lapb_list_lock);
if (lapb_tokentostruct(token) != NULL) lapb = __lapb_tokentostruct(token);
return LAPB_BADTOKEN; if (lapb) {
lapb_put(lapb);
goto out;
}
if ((lapb = lapb_create_cb()) == NULL) lapb = lapb_create_cb();
return LAPB_NOMEM; rc = LAPB_NOMEM;
if (!lapb)
goto out;
lapb->token = token; lapb->token = token;
lapb->callbacks = *callbacks; lapb->callbacks = *callbacks;
lapb_insert_cb(lapb); __lapb_insert_cb(lapb);
lapb_start_t1timer(lapb); lapb_start_t1timer(lapb);
return LAPB_OK; rc = LAPB_OK;
out:
write_unlock_bh(&lapb_list_lock);
return rc;
} }
int lapb_unregister(void *token) int lapb_unregister(void *token)
{ {
lapb_cb *lapb; struct lapb_cb *lapb;
int rc = LAPB_BADTOKEN;
if ((lapb = lapb_tokentostruct(token)) == NULL) write_unlock_bh(&lapb_list_lock);
return LAPB_BADTOKEN; lapb = __lapb_tokentostruct(token);
if (!lapb)
goto out;
lapb_stop_t1timer(lapb); lapb_stop_t1timer(lapb);
lapb_stop_t2timer(lapb); lapb_stop_t2timer(lapb);
lapb_clear_queues(lapb); lapb_clear_queues(lapb);
lapb_remove_cb(lapb); __lapb_remove_cb(lapb);
lapb_free_cb(lapb); lapb_put(lapb);
rc = LAPB_OK;
return LAPB_OK; out:
write_unlock_bh(&lapb_list_lock);
return rc;
} }
int lapb_getparms(void *token, struct lapb_parms_struct *parms) int lapb_getparms(void *token, struct lapb_parms_struct *parms)
{ {
lapb_cb *lapb; int rc = LAPB_BADTOKEN;
struct lapb_cb *lapb = lapb_tokentostruct(token);
if ((lapb = lapb_tokentostruct(token)) == NULL) if (!lapb)
return LAPB_BADTOKEN; goto out;
parms->t1 = lapb->t1 / HZ; parms->t1 = lapb->t1 / HZ;
parms->t2 = lapb->t2 / HZ; parms->t2 = lapb->t2 / HZ;
...@@ -205,33 +229,29 @@ int lapb_getparms(void *token, struct lapb_parms_struct *parms) ...@@ -205,33 +229,29 @@ int lapb_getparms(void *token, struct lapb_parms_struct *parms)
else else
parms->t2timer = (lapb->t2timer.expires - jiffies) / HZ; parms->t2timer = (lapb->t2timer.expires - jiffies) / HZ;
return LAPB_OK; lapb_put(lapb);
rc = LAPB_OK;
out:
return rc;
} }
int lapb_setparms(void *token, struct lapb_parms_struct *parms) int lapb_setparms(void *token, struct lapb_parms_struct *parms)
{ {
lapb_cb *lapb; int rc = LAPB_BADTOKEN;
struct lapb_cb *lapb = lapb_tokentostruct(token);
if ((lapb = lapb_tokentostruct(token)) == NULL)
return LAPB_BADTOKEN;
if (parms->t1 < 1)
return LAPB_INVALUE;
if (parms->t2 < 1) if (!lapb)
return LAPB_INVALUE; goto out;
if (parms->n2 < 1) rc = LAPB_INVALUE;
return LAPB_INVALUE; if (parms->t1 < 1 || parms->t2 < 1 || parms->n2 < 1)
goto out_put;
if (lapb->state == LAPB_STATE_0) { if (lapb->state == LAPB_STATE_0) {
if (parms->mode & LAPB_EXTENDED) { if (((parms->mode & LAPB_EXTENDED) &&
if (parms->window < 1 || parms->window > 127) (parms->window < 1 || parms->window > 127)) ||
return LAPB_INVALUE; (parms->window < 1 || parms->window > 7))
} else { goto out_put;
if (parms->window < 1 || parms->window > 7)
return LAPB_INVALUE;
}
lapb->mode = parms->mode; lapb->mode = parms->mode;
lapb->window = parms->window; lapb->window = parms->window;
...@@ -241,45 +261,55 @@ int lapb_setparms(void *token, struct lapb_parms_struct *parms) ...@@ -241,45 +261,55 @@ int lapb_setparms(void *token, struct lapb_parms_struct *parms)
lapb->t2 = parms->t2 * HZ; lapb->t2 = parms->t2 * HZ;
lapb->n2 = parms->n2; lapb->n2 = parms->n2;
return LAPB_OK; rc = LAPB_OK;
out_put:
lapb_put(lapb);
out:
return rc;
} }
int lapb_connect_request(void *token) int lapb_connect_request(void *token)
{ {
lapb_cb *lapb; struct lapb_cb *lapb = lapb_tokentostruct(token);
int rc = LAPB_BADTOKEN;
if ((lapb = lapb_tokentostruct(token)) == NULL) if (!lapb)
return LAPB_BADTOKEN; goto out;
switch (lapb->state) { rc = LAPB_OK;
case LAPB_STATE_1: if (lapb->state == LAPB_STATE_1)
return LAPB_OK; goto out_put;
case LAPB_STATE_3:
case LAPB_STATE_4: rc = LAPB_CONNECTED;
return LAPB_CONNECTED; if (lapb->state == LAPB_STATE_3 || lapb->state == LAPB_STATE_4)
} goto out_put;
lapb_establish_data_link(lapb); lapb_establish_data_link(lapb);
#if LAPB_DEBUG > 0 #if LAPB_DEBUG > 0
printk(KERN_DEBUG "lapb: (%p) S0 -> S1\n", lapb->token); printk(KERN_DEBUG "lapb: (%p) S0 -> S1\n", lapb->token);
#endif #endif
lapb->state = LAPB_STATE_1; lapb->state = LAPB_STATE_1;
return LAPB_OK; rc = LAPB_OK;
out_put:
lapb_put(lapb);
out:
return rc;
} }
int lapb_disconnect_request(void *token) int lapb_disconnect_request(void *token)
{ {
lapb_cb *lapb; struct lapb_cb *lapb = lapb_tokentostruct(token);
int rc = LAPB_BADTOKEN;
if ((lapb = lapb_tokentostruct(token)) == NULL) if (!lapb)
return LAPB_BADTOKEN; goto out;
switch (lapb->state) { switch (lapb->state) {
case LAPB_STATE_0: case LAPB_STATE_0:
return LAPB_NOTCONNECTED; rc = LAPB_NOTCONNECTED;
goto out_put;
case LAPB_STATE_1: case LAPB_STATE_1:
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
...@@ -291,10 +321,12 @@ int lapb_disconnect_request(void *token) ...@@ -291,10 +321,12 @@ int lapb_disconnect_request(void *token)
lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND); lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND);
lapb->state = LAPB_STATE_0; lapb->state = LAPB_STATE_0;
lapb_start_t1timer(lapb); lapb_start_t1timer(lapb);
return LAPB_NOTCONNECTED; rc = LAPB_NOTCONNECTED;
goto out_put;
case LAPB_STATE_2: case LAPB_STATE_2:
return LAPB_OK; rc = LAPB_OK;
goto out_put;
} }
lapb_clear_queues(lapb); lapb_clear_queues(lapb);
...@@ -311,77 +343,87 @@ int lapb_disconnect_request(void *token) ...@@ -311,77 +343,87 @@ int lapb_disconnect_request(void *token)
printk(KERN_DEBUG "lapb: (%p) S3 -> S2\n", lapb->token); printk(KERN_DEBUG "lapb: (%p) S3 -> S2\n", lapb->token);
#endif #endif
return LAPB_OK; rc = LAPB_OK;
out_put:
lapb_put(lapb);
out:
return rc;
} }
int lapb_data_request(void *token, struct sk_buff *skb) int lapb_data_request(void *token, struct sk_buff *skb)
{ {
lapb_cb *lapb; struct lapb_cb *lapb = lapb_tokentostruct(token);
int rc = LAPB_BADTOKEN;
if ((lapb = lapb_tokentostruct(token)) == NULL) if (!lapb)
return LAPB_BADTOKEN; goto out;
rc = LAPB_NOTCONNECTED;
if (lapb->state != LAPB_STATE_3 && lapb->state != LAPB_STATE_4) if (lapb->state != LAPB_STATE_3 && lapb->state != LAPB_STATE_4)
return LAPB_NOTCONNECTED; goto out_put;
skb_queue_tail(&lapb->write_queue, skb); skb_queue_tail(&lapb->write_queue, skb);
lapb_kick(lapb); lapb_kick(lapb);
rc = LAPB_OK;
return LAPB_OK; out_put:
lapb_put(lapb);
out:
return rc;
} }
int lapb_data_received(void *token, struct sk_buff *skb) int lapb_data_received(void *token, struct sk_buff *skb)
{ {
lapb_cb *lapb; struct lapb_cb *lapb = lapb_tokentostruct(token);
int rc = LAPB_BADTOKEN;
if ((lapb = lapb_tokentostruct(token)) == NULL)
return LAPB_BADTOKEN;
lapb_data_input(lapb, skb); if (lapb) {
lapb_data_input(lapb, skb);
lapb_put(lapb);
rc = LAPB_OK;
}
return LAPB_OK; return rc;
} }
void lapb_connect_confirmation(lapb_cb *lapb, int reason) void lapb_connect_confirmation(struct lapb_cb *lapb, int reason)
{ {
if (lapb->callbacks.connect_confirmation != NULL) if (lapb->callbacks.connect_confirmation)
(lapb->callbacks.connect_confirmation)(lapb->token, reason); lapb->callbacks.connect_confirmation(lapb->token, reason);
} }
void lapb_connect_indication(lapb_cb *lapb, int reason) void lapb_connect_indication(struct lapb_cb *lapb, int reason)
{ {
if (lapb->callbacks.connect_indication != NULL) if (lapb->callbacks.connect_indication)
(lapb->callbacks.connect_indication)(lapb->token, reason); lapb->callbacks.connect_indication(lapb->token, reason);
} }
void lapb_disconnect_confirmation(lapb_cb *lapb, int reason) void lapb_disconnect_confirmation(struct lapb_cb *lapb, int reason)
{ {
if (lapb->callbacks.disconnect_confirmation != NULL) if (lapb->callbacks.disconnect_confirmation)
(lapb->callbacks.disconnect_confirmation)(lapb->token, reason); lapb->callbacks.disconnect_confirmation(lapb->token, reason);
} }
void lapb_disconnect_indication(lapb_cb *lapb, int reason) void lapb_disconnect_indication(struct lapb_cb *lapb, int reason)
{ {
if (lapb->callbacks.disconnect_indication != NULL) if (lapb->callbacks.disconnect_indication)
(lapb->callbacks.disconnect_indication)(lapb->token, reason); lapb->callbacks.disconnect_indication(lapb->token, reason);
} }
int lapb_data_indication(lapb_cb *lapb, struct sk_buff *skb) int lapb_data_indication(struct lapb_cb *lapb, struct sk_buff *skb)
{ {
if (lapb->callbacks.data_indication != NULL) { if (lapb->callbacks.data_indication)
return (lapb->callbacks.data_indication)(lapb->token, skb); return lapb->callbacks.data_indication(lapb->token, skb);
}
kfree_skb(skb); kfree_skb(skb);
return NET_RX_CN_HIGH; /* For now; must be != NET_RX_DROP */ return NET_RX_CN_HIGH; /* For now; must be != NET_RX_DROP */
} }
int lapb_data_transmit(lapb_cb *lapb, struct sk_buff *skb) int lapb_data_transmit(struct lapb_cb *lapb, struct sk_buff *skb)
{ {
int used = 0; int used = 0;
if (lapb->callbacks.data_transmit != NULL) { if (lapb->callbacks.data_transmit) {
(lapb->callbacks.data_transmit)(lapb->token, skb); lapb->callbacks.data_transmit(lapb->token, skb);
used = 1; used = 1;
} }
......
...@@ -40,26 +40,33 @@ ...@@ -40,26 +40,33 @@
* State machine for state 0, Disconnected State. * State machine for state 0, Disconnected State.
* The handling of the timer(s) is in file lapb_timer.c. * The handling of the timer(s) is in file lapb_timer.c.
*/ */
static void lapb_state0_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame) static void lapb_state0_machine(struct lapb_cb *lapb, struct sk_buff *skb,
struct lapb_frame *frame)
{ {
switch (frame->type) { switch (frame->type) {
case LAPB_SABM: case LAPB_SABM:
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S0 RX SABM(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S0 RX SABM(%d)\n",
lapb->token, frame->pf);
#endif #endif
if (lapb->mode & LAPB_EXTENDED) { if (lapb->mode & LAPB_EXTENDED) {
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S0 TX DM(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S0 TX DM(%d)\n",
lapb->token, frame->pf);
#endif #endif
lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); lapb_send_control(lapb, LAPB_DM, frame->pf,
LAPB_RESPONSE);
} else { } else {
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S0 TX UA(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S0 TX UA(%d)\n",
lapb->token, frame->pf);
#endif #endif
#if LAPB_DEBUG > 0 #if LAPB_DEBUG > 0
printk(KERN_DEBUG "lapb: (%p) S0 -> S3\n", lapb->token); printk(KERN_DEBUG "lapb: (%p) S0 -> S3\n",
lapb->token);
#endif #endif
lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); lapb_send_control(lapb, LAPB_UA, frame->pf,
LAPB_RESPONSE);
lapb_stop_t1timer(lapb); lapb_stop_t1timer(lapb);
lapb_stop_t2timer(lapb); lapb_stop_t2timer(lapb);
lapb->state = LAPB_STATE_3; lapb->state = LAPB_STATE_3;
...@@ -74,16 +81,20 @@ static void lapb_state0_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_ ...@@ -74,16 +81,20 @@ static void lapb_state0_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
case LAPB_SABME: case LAPB_SABME:
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S0 RX SABME(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S0 RX SABME(%d)\n",
lapb->token, frame->pf);
#endif #endif
if (lapb->mode & LAPB_EXTENDED) { if (lapb->mode & LAPB_EXTENDED) {
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S0 TX UA(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S0 TX UA(%d)\n",
lapb->token, frame->pf);
#endif #endif
#if LAPB_DEBUG > 0 #if LAPB_DEBUG > 0
printk(KERN_DEBUG "lapb: (%p) S0 -> S3\n", lapb->token); printk(KERN_DEBUG "lapb: (%p) S0 -> S3\n",
lapb->token);
#endif #endif
lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); lapb_send_control(lapb, LAPB_UA, frame->pf,
LAPB_RESPONSE);
lapb_stop_t1timer(lapb); lapb_stop_t1timer(lapb);
lapb_stop_t2timer(lapb); lapb_stop_t2timer(lapb);
lapb->state = LAPB_STATE_3; lapb->state = LAPB_STATE_3;
...@@ -95,18 +106,23 @@ static void lapb_state0_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_ ...@@ -95,18 +106,23 @@ static void lapb_state0_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
lapb_connect_indication(lapb, LAPB_OK); lapb_connect_indication(lapb, LAPB_OK);
} else { } else {
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S0 TX DM(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S0 TX DM(%d)\n",
lapb->token, frame->pf);
#endif #endif
lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); lapb_send_control(lapb, LAPB_DM, frame->pf,
LAPB_RESPONSE);
} }
break; break;
case LAPB_DISC: case LAPB_DISC:
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S0 RX DISC(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S0 RX DISC(%d)\n",
printk(KERN_DEBUG "lapb: (%p) S0 TX UA(%d)\n", lapb->token, frame->pf); lapb->token, frame->pf);
printk(KERN_DEBUG "lapb: (%p) S0 TX UA(%d)\n",
lapb->token, frame->pf);
#endif #endif
lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); lapb_send_control(lapb, LAPB_UA, frame->pf,
LAPB_RESPONSE);
break; break;
default: default:
...@@ -120,58 +136,74 @@ static void lapb_state0_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_ ...@@ -120,58 +136,74 @@ static void lapb_state0_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
* State machine for state 1, Awaiting Connection State. * State machine for state 1, Awaiting Connection State.
* The handling of the timer(s) is in file lapb_timer.c. * The handling of the timer(s) is in file lapb_timer.c.
*/ */
static void lapb_state1_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame) static void lapb_state1_machine(struct lapb_cb *lapb, struct sk_buff *skb,
struct lapb_frame *frame)
{ {
switch (frame->type) { switch (frame->type) {
case LAPB_SABM: case LAPB_SABM:
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S1 RX SABM(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S1 RX SABM(%d)\n",
lapb->token, frame->pf);
#endif #endif
if (lapb->mode & LAPB_EXTENDED) { if (lapb->mode & LAPB_EXTENDED) {
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S1 TX DM(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S1 TX DM(%d)\n",
lapb->token, frame->pf);
#endif #endif
lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); lapb_send_control(lapb, LAPB_DM, frame->pf,
LAPB_RESPONSE);
} else { } else {
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S1 TX UA(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S1 TX UA(%d)\n",
lapb->token, frame->pf);
#endif #endif
lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); lapb_send_control(lapb, LAPB_UA, frame->pf,
LAPB_RESPONSE);
} }
break; break;
case LAPB_SABME: case LAPB_SABME:
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S1 RX SABME(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S1 RX SABME(%d)\n",
lapb->token, frame->pf);
#endif #endif
if (lapb->mode & LAPB_EXTENDED) { if (lapb->mode & LAPB_EXTENDED) {
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S1 TX UA(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S1 TX UA(%d)\n",
lapb->token, frame->pf);
#endif #endif
lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); lapb_send_control(lapb, LAPB_UA, frame->pf,
LAPB_RESPONSE);
} else { } else {
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S1 TX DM(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S1 TX DM(%d)\n",
lapb->token, frame->pf);
#endif #endif
lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); lapb_send_control(lapb, LAPB_DM, frame->pf,
LAPB_RESPONSE);
} }
break; break;
case LAPB_DISC: case LAPB_DISC:
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S1 RX DISC(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S1 RX DISC(%d)\n",
printk(KERN_DEBUG "lapb: (%p) S1 TX DM(%d)\n", lapb->token, frame->pf); lapb->token, frame->pf);
printk(KERN_DEBUG "lapb: (%p) S1 TX DM(%d)\n",
lapb->token, frame->pf);
#endif #endif
lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); lapb_send_control(lapb, LAPB_DM, frame->pf,
LAPB_RESPONSE);
break; break;
case LAPB_UA: case LAPB_UA:
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S1 RX UA(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S1 RX UA(%d)\n",
lapb->token, frame->pf);
#endif #endif
if (frame->pf) { if (frame->pf) {
#if LAPB_DEBUG > 0 #if LAPB_DEBUG > 0
printk(KERN_DEBUG "lapb: (%p) S1 -> S3\n", lapb->token); printk(KERN_DEBUG "lapb: (%p) S1 -> S3\n",
lapb->token);
#endif #endif
lapb_stop_t1timer(lapb); lapb_stop_t1timer(lapb);
lapb_stop_t2timer(lapb); lapb_stop_t2timer(lapb);
...@@ -187,11 +219,13 @@ static void lapb_state1_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_ ...@@ -187,11 +219,13 @@ static void lapb_state1_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
case LAPB_DM: case LAPB_DM:
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S1 RX DM(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S1 RX DM(%d)\n",
lapb->token, frame->pf);
#endif #endif
if (frame->pf) { if (frame->pf) {
#if LAPB_DEBUG > 0 #if LAPB_DEBUG > 0
printk(KERN_DEBUG "lapb: (%p) S1 -> S0\n", lapb->token); printk(KERN_DEBUG "lapb: (%p) S1 -> S0\n",
lapb->token);
#endif #endif
lapb_clear_queues(lapb); lapb_clear_queues(lapb);
lapb->state = LAPB_STATE_0; lapb->state = LAPB_STATE_0;
...@@ -200,9 +234,6 @@ static void lapb_state1_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_ ...@@ -200,9 +234,6 @@ static void lapb_state1_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
lapb_disconnect_indication(lapb, LAPB_REFUSED); lapb_disconnect_indication(lapb, LAPB_REFUSED);
} }
break; break;
default:
break;
} }
kfree_skb(skb); kfree_skb(skb);
...@@ -212,33 +243,42 @@ static void lapb_state1_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_ ...@@ -212,33 +243,42 @@ static void lapb_state1_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
* State machine for state 2, Awaiting Release State. * State machine for state 2, Awaiting Release State.
* The handling of the timer(s) is in file lapb_timer.c * The handling of the timer(s) is in file lapb_timer.c
*/ */
static void lapb_state2_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame) static void lapb_state2_machine(struct lapb_cb *lapb, struct sk_buff *skb,
struct lapb_frame *frame)
{ {
switch (frame->type) { switch (frame->type) {
case LAPB_SABM: case LAPB_SABM:
case LAPB_SABME: case LAPB_SABME:
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S2 RX {SABM,SABME}(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S2 RX {SABM,SABME}(%d)\n",
printk(KERN_DEBUG "lapb: (%p) S2 TX DM(%d)\n", lapb->token, frame->pf); lapb->token, frame->pf);
printk(KERN_DEBUG "lapb: (%p) S2 TX DM(%d)\n",
lapb->token, frame->pf);
#endif #endif
lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); lapb_send_control(lapb, LAPB_DM, frame->pf,
LAPB_RESPONSE);
break; break;
case LAPB_DISC: case LAPB_DISC:
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S2 RX DISC(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S2 RX DISC(%d)\n",
printk(KERN_DEBUG "lapb: (%p) S2 TX UA(%d)\n", lapb->token, frame->pf); lapb->token, frame->pf);
printk(KERN_DEBUG "lapb: (%p) S2 TX UA(%d)\n",
lapb->token, frame->pf);
#endif #endif
lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); lapb_send_control(lapb, LAPB_UA, frame->pf,
LAPB_RESPONSE);
break; break;
case LAPB_UA: case LAPB_UA:
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S2 RX UA(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S2 RX UA(%d)\n",
lapb->token, frame->pf);
#endif #endif
if (frame->pf) { if (frame->pf) {
#if LAPB_DEBUG > 0 #if LAPB_DEBUG > 0
printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n", lapb->token); printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n",
lapb->token);
#endif #endif
lapb->state = LAPB_STATE_0; lapb->state = LAPB_STATE_0;
lapb_start_t1timer(lapb); lapb_start_t1timer(lapb);
...@@ -249,16 +289,19 @@ static void lapb_state2_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_ ...@@ -249,16 +289,19 @@ static void lapb_state2_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
case LAPB_DM: case LAPB_DM:
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S2 RX DM(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S2 RX DM(%d)\n",
lapb->token, frame->pf);
#endif #endif
if (frame->pf) { if (frame->pf) {
#if LAPB_DEBUG > 0 #if LAPB_DEBUG > 0
printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n", lapb->token); printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n",
lapb->token);
#endif #endif
lapb->state = LAPB_STATE_0; lapb->state = LAPB_STATE_0;
lapb_start_t1timer(lapb); lapb_start_t1timer(lapb);
lapb_stop_t2timer(lapb); lapb_stop_t2timer(lapb);
lapb_disconnect_confirmation(lapb, LAPB_NOTCONNECTED); lapb_disconnect_confirmation(lapb,
LAPB_NOTCONNECTED);
} }
break; break;
...@@ -267,13 +310,14 @@ static void lapb_state2_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_ ...@@ -267,13 +310,14 @@ static void lapb_state2_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
case LAPB_RNR: case LAPB_RNR:
case LAPB_RR: case LAPB_RR:
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S2 RX {I,REJ,RNR,RR}(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S2 RX {I,REJ,RNR,RR}"
printk(KERN_DEBUG "lapb: (%p) S2 RX DM(%d)\n", lapb->token, frame->pf); "(%d)\n", lapb->token, frame->pf);
printk(KERN_DEBUG "lapb: (%p) S2 RX DM(%d)\n",
lapb->token, frame->pf);
#endif #endif
if (frame->pf) lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); if (frame->pf)
break; lapb_send_control(lapb, LAPB_DM, frame->pf,
LAPB_RESPONSE);
default:
break; break;
} }
...@@ -284,28 +328,33 @@ static void lapb_state2_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_ ...@@ -284,28 +328,33 @@ static void lapb_state2_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
* State machine for state 3, Connected State. * State machine for state 3, Connected State.
* The handling of the timer(s) is in file lapb_timer.c * The handling of the timer(s) is in file lapb_timer.c
*/ */
static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame) static void lapb_state3_machine(struct lapb_cb *lapb, struct sk_buff *skb,
struct lapb_frame *frame)
{ {
int queued = 0; int queued = 0;
int modulus; int modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS :
LAPB_SMODULUS;
modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS : LAPB_SMODULUS;
switch (frame->type) { switch (frame->type) {
case LAPB_SABM: case LAPB_SABM:
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S3 RX SABM(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S3 RX SABM(%d)\n",
lapb->token, frame->pf);
#endif #endif
if (lapb->mode & LAPB_EXTENDED) { if (lapb->mode & LAPB_EXTENDED) {
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S3 TX DM(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S3 TX DM(%d)\n",
lapb->token, frame->pf);
#endif #endif
lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); lapb_send_control(lapb, LAPB_DM, frame->pf,
LAPB_RESPONSE);
} else { } else {
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S3 TX UA(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S3 TX UA(%d)\n",
lapb->token, frame->pf);
#endif #endif
lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); lapb_send_control(lapb, LAPB_UA, frame->pf,
LAPB_RESPONSE);
lapb_stop_t1timer(lapb); lapb_stop_t1timer(lapb);
lapb_stop_t2timer(lapb); lapb_stop_t2timer(lapb);
lapb->condition = 0x00; lapb->condition = 0x00;
...@@ -319,13 +368,16 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_ ...@@ -319,13 +368,16 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
case LAPB_SABME: case LAPB_SABME:
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S3 RX SABME(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S3 RX SABME(%d)\n",
lapb->token, frame->pf);
#endif #endif
if (lapb->mode & LAPB_EXTENDED) { if (lapb->mode & LAPB_EXTENDED) {
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S3 TX UA(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S3 TX UA(%d)\n",
lapb->token, frame->pf);
#endif #endif
lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); lapb_send_control(lapb, LAPB_UA, frame->pf,
LAPB_RESPONSE);
lapb_stop_t1timer(lapb); lapb_stop_t1timer(lapb);
lapb_stop_t2timer(lapb); lapb_stop_t2timer(lapb);
lapb->condition = 0x00; lapb->condition = 0x00;
...@@ -336,21 +388,26 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_ ...@@ -336,21 +388,26 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
lapb_requeue_frames(lapb); lapb_requeue_frames(lapb);
} else { } else {
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S3 TX DM(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S3 TX DM(%d)\n",
lapb->token, frame->pf);
#endif #endif
lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); lapb_send_control(lapb, LAPB_DM, frame->pf,
LAPB_RESPONSE);
} }
break; break;
case LAPB_DISC: case LAPB_DISC:
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S3 RX DISC(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S3 RX DISC(%d)\n",
lapb->token, frame->pf);
#endif #endif
#if LAPB_DEBUG > 0 #if LAPB_DEBUG > 0
printk(KERN_DEBUG "lapb: (%p) S3 -> S0\n", lapb->token); printk(KERN_DEBUG "lapb: (%p) S3 -> S0\n",
lapb->token);
#endif #endif
lapb_clear_queues(lapb); lapb_clear_queues(lapb);
lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); lapb_send_control(lapb, LAPB_UA, frame->pf,
LAPB_RESPONSE);
lapb_start_t1timer(lapb); lapb_start_t1timer(lapb);
lapb_stop_t2timer(lapb); lapb_stop_t2timer(lapb);
lapb->state = LAPB_STATE_0; lapb->state = LAPB_STATE_0;
...@@ -359,10 +416,12 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_ ...@@ -359,10 +416,12 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
case LAPB_DM: case LAPB_DM:
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S3 RX DM(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S3 RX DM(%d)\n",
lapb->token, frame->pf);
#endif #endif
#if LAPB_DEBUG > 0 #if LAPB_DEBUG > 0
printk(KERN_DEBUG "lapb: (%p) S3 -> S0\n", lapb->token); printk(KERN_DEBUG "lapb: (%p) S3 -> S0\n",
lapb->token);
#endif #endif
lapb_clear_queues(lapb); lapb_clear_queues(lapb);
lapb->state = LAPB_STATE_0; lapb->state = LAPB_STATE_0;
...@@ -373,7 +432,8 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_ ...@@ -373,7 +432,8 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
case LAPB_RNR: case LAPB_RNR:
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S3 RX RNR(%d) R%d\n", lapb->token, frame->pf, frame->nr); printk(KERN_DEBUG "lapb: (%p) S3 RX RNR(%d) R%d\n",
lapb->token, frame->pf, frame->nr);
#endif #endif
lapb->condition |= LAPB_PEER_RX_BUSY_CONDITION; lapb->condition |= LAPB_PEER_RX_BUSY_CONDITION;
lapb_check_need_response(lapb, frame->cr, frame->pf); lapb_check_need_response(lapb, frame->cr, frame->pf);
...@@ -384,7 +444,8 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_ ...@@ -384,7 +444,8 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
lapb->frmr_type = LAPB_FRMR_Z; lapb->frmr_type = LAPB_FRMR_Z;
lapb_transmit_frmr(lapb); lapb_transmit_frmr(lapb);
#if LAPB_DEBUG > 0 #if LAPB_DEBUG > 0
printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->token); printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n",
lapb->token);
#endif #endif
lapb_start_t1timer(lapb); lapb_start_t1timer(lapb);
lapb_stop_t2timer(lapb); lapb_stop_t2timer(lapb);
...@@ -395,7 +456,8 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_ ...@@ -395,7 +456,8 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
case LAPB_RR: case LAPB_RR:
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S3 RX RR(%d) R%d\n", lapb->token, frame->pf, frame->nr); printk(KERN_DEBUG "lapb: (%p) S3 RX RR(%d) R%d\n",
lapb->token, frame->pf, frame->nr);
#endif #endif
lapb->condition &= ~LAPB_PEER_RX_BUSY_CONDITION; lapb->condition &= ~LAPB_PEER_RX_BUSY_CONDITION;
lapb_check_need_response(lapb, frame->cr, frame->pf); lapb_check_need_response(lapb, frame->cr, frame->pf);
...@@ -406,7 +468,8 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_ ...@@ -406,7 +468,8 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
lapb->frmr_type = LAPB_FRMR_Z; lapb->frmr_type = LAPB_FRMR_Z;
lapb_transmit_frmr(lapb); lapb_transmit_frmr(lapb);
#if LAPB_DEBUG > 0 #if LAPB_DEBUG > 0
printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->token); printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n",
lapb->token);
#endif #endif
lapb_start_t1timer(lapb); lapb_start_t1timer(lapb);
lapb_stop_t2timer(lapb); lapb_stop_t2timer(lapb);
...@@ -417,7 +480,8 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_ ...@@ -417,7 +480,8 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
case LAPB_REJ: case LAPB_REJ:
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S3 RX REJ(%d) R%d\n", lapb->token, frame->pf, frame->nr); printk(KERN_DEBUG "lapb: (%p) S3 RX REJ(%d) R%d\n",
lapb->token, frame->pf, frame->nr);
#endif #endif
lapb->condition &= ~LAPB_PEER_RX_BUSY_CONDITION; lapb->condition &= ~LAPB_PEER_RX_BUSY_CONDITION;
lapb_check_need_response(lapb, frame->cr, frame->pf); lapb_check_need_response(lapb, frame->cr, frame->pf);
...@@ -431,7 +495,8 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_ ...@@ -431,7 +495,8 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
lapb->frmr_type = LAPB_FRMR_Z; lapb->frmr_type = LAPB_FRMR_Z;
lapb_transmit_frmr(lapb); lapb_transmit_frmr(lapb);
#if LAPB_DEBUG > 0 #if LAPB_DEBUG > 0
printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->token); printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n",
lapb->token);
#endif #endif
lapb_start_t1timer(lapb); lapb_start_t1timer(lapb);
lapb_stop_t2timer(lapb); lapb_stop_t2timer(lapb);
...@@ -442,14 +507,16 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_ ...@@ -442,14 +507,16 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
case LAPB_I: case LAPB_I:
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S3 RX I(%d) S%d R%d\n", lapb->token, frame->pf, frame->ns, frame->nr); printk(KERN_DEBUG "lapb: (%p) S3 RX I(%d) S%d R%d\n",
lapb->token, frame->pf, frame->ns, frame->nr);
#endif #endif
if (!lapb_validate_nr(lapb, frame->nr)) { if (!lapb_validate_nr(lapb, frame->nr)) {
lapb->frmr_data = *frame; lapb->frmr_data = *frame;
lapb->frmr_type = LAPB_FRMR_Z; lapb->frmr_type = LAPB_FRMR_Z;
lapb_transmit_frmr(lapb); lapb_transmit_frmr(lapb);
#if LAPB_DEBUG > 0 #if LAPB_DEBUG > 0
printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->token); printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n",
lapb->token);
#endif #endif
lapb_start_t1timer(lapb); lapb_start_t1timer(lapb);
lapb_stop_t2timer(lapb); lapb_stop_t2timer(lapb);
...@@ -457,11 +524,11 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_ ...@@ -457,11 +524,11 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
lapb->n2count = 0; lapb->n2count = 0;
break; break;
} }
if (lapb->condition & LAPB_PEER_RX_BUSY_CONDITION) { if (lapb->condition & LAPB_PEER_RX_BUSY_CONDITION)
lapb_frames_acked(lapb, frame->nr); lapb_frames_acked(lapb, frame->nr);
} else { else
lapb_check_iframes_acked(lapb, frame->nr); lapb_check_iframes_acked(lapb, frame->nr);
}
if (frame->ns == lapb->vr) { if (frame->ns == lapb->vr) {
int cn; int cn;
cn = lapb_data_indication(lapb, skb); cn = lapb_data_indication(lapb, skb);
...@@ -473,16 +540,18 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_ ...@@ -473,16 +540,18 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
* to re-transmit the frame later like * to re-transmit the frame later like
* a frame lost on the wire. * a frame lost on the wire.
*/ */
if(cn == NET_RX_DROP){ if (cn == NET_RX_DROP) {
printk(KERN_DEBUG "LAPB: rx congestion\n"); printk(KERN_DEBUG
"LAPB: rx congestion\n");
break; break;
} }
lapb->vr = (lapb->vr + 1) % modulus; lapb->vr = (lapb->vr + 1) % modulus;
lapb->condition &= ~LAPB_REJECT_CONDITION; lapb->condition &= ~LAPB_REJECT_CONDITION;
if (frame->pf) { if (frame->pf)
lapb_enquiry_response(lapb); lapb_enquiry_response(lapb);
} else { else {
if (!(lapb->condition & LAPB_ACK_PENDING_CONDITION)) { if (!(lapb->condition &
LAPB_ACK_PENDING_CONDITION)) {
lapb->condition |= LAPB_ACK_PENDING_CONDITION; lapb->condition |= LAPB_ACK_PENDING_CONDITION;
lapb_start_t2timer(lapb); lapb_start_t2timer(lapb);
} }
...@@ -493,10 +562,14 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_ ...@@ -493,10 +562,14 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
lapb_enquiry_response(lapb); lapb_enquiry_response(lapb);
} else { } else {
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S3 TX REJ(%d) R%d\n", lapb->token, frame->pf, lapb->vr); printk(KERN_DEBUG
"lapb: (%p) S3 TX REJ(%d) R%d\n",
lapb->token, frame->pf, lapb->vr);
#endif #endif
lapb->condition |= LAPB_REJECT_CONDITION; lapb->condition |= LAPB_REJECT_CONDITION;
lapb_send_control(lapb, LAPB_REJ, frame->pf, LAPB_RESPONSE); lapb_send_control(lapb, LAPB_REJ,
frame->pf,
LAPB_RESPONSE);
lapb->condition &= ~LAPB_ACK_PENDING_CONDITION; lapb->condition &= ~LAPB_ACK_PENDING_CONDITION;
} }
} }
...@@ -504,11 +577,15 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_ ...@@ -504,11 +577,15 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
case LAPB_FRMR: case LAPB_FRMR:
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S3 RX FRMR(%d) %02X %02X %02X %02X %02X\n", lapb->token, frame->pf, skb->data[0], skb->data[1], skb->data[2], skb->data[3], skb->data[4]); printk(KERN_DEBUG "lapb: (%p) S3 RX FRMR(%d) %02X "
"%02X %02X %02X %02X\n", lapb->token, frame->pf,
skb->data[0], skb->data[1], skb->data[2],
skb->data[3], skb->data[4]);
#endif #endif
lapb_establish_data_link(lapb); lapb_establish_data_link(lapb);
#if LAPB_DEBUG > 0 #if LAPB_DEBUG > 0
printk(KERN_DEBUG "lapb: (%p) S3 -> S1\n", lapb->token); printk(KERN_DEBUG "lapb: (%p) S3 -> S1\n",
lapb->token);
#endif #endif
lapb_requeue_frames(lapb); lapb_requeue_frames(lapb);
lapb->state = LAPB_STATE_1; lapb->state = LAPB_STATE_1;
...@@ -516,7 +593,8 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_ ...@@ -516,7 +593,8 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
case LAPB_ILLEGAL: case LAPB_ILLEGAL:
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S3 RX ILLEGAL(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S3 RX ILLEGAL(%d)\n",
lapb->token, frame->pf);
#endif #endif
lapb->frmr_data = *frame; lapb->frmr_data = *frame;
lapb->frmr_type = LAPB_FRMR_W; lapb->frmr_type = LAPB_FRMR_W;
...@@ -529,9 +607,6 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_ ...@@ -529,9 +607,6 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
lapb->state = LAPB_STATE_4; lapb->state = LAPB_STATE_4;
lapb->n2count = 0; lapb->n2count = 0;
break; break;
default:
break;
} }
if (!queued) if (!queued)
...@@ -542,26 +617,33 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_ ...@@ -542,26 +617,33 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
* State machine for state 4, Frame Reject State. * State machine for state 4, Frame Reject State.
* The handling of the timer(s) is in file lapb_timer.c. * The handling of the timer(s) is in file lapb_timer.c.
*/ */
static void lapb_state4_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame) static void lapb_state4_machine(struct lapb_cb *lapb, struct sk_buff *skb,
struct lapb_frame *frame)
{ {
switch (frame->type) { switch (frame->type) {
case LAPB_SABM: case LAPB_SABM:
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S4 RX SABM(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S4 RX SABM(%d)\n",
lapb->token, frame->pf);
#endif #endif
if (lapb->mode & LAPB_EXTENDED) { if (lapb->mode & LAPB_EXTENDED) {
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S4 TX DM(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S4 TX DM(%d)\n",
lapb->token, frame->pf);
#endif #endif
lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); lapb_send_control(lapb, LAPB_DM, frame->pf,
LAPB_RESPONSE);
} else { } else {
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S4 TX UA(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S4 TX UA(%d)\n",
lapb->token, frame->pf);
#endif #endif
#if LAPB_DEBUG > 0 #if LAPB_DEBUG > 0
printk(KERN_DEBUG "lapb: (%p) S4 -> S3\n", lapb->token); printk(KERN_DEBUG "lapb: (%p) S4 -> S3\n",
lapb->token);
#endif #endif
lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); lapb_send_control(lapb, LAPB_UA, frame->pf,
LAPB_RESPONSE);
lapb_stop_t1timer(lapb); lapb_stop_t1timer(lapb);
lapb_stop_t2timer(lapb); lapb_stop_t2timer(lapb);
lapb->state = LAPB_STATE_3; lapb->state = LAPB_STATE_3;
...@@ -576,16 +658,20 @@ static void lapb_state4_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_ ...@@ -576,16 +658,20 @@ static void lapb_state4_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
case LAPB_SABME: case LAPB_SABME:
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S4 RX SABME(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S4 RX SABME(%d)\n",
lapb->token, frame->pf);
#endif #endif
if (lapb->mode & LAPB_EXTENDED) { if (lapb->mode & LAPB_EXTENDED) {
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S4 TX UA(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S4 TX UA(%d)\n",
lapb->token, frame->pf);
#endif #endif
#if LAPB_DEBUG > 0 #if LAPB_DEBUG > 0
printk(KERN_DEBUG "lapb: (%p) S4 -> S3\n", lapb->token); printk(KERN_DEBUG "lapb: (%p) S4 -> S3\n",
lapb->token);
#endif #endif
lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); lapb_send_control(lapb, LAPB_UA, frame->pf,
LAPB_RESPONSE);
lapb_stop_t1timer(lapb); lapb_stop_t1timer(lapb);
lapb_stop_t2timer(lapb); lapb_stop_t2timer(lapb);
lapb->state = LAPB_STATE_3; lapb->state = LAPB_STATE_3;
...@@ -597,14 +683,13 @@ static void lapb_state4_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_ ...@@ -597,14 +683,13 @@ static void lapb_state4_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
lapb_connect_indication(lapb, LAPB_OK); lapb_connect_indication(lapb, LAPB_OK);
} else { } else {
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S4 TX DM(%d)\n", lapb->token, frame->pf); printk(KERN_DEBUG "lapb: (%p) S4 TX DM(%d)\n",
lapb->token, frame->pf);
#endif #endif
lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); lapb_send_control(lapb, LAPB_DM, frame->pf,
LAPB_RESPONSE);
} }
break; break;
default:
break;
} }
kfree_skb(skb); kfree_skb(skb);
...@@ -613,28 +698,23 @@ static void lapb_state4_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_ ...@@ -613,28 +698,23 @@ static void lapb_state4_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
/* /*
* Process an incoming LAPB frame * Process an incoming LAPB frame
*/ */
void lapb_data_input(lapb_cb *lapb, struct sk_buff *skb) void lapb_data_input(struct lapb_cb *lapb, struct sk_buff *skb)
{ {
struct lapb_frame frame; struct lapb_frame frame;
lapb_decode(lapb, skb, &frame); lapb_decode(lapb, skb, &frame);
switch (lapb->state) { switch (lapb->state) {
case LAPB_STATE_0: case LAPB_STATE_0:
lapb_state0_machine(lapb, skb, &frame); lapb_state0_machine(lapb, skb, &frame); break;
break; case LAPB_STATE_1:
case LAPB_STATE_1: lapb_state1_machine(lapb, skb, &frame); break;
lapb_state1_machine(lapb, skb, &frame); case LAPB_STATE_2:
break; lapb_state2_machine(lapb, skb, &frame); break;
case LAPB_STATE_2: case LAPB_STATE_3:
lapb_state2_machine(lapb, skb, &frame); lapb_state3_machine(lapb, skb, &frame); break;
break; case LAPB_STATE_4:
case LAPB_STATE_3: lapb_state4_machine(lapb, skb, &frame); break;
lapb_state3_machine(lapb, skb, &frame);
break;
case LAPB_STATE_4:
lapb_state4_machine(lapb, skb, &frame);
break;
} }
lapb_kick(lapb); lapb_kick(lapb);
......
...@@ -38,56 +38,54 @@ ...@@ -38,56 +38,54 @@
* This procedure is passed a buffer descriptor for an iframe. It builds * This procedure is passed a buffer descriptor for an iframe. It builds
* the rest of the control part of the frame and then writes it out. * the rest of the control part of the frame and then writes it out.
*/ */
static void lapb_send_iframe(lapb_cb *lapb, struct sk_buff *skb, int poll_bit) static void lapb_send_iframe(struct lapb_cb *lapb, struct sk_buff *skb, int poll_bit)
{ {
unsigned char *frame; unsigned char *frame;
if (skb == NULL) if (!skb)
return; return;
if (lapb->mode & LAPB_EXTENDED) { if (lapb->mode & LAPB_EXTENDED) {
frame = skb_push(skb, 2); frame = skb_push(skb, 2);
frame[0] = LAPB_I; frame[0] = LAPB_I;
frame[0] |= (lapb->vs << 1); frame[0] |= lapb->vs << 1;
frame[1] = (poll_bit) ? LAPB_EPF : 0; frame[1] = poll_bit ? LAPB_EPF : 0;
frame[1] |= (lapb->vr << 1); frame[1] |= lapb->vr << 1;
} else { } else {
frame = skb_push(skb, 1); frame = skb_push(skb, 1);
*frame = LAPB_I; *frame = LAPB_I;
*frame |= (poll_bit) ? LAPB_SPF : 0; *frame |= poll_bit ? LAPB_SPF : 0;
*frame |= (lapb->vr << 5); *frame |= lapb->vr << 5;
*frame |= (lapb->vs << 1); *frame |= lapb->vs << 1;
} }
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S%d TX I(%d) S%d R%d\n", lapb->token, lapb->state, poll_bit, lapb->vs, lapb->vr); printk(KERN_DEBUG "lapb: (%p) S%d TX I(%d) S%d R%d\n",
lapb->token, lapb->state, poll_bit, lapb->vs, lapb->vr);
#endif #endif
lapb_transmit_buffer(lapb, skb, LAPB_COMMAND); lapb_transmit_buffer(lapb, skb, LAPB_COMMAND);
} }
void lapb_kick(lapb_cb *lapb) void lapb_kick(struct lapb_cb *lapb)
{ {
struct sk_buff *skb, *skbn; struct sk_buff *skb, *skbn;
unsigned short modulus, start, end; unsigned short modulus, start, end;
modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS : LAPB_SMODULUS; modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS : LAPB_SMODULUS;
start = !skb_peek(&lapb->ack_queue) ? lapb->va : lapb->vs;
start = (skb_peek(&lapb->ack_queue) == NULL) ? lapb->va : lapb->vs;
end = (lapb->va + lapb->window) % modulus; end = (lapb->va + lapb->window) % modulus;
if (!(lapb->condition & LAPB_PEER_RX_BUSY_CONDITION) && if (!(lapb->condition & LAPB_PEER_RX_BUSY_CONDITION) &&
start != end && start != end && skb_peek(&lapb->write_queue)) {
skb_peek(&lapb->write_queue) != NULL) {
lapb->vs = start; lapb->vs = start;
/* /*
* Dequeue the frame and copy it. * Dequeue the frame and copy it.
*/ */
skb = skb_dequeue(&lapb->write_queue); skb = skb_dequeue(&lapb->write_queue);
do { do {
if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) { if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) {
...@@ -95,7 +93,7 @@ void lapb_kick(lapb_cb *lapb) ...@@ -95,7 +93,7 @@ void lapb_kick(lapb_cb *lapb)
break; break;
} }
if (skb->sk != NULL) if (skb->sk)
skb_set_owner_w(skbn, skb->sk); skb_set_owner_w(skbn, skb->sk);
/* /*
...@@ -119,7 +117,7 @@ void lapb_kick(lapb_cb *lapb) ...@@ -119,7 +117,7 @@ void lapb_kick(lapb_cb *lapb)
} }
} }
void lapb_transmit_buffer(lapb_cb *lapb, struct sk_buff *skb, int type) void lapb_transmit_buffer(struct lapb_cb *lapb, struct sk_buff *skb, int type)
{ {
unsigned char *ptr; unsigned char *ptr;
...@@ -152,26 +150,30 @@ void lapb_transmit_buffer(lapb_cb *lapb, struct sk_buff *skb, int type) ...@@ -152,26 +150,30 @@ void lapb_transmit_buffer(lapb_cb *lapb, struct sk_buff *skb, int type)
} }
#if LAPB_DEBUG > 2 #if LAPB_DEBUG > 2
printk(KERN_DEBUG "lapb: (%p) S%d TX %02X %02X %02X\n", lapb->token, lapb->state, skb->data[0], skb->data[1], skb->data[2]); printk(KERN_DEBUG "lapb: (%p) S%d TX %02X %02X %02X\n",
lapb->token, lapb->state,
skb->data[0], skb->data[1], skb->data[2]);
#endif #endif
if (!lapb_data_transmit(lapb, skb)) if (!lapb_data_transmit(lapb, skb))
kfree_skb(skb); kfree_skb(skb);
} }
void lapb_establish_data_link(lapb_cb *lapb) void lapb_establish_data_link(struct lapb_cb *lapb)
{ {
lapb->condition = 0x00; lapb->condition = 0x00;
lapb->n2count = 0; lapb->n2count = 0;
if (lapb->mode & LAPB_EXTENDED) { if (lapb->mode & LAPB_EXTENDED) {
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S%d TX SABME(1)\n", lapb->token, lapb->state); printk(KERN_DEBUG "lapb: (%p) S%d TX SABME(1)\n",
lapb->token, lapb->state);
#endif #endif
lapb_send_control(lapb, LAPB_SABME, LAPB_POLLON, LAPB_COMMAND); lapb_send_control(lapb, LAPB_SABME, LAPB_POLLON, LAPB_COMMAND);
} else { } else {
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S%d TX SABM(1)\n", lapb->token, lapb->state); printk(KERN_DEBUG "lapb: (%p) S%d TX SABM(1)\n",
lapb->token, lapb->state);
#endif #endif
lapb_send_control(lapb, LAPB_SABM, LAPB_POLLON, LAPB_COMMAND); lapb_send_control(lapb, LAPB_SABM, LAPB_POLLON, LAPB_COMMAND);
} }
...@@ -180,10 +182,11 @@ void lapb_establish_data_link(lapb_cb *lapb) ...@@ -180,10 +182,11 @@ void lapb_establish_data_link(lapb_cb *lapb)
lapb_stop_t2timer(lapb); lapb_stop_t2timer(lapb);
} }
void lapb_enquiry_response(lapb_cb *lapb) void lapb_enquiry_response(struct lapb_cb *lapb)
{ {
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S%d TX RR(1) R%d\n", lapb->token, lapb->state, lapb->vr); printk(KERN_DEBUG "lapb: (%p) S%d TX RR(1) R%d\n",
lapb->token, lapb->state, lapb->vr);
#endif #endif
lapb_send_control(lapb, LAPB_RR, LAPB_POLLON, LAPB_RESPONSE); lapb_send_control(lapb, LAPB_RR, LAPB_POLLON, LAPB_RESPONSE);
...@@ -191,32 +194,30 @@ void lapb_enquiry_response(lapb_cb *lapb) ...@@ -191,32 +194,30 @@ void lapb_enquiry_response(lapb_cb *lapb)
lapb->condition &= ~LAPB_ACK_PENDING_CONDITION; lapb->condition &= ~LAPB_ACK_PENDING_CONDITION;
} }
void lapb_timeout_response(lapb_cb *lapb) void lapb_timeout_response(struct lapb_cb *lapb)
{ {
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S%d TX RR(0) R%d\n", lapb->token, lapb->state, lapb->vr); printk(KERN_DEBUG "lapb: (%p) S%d TX RR(0) R%d\n",
lapb->token, lapb->state, lapb->vr);
#endif #endif
lapb_send_control(lapb, LAPB_RR, LAPB_POLLOFF, LAPB_RESPONSE); lapb_send_control(lapb, LAPB_RR, LAPB_POLLOFF, LAPB_RESPONSE);
lapb->condition &= ~LAPB_ACK_PENDING_CONDITION; lapb->condition &= ~LAPB_ACK_PENDING_CONDITION;
} }
void lapb_check_iframes_acked(lapb_cb *lapb, unsigned short nr) void lapb_check_iframes_acked(struct lapb_cb *lapb, unsigned short nr)
{ {
if (lapb->vs == nr) { if (lapb->vs == nr) {
lapb_frames_acked(lapb, nr); lapb_frames_acked(lapb, nr);
lapb_stop_t1timer(lapb); lapb_stop_t1timer(lapb);
lapb->n2count = 0; lapb->n2count = 0;
} else { } else if (lapb->va != nr) {
if (lapb->va != nr) { lapb_frames_acked(lapb, nr);
lapb_frames_acked(lapb, nr); lapb_start_t1timer(lapb);
lapb_start_t1timer(lapb);
}
} }
} }
void lapb_check_need_response(lapb_cb *lapb, int type, int pf) void lapb_check_need_response(struct lapb_cb *lapb, int type, int pf)
{ {
if (type == LAPB_COMMAND && pf) if (type == LAPB_COMMAND && pf)
lapb_enquiry_response(lapb); lapb_enquiry_response(lapb);
......
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
/* /*
* This routine purges all the queues of frames. * This routine purges all the queues of frames.
*/ */
void lapb_clear_queues(lapb_cb *lapb) void lapb_clear_queues(struct lapb_cb *lapb)
{ {
skb_queue_purge(&lapb->write_queue); skb_queue_purge(&lapb->write_queue);
skb_queue_purge(&lapb->ack_queue); skb_queue_purge(&lapb->ack_queue);
...@@ -47,7 +47,7 @@ void lapb_clear_queues(lapb_cb *lapb) ...@@ -47,7 +47,7 @@ void lapb_clear_queues(lapb_cb *lapb)
* acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the * acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the
* SDL diagram. * SDL diagram.
*/ */
void lapb_frames_acked(lapb_cb *lapb, unsigned short nr) void lapb_frames_acked(struct lapb_cb *lapb, unsigned short nr)
{ {
struct sk_buff *skb; struct sk_buff *skb;
int modulus; int modulus;
...@@ -57,16 +57,15 @@ void lapb_frames_acked(lapb_cb *lapb, unsigned short nr) ...@@ -57,16 +57,15 @@ void lapb_frames_acked(lapb_cb *lapb, unsigned short nr)
/* /*
* Remove all the ack-ed frames from the ack queue. * Remove all the ack-ed frames from the ack queue.
*/ */
if (lapb->va != nr) { if (lapb->va != nr)
while (skb_peek(&lapb->ack_queue) != NULL && lapb->va != nr) { while (skb_peek(&lapb->ack_queue) && lapb->va != nr) {
skb = skb_dequeue(&lapb->ack_queue); skb = skb_dequeue(&lapb->ack_queue);
kfree_skb(skb); kfree_skb(skb);
lapb->va = (lapb->va + 1) % modulus; lapb->va = (lapb->va + 1) % modulus;
} }
}
} }
void lapb_requeue_frames(lapb_cb *lapb) void lapb_requeue_frames(struct lapb_cb *lapb)
{ {
struct sk_buff *skb, *skb_prev = NULL; struct sk_buff *skb, *skb_prev = NULL;
...@@ -76,7 +75,7 @@ void lapb_requeue_frames(lapb_cb *lapb) ...@@ -76,7 +75,7 @@ void lapb_requeue_frames(lapb_cb *lapb)
* possibility of an empty output queue. * possibility of an empty output queue.
*/ */
while ((skb = skb_dequeue(&lapb->ack_queue)) != NULL) { while ((skb = skb_dequeue(&lapb->ack_queue)) != NULL) {
if (skb_prev == NULL) if (!skb_prev)
skb_queue_head(&lapb->write_queue, skb); skb_queue_head(&lapb->write_queue, skb);
else else
skb_append(skb_prev, skb); skb_append(skb_prev, skb);
...@@ -88,7 +87,7 @@ void lapb_requeue_frames(lapb_cb *lapb) ...@@ -88,7 +87,7 @@ void lapb_requeue_frames(lapb_cb *lapb)
* Validate that the value of nr is between va and vs. Return true or * Validate that the value of nr is between va and vs. Return true or
* false for testing. * false for testing.
*/ */
int lapb_validate_nr(lapb_cb *lapb, unsigned short nr) int lapb_validate_nr(struct lapb_cb *lapb, unsigned short nr)
{ {
unsigned short vc = lapb->va; unsigned short vc = lapb->va;
int modulus; int modulus;
...@@ -96,25 +95,27 @@ int lapb_validate_nr(lapb_cb *lapb, unsigned short nr) ...@@ -96,25 +95,27 @@ int lapb_validate_nr(lapb_cb *lapb, unsigned short nr)
modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS : LAPB_SMODULUS; modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS : LAPB_SMODULUS;
while (vc != lapb->vs) { while (vc != lapb->vs) {
if (nr == vc) return 1; if (nr == vc)
return 1;
vc = (vc + 1) % modulus; vc = (vc + 1) % modulus;
} }
if (nr == lapb->vs) return 1; return nr == lapb->vs;
return 0;
} }
/* /*
* This routine is the centralised routine for parsing the control * This routine is the centralised routine for parsing the control
* information for the different frame formats. * information for the different frame formats.
*/ */
void lapb_decode(lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame) void lapb_decode(struct lapb_cb *lapb, struct sk_buff *skb,
struct lapb_frame *frame)
{ {
frame->type = LAPB_ILLEGAL; frame->type = LAPB_ILLEGAL;
#if LAPB_DEBUG > 2 #if LAPB_DEBUG > 2
printk(KERN_DEBUG "lapb: (%p) S%d RX %02X %02X %02X\n", lapb->token, lapb->state, skb->data[0], skb->data[1], skb->data[2]); printk(KERN_DEBUG "lapb: (%p) S%d RX %02X %02X %02X\n",
lapb->token, lapb->state,
skb->data[0], skb->data[1], skb->data[2]);
#endif #endif
if (lapb->mode & LAPB_MLP) { if (lapb->mode & LAPB_MLP) {
...@@ -146,22 +147,31 @@ void lapb_decode(lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame) ...@@ -146,22 +147,31 @@ void lapb_decode(lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame)
skb_pull(skb, 1); skb_pull(skb, 1);
if (lapb->mode & LAPB_EXTENDED) { if (lapb->mode & LAPB_EXTENDED) {
if ((skb->data[0] & LAPB_S) == 0) { if (!(skb->data[0] & LAPB_S)) {
frame->type = LAPB_I; /* I frame - carries NR/NS/PF */ /*
* I frame - carries NR/NS/PF
*/
frame->type = LAPB_I;
frame->ns = (skb->data[0] >> 1) & 0x7F; frame->ns = (skb->data[0] >> 1) & 0x7F;
frame->nr = (skb->data[1] >> 1) & 0x7F; frame->nr = (skb->data[1] >> 1) & 0x7F;
frame->pf = skb->data[1] & LAPB_EPF; frame->pf = skb->data[1] & LAPB_EPF;
frame->control[0] = skb->data[0]; frame->control[0] = skb->data[0];
frame->control[1] = skb->data[1]; frame->control[1] = skb->data[1];
skb_pull(skb, 2); skb_pull(skb, 2);
} else if ((skb->data[0] & LAPB_U) == 1) { /* S frame - take out PF/NR */ } else if ((skb->data[0] & LAPB_U) == 1) {
/*
* S frame - take out PF/NR
*/
frame->type = skb->data[0] & 0x0F; frame->type = skb->data[0] & 0x0F;
frame->nr = (skb->data[1] >> 1) & 0x7F; frame->nr = (skb->data[1] >> 1) & 0x7F;
frame->pf = skb->data[1] & LAPB_EPF; frame->pf = skb->data[1] & LAPB_EPF;
frame->control[0] = skb->data[0]; frame->control[0] = skb->data[0];
frame->control[1] = skb->data[1]; frame->control[1] = skb->data[1];
skb_pull(skb, 2); skb_pull(skb, 2);
} else if ((skb->data[0] & LAPB_U) == 3) { /* U frame - take out PF */ } else if ((skb->data[0] & LAPB_U) == 3) {
/*
* U frame - take out PF
*/
frame->type = skb->data[0] & ~LAPB_SPF; frame->type = skb->data[0] & ~LAPB_SPF;
frame->pf = skb->data[0] & LAPB_SPF; frame->pf = skb->data[0] & LAPB_SPF;
frame->control[0] = skb->data[0]; frame->control[0] = skb->data[0];
...@@ -169,16 +179,25 @@ void lapb_decode(lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame) ...@@ -169,16 +179,25 @@ void lapb_decode(lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame)
skb_pull(skb, 1); skb_pull(skb, 1);
} }
} else { } else {
if ((skb->data[0] & LAPB_S) == 0) { if (!(skb->data[0] & LAPB_S)) {
frame->type = LAPB_I; /* I frame - carries NR/NS/PF */ /*
* I frame - carries NR/NS/PF
*/
frame->type = LAPB_I;
frame->ns = (skb->data[0] >> 1) & 0x07; frame->ns = (skb->data[0] >> 1) & 0x07;
frame->nr = (skb->data[0] >> 5) & 0x07; frame->nr = (skb->data[0] >> 5) & 0x07;
frame->pf = skb->data[0] & LAPB_SPF; frame->pf = skb->data[0] & LAPB_SPF;
} else if ((skb->data[0] & LAPB_U) == 1) { /* S frame - take out PF/NR */ } else if ((skb->data[0] & LAPB_U) == 1) {
/*
* S frame - take out PF/NR
*/
frame->type = skb->data[0] & 0x0F; frame->type = skb->data[0] & 0x0F;
frame->nr = (skb->data[0] >> 5) & 0x07; frame->nr = (skb->data[0] >> 5) & 0x07;
frame->pf = skb->data[0] & LAPB_SPF; frame->pf = skb->data[0] & LAPB_SPF;
} else if ((skb->data[0] & LAPB_U) == 3) { /* U frame - take out PF */ } else if ((skb->data[0] & LAPB_U) == 3) {
/*
* U frame - take out PF
*/
frame->type = skb->data[0] & ~LAPB_SPF; frame->type = skb->data[0] & ~LAPB_SPF;
frame->pf = skb->data[0] & LAPB_SPF; frame->pf = skb->data[0] & LAPB_SPF;
} }
...@@ -195,7 +214,8 @@ void lapb_decode(lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame) ...@@ -195,7 +214,8 @@ void lapb_decode(lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame)
* Only supervisory or unnumbered frames are processed, FRMRs are handled * Only supervisory or unnumbered frames are processed, FRMRs are handled
* by lapb_transmit_frmr below. * by lapb_transmit_frmr below.
*/ */
void lapb_send_control(lapb_cb *lapb, int frametype, int poll_bit, int type) void lapb_send_control(struct lapb_cb *lapb, int frametype,
int poll_bit, int type)
{ {
struct sk_buff *skb; struct sk_buff *skb;
unsigned char *dptr; unsigned char *dptr;
...@@ -209,18 +229,18 @@ void lapb_send_control(lapb_cb *lapb, int frametype, int poll_bit, int type) ...@@ -209,18 +229,18 @@ void lapb_send_control(lapb_cb *lapb, int frametype, int poll_bit, int type)
if ((frametype & LAPB_U) == LAPB_U) { if ((frametype & LAPB_U) == LAPB_U) {
dptr = skb_put(skb, 1); dptr = skb_put(skb, 1);
*dptr = frametype; *dptr = frametype;
*dptr |= (poll_bit) ? LAPB_SPF : 0; *dptr |= poll_bit ? LAPB_SPF : 0;
} else { } else {
dptr = skb_put(skb, 2); dptr = skb_put(skb, 2);
dptr[0] = frametype; dptr[0] = frametype;
dptr[1] = (lapb->vr << 1); dptr[1] = (lapb->vr << 1);
dptr[1] |= (poll_bit) ? LAPB_EPF : 0; dptr[1] |= poll_bit ? LAPB_EPF : 0;
} }
} else { } else {
dptr = skb_put(skb, 1); dptr = skb_put(skb, 1);
*dptr = frametype; *dptr = frametype;
*dptr |= (poll_bit) ? LAPB_SPF : 0; *dptr |= poll_bit ? LAPB_SPF : 0;
if ((frametype & LAPB_U) == LAPB_S) /* S frames carry NR */ if ((frametype & LAPB_U) == LAPB_S) /* S frames carry NR */
*dptr |= (lapb->vr << 5); *dptr |= (lapb->vr << 5);
} }
...@@ -231,7 +251,7 @@ void lapb_send_control(lapb_cb *lapb, int frametype, int poll_bit, int type) ...@@ -231,7 +251,7 @@ void lapb_send_control(lapb_cb *lapb, int frametype, int poll_bit, int type)
* This routine generates FRMRs based on information previously stored in * This routine generates FRMRs based on information previously stored in
* the LAPB control block. * the LAPB control block.
*/ */
void lapb_transmit_frmr(lapb_cb *lapb) void lapb_transmit_frmr(struct lapb_cb *lapb)
{ {
struct sk_buff *skb; struct sk_buff *skb;
unsigned char *dptr; unsigned char *dptr;
...@@ -254,7 +274,10 @@ void lapb_transmit_frmr(lapb_cb *lapb) ...@@ -254,7 +274,10 @@ void lapb_transmit_frmr(lapb_cb *lapb)
*dptr++ = lapb->frmr_type; *dptr++ = lapb->frmr_type;
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S%d TX FRMR %02X %02X %02X %02X %02X\n", lapb->token, lapb->state, skb->data[1], skb->data[2], skb->data[3], skb->data[4], skb->data[5]); printk(KERN_DEBUG "lapb: (%p) S%d TX FRMR %02X %02X %02X %02X %02X\n",
lapb->token, lapb->state,
skb->data[1], skb->data[2], skb->data[3],
skb->data[4], skb->data[5]);
#endif #endif
} else { } else {
dptr = skb_put(skb, 4); dptr = skb_put(skb, 4);
...@@ -268,7 +291,9 @@ void lapb_transmit_frmr(lapb_cb *lapb) ...@@ -268,7 +291,9 @@ void lapb_transmit_frmr(lapb_cb *lapb)
*dptr++ = lapb->frmr_type; *dptr++ = lapb->frmr_type;
#if LAPB_DEBUG > 1 #if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S%d TX FRMR %02X %02X %02X\n", lapb->token, lapb->state, skb->data[1], skb->data[2], skb->data[3]); printk(KERN_DEBUG "lapb: (%p) S%d TX FRMR %02X %02X %02X\n",
lapb->token, lapb->state, skb->data[1],
skb->data[2], skb->data[3]);
#endif #endif
} }
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
static void lapb_t1timer_expiry(unsigned long); static void lapb_t1timer_expiry(unsigned long);
static void lapb_t2timer_expiry(unsigned long); static void lapb_t2timer_expiry(unsigned long);
void lapb_start_t1timer(lapb_cb *lapb) void lapb_start_t1timer(struct lapb_cb *lapb)
{ {
del_timer(&lapb->t1timer); del_timer(&lapb->t1timer);
...@@ -48,7 +48,7 @@ void lapb_start_t1timer(lapb_cb *lapb) ...@@ -48,7 +48,7 @@ void lapb_start_t1timer(lapb_cb *lapb)
add_timer(&lapb->t1timer); add_timer(&lapb->t1timer);
} }
void lapb_start_t2timer(lapb_cb *lapb) void lapb_start_t2timer(struct lapb_cb *lapb)
{ {
del_timer(&lapb->t2timer); del_timer(&lapb->t2timer);
...@@ -59,24 +59,24 @@ void lapb_start_t2timer(lapb_cb *lapb) ...@@ -59,24 +59,24 @@ void lapb_start_t2timer(lapb_cb *lapb)
add_timer(&lapb->t2timer); add_timer(&lapb->t2timer);
} }
void lapb_stop_t1timer(lapb_cb *lapb) void lapb_stop_t1timer(struct lapb_cb *lapb)
{ {
del_timer(&lapb->t1timer); del_timer(&lapb->t1timer);
} }
void lapb_stop_t2timer(lapb_cb *lapb) void lapb_stop_t2timer(struct lapb_cb *lapb)
{ {
del_timer(&lapb->t2timer); del_timer(&lapb->t2timer);
} }
int lapb_t1timer_running(lapb_cb *lapb) int lapb_t1timer_running(struct lapb_cb *lapb)
{ {
return timer_pending(&lapb->t1timer); return timer_pending(&lapb->t1timer);
} }
static void lapb_t2timer_expiry(unsigned long param) static void lapb_t2timer_expiry(unsigned long param)
{ {
lapb_cb *lapb = (lapb_cb *)param; struct lapb_cb *lapb = (struct lapb_cb *)param;
if (lapb->condition & LAPB_ACK_PENDING_CONDITION) { if (lapb->condition & LAPB_ACK_PENDING_CONDITION) {
lapb->condition &= ~LAPB_ACK_PENDING_CONDITION; lapb->condition &= ~LAPB_ACK_PENDING_CONDITION;
...@@ -86,7 +86,7 @@ static void lapb_t2timer_expiry(unsigned long param) ...@@ -86,7 +86,7 @@ static void lapb_t2timer_expiry(unsigned long param)
static void lapb_t1timer_expiry(unsigned long param) static void lapb_t1timer_expiry(unsigned long param)
{ {
lapb_cb *lapb = (lapb_cb *)param; struct lapb_cb *lapb = (struct lapb_cb *)param;
switch (lapb->state) { switch (lapb->state) {
......
/* /*
* X.25 Packet Layer release 002 * X.25 Packet Layer release 002
* *
* This is ALPHA test software. This code may break your machine, randomly fail to work with new * This is ALPHA test software. This code may break your machine,
* releases, misbehave and/or generally screw up. It might even work. * randomly fail to work with new releases, misbehave and/or generally
* screw up. It might even work.
* *
* This code REQUIRES 2.1.15 or higher * This code REQUIRES 2.1.15 or higher
* *
...@@ -64,13 +65,15 @@ int sysctl_x25_reset_request_timeout = X25_DEFAULT_T22; ...@@ -64,13 +65,15 @@ int sysctl_x25_reset_request_timeout = X25_DEFAULT_T22;
int sysctl_x25_clear_request_timeout = X25_DEFAULT_T23; int sysctl_x25_clear_request_timeout = X25_DEFAULT_T23;
int sysctl_x25_ack_holdback_timeout = X25_DEFAULT_T2; int sysctl_x25_ack_holdback_timeout = X25_DEFAULT_T2;
static struct sock *volatile x25_list /* = NULL initially */; static struct sock *x25_list;
static rwlock_t x25_list_lock = RW_LOCK_UNLOCKED;
static struct proto_ops x25_proto_ops; static struct proto_ops x25_proto_ops;
static x25_address null_x25_address = {" "}; static struct x25_address null_x25_address = {" "};
int x25_addr_ntoa(unsigned char *p, x25_address *called_addr, x25_address *calling_addr) int x25_addr_ntoa(unsigned char *p, struct x25_address *called_addr,
struct x25_address *calling_addr)
{ {
int called_len, calling_len; int called_len, calling_len;
char *called, *calling; char *called, *calling;
...@@ -101,13 +104,13 @@ int x25_addr_ntoa(unsigned char *p, x25_address *called_addr, x25_address *calli ...@@ -101,13 +104,13 @@ int x25_addr_ntoa(unsigned char *p, x25_address *called_addr, x25_address *calli
} }
} }
*called = '\0'; *called = *calling = '\0';
*calling = '\0';
return 1 + (called_len + calling_len + 1) / 2; return 1 + (called_len + calling_len + 1) / 2;
} }
int x25_addr_aton(unsigned char *p, x25_address *called_addr, x25_address *calling_addr) int x25_addr_aton(unsigned char *p, struct x25_address *called_addr,
struct x25_address *calling_addr)
{ {
unsigned int called_len, calling_len; unsigned int called_len, calling_len;
char *called, *calling; char *called, *calling;
...@@ -150,28 +153,22 @@ int x25_addr_aton(unsigned char *p, x25_address *called_addr, x25_address *calli ...@@ -150,28 +153,22 @@ int x25_addr_aton(unsigned char *p, x25_address *called_addr, x25_address *calli
static void x25_remove_socket(struct sock *sk) static void x25_remove_socket(struct sock *sk)
{ {
struct sock *s; struct sock *s;
unsigned long flags;
save_flags(flags); write_lock_bh(&x25_list_lock);
cli();
if ((s = x25_list) == sk) { if ((s = x25_list) == sk)
x25_list = s->next; x25_list = s->next;
restore_flags(flags); else while (s && s->next) {
return;
}
while (s != NULL && s->next != NULL) {
if (s->next == sk) { if (s->next == sk) {
s->next = sk->next; s->next = sk->next;
restore_flags(flags); sock_put(sk);
return; break;
} }
s = s->next; s = s->next;
} }
restore_flags(flags); write_unlock_bh(&x25_list_lock);
} }
/* /*
...@@ -181,18 +178,23 @@ static void x25_kill_by_device(struct net_device *dev) ...@@ -181,18 +178,23 @@ static void x25_kill_by_device(struct net_device *dev)
{ {
struct sock *s; struct sock *s;
for (s = x25_list; s != NULL; s = s->next) write_lock_bh(&x25_list_lock);
for (s = x25_list; s; s = s->next)
if (x25_sk(s)->neighbour && x25_sk(s)->neighbour->dev == dev) if (x25_sk(s)->neighbour && x25_sk(s)->neighbour->dev == dev)
x25_disconnect(s, ENETUNREACH, 0, 0); x25_disconnect(s, ENETUNREACH, 0, 0);
write_unlock_bh(&x25_list_lock);
} }
/* /*
* Handle device status changes. * Handle device status changes.
*/ */
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 = (struct net_device *)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)
...@@ -204,8 +206,11 @@ static int x25_device_event(struct notifier_block *this, unsigned long event, vo ...@@ -204,8 +206,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);
...@@ -223,76 +228,79 @@ static int x25_device_event(struct notifier_block *this, unsigned long event, vo ...@@ -223,76 +228,79 @@ static int x25_device_event(struct notifier_block *this, unsigned long event, vo
*/ */
static void x25_insert_socket(struct sock *sk) static void x25_insert_socket(struct sock *sk)
{ {
unsigned long flags; write_lock_bh(&x25_list_lock);
save_flags(flags);
cli();
sk->next = x25_list; sk->next = x25_list;
x25_list = sk; x25_list = sk;
sock_hold(sk);
restore_flags(flags); write_unlock_bh(&x25_list_lock);
} }
/* /*
* Find a socket that wants to accept the Call Request we just * Find a socket that wants to accept the Call Request we just
* received. * received.
*/ */
static struct sock *x25_find_listener(x25_address *addr) static struct sock *x25_find_listener(struct x25_address *addr)
{ {
unsigned long flags;
struct sock *s; struct sock *s;
save_flags(flags); read_lock_bh(&x25_list_lock);
cli();
for (s = x25_list; s != NULL; s = s->next) { for (s = x25_list; s; s = s->next)
if ((!strcmp(addr->x25_addr, x25_sk(s)->source_addr.x25_addr) || if ((!strcmp(addr->x25_addr, x25_sk(s)->source_addr.x25_addr) ||
strcmp(addr->x25_addr, null_x25_address.x25_addr) == 0) && !strcmp(addr->x25_addr, null_x25_address.x25_addr)) &&
s->state == TCP_LISTEN) { s->state == TCP_LISTEN)
restore_flags(flags); break;
return s;
}
}
restore_flags(flags); if (s)
return NULL; sock_hold(s);
read_unlock_bh(&x25_list_lock);
return s;
} }
/* /*
* 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;
save_flags(flags); for (s = x25_list; s; s = s->next)
cli(); if (x25_sk(s)->lci == lci && x25_sk(s)->neighbour == nb)
break;
if (s)
sock_hold(s);
return s;
}
for (s = x25_list; s != NULL; s = s->next) { struct sock *x25_find_socket(unsigned int lci, struct x25_neigh *nb)
if (x25_sk(s)->lci == lci && x25_sk(s)->neighbour == neigh) { {
restore_flags(flags); struct sock *s;
return s;
}
}
restore_flags(flags); read_lock_bh(&x25_list_lock);
return NULL; s = __x25_find_socket(lci, nb);
read_unlock_bh(&x25_list_lock);
return s;
} }
/* /*
* 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;
struct sock *sk;
while (x25_find_socket(lci, neigh) != NULL) { read_lock_bh(&x25_list_lock);
lci++;
if (lci == 4096) return 0; while ((sk = __x25_find_socket(lci, nb)) != NULL) {
sock_put(sk);
if (++lci == 4096) {
lci = 0;
break;
}
} }
read_unlock_bh(&x25_list_lock);
return lci; return lci;
} }
...@@ -318,11 +326,9 @@ static void x25_destroy_timer(unsigned long data) ...@@ -318,11 +326,9 @@ static void x25_destroy_timer(unsigned long data)
void x25_destroy_socket(struct sock *sk) /* Not static as it's used by the timer */ void x25_destroy_socket(struct sock *sk) /* Not static as it's used by the timer */
{ {
struct sk_buff *skb; struct sk_buff *skb;
unsigned long flags;
save_flags(flags);
cli();
sock_hold(sk);
lock_sock(sk);
x25_stop_heartbeat(sk); x25_stop_heartbeat(sk);
x25_stop_timer(sk); x25_stop_timer(sk);
...@@ -339,7 +345,7 @@ void x25_destroy_socket(struct sock *sk) /* Not static as it's used by the timer ...@@ -339,7 +345,7 @@ void x25_destroy_socket(struct sock *sk) /* Not static as it's used by the timer
kfree_skb(skb); kfree_skb(skb);
} }
if (atomic_read(&sk->wmem_alloc) != 0 || atomic_read(&sk->rmem_alloc) != 0) { if (atomic_read(&sk->wmem_alloc) || atomic_read(&sk->rmem_alloc)) {
/* Defer: outstanding buffers */ /* Defer: outstanding buffers */
init_timer(&sk->timer); init_timer(&sk->timer);
sk->timer.expires = jiffies + 10 * HZ; sk->timer.expires = jiffies + 10 * HZ;
...@@ -350,8 +356,8 @@ void x25_destroy_socket(struct sock *sk) /* Not static as it's used by the timer ...@@ -350,8 +356,8 @@ void x25_destroy_socket(struct sock *sk) /* Not static as it's used by the timer
sk_free(sk); sk_free(sk);
MOD_DEC_USE_COUNT; MOD_DEC_USE_COUNT;
} }
release_sock(sk);
restore_flags(flags); sock_put(sk);
} }
/* /*
...@@ -360,81 +366,77 @@ void x25_destroy_socket(struct sock *sk) /* Not static as it's used by the timer ...@@ -360,81 +366,77 @@ void x25_destroy_socket(struct sock *sk) /* Not static as it's used by the timer
*/ */
static int x25_setsockopt(struct socket *sock, int level, int optname, static int x25_setsockopt(struct socket *sock, int level, int optname,
char *optval, int optlen) char *optval, int optlen)
{ {
struct sock *sk = sock->sk;
int opt; int opt;
struct sock *sk = sock->sk;
int rc = -ENOPROTOOPT;
if (level != SOL_X25) if (level != SOL_X25 || optname != X25_QBITINCL)
return -ENOPROTOOPT; goto out;
rc = -EINVAL;
if (optlen < sizeof(int)) if (optlen < sizeof(int))
return-EINVAL; goto out;
rc = -EFAULT;
if (get_user(opt, (int *)optval)) if (get_user(opt, (int *)optval))
return -EFAULT; goto out;
switch (optname) {
case X25_QBITINCL:
x25_sk(sk)->qbitincl = opt ? 1 : 0;
return 0;
default: x25_sk(sk)->qbitincl = !!opt;
return -ENOPROTOOPT; rc = 0;
} out:
return rc;
} }
static int x25_getsockopt(struct socket *sock, int level, int optname, static int x25_getsockopt(struct socket *sock, int level, int optname,
char *optval, int *optlen) char *optval, int *optlen)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
int val = 0; int val, len, rc = -ENOPROTOOPT;
int len;
if (level != SOL_X25) if (level != SOL_X25 || optname != X25_QBITINCL)
return -ENOPROTOOPT; goto out;
rc = -EFAULT;
if (get_user(len, optlen)) if (get_user(len, optlen))
return -EFAULT; goto out;
switch (optname) {
case X25_QBITINCL:
val = x25_sk(sk)->qbitincl;
break;
default:
return -ENOPROTOOPT;
}
len = min_t(unsigned int, len, sizeof(int)); len = min_t(unsigned int, len, sizeof(int));
rc = -EINVAL;
if (len < 0) if (len < 0)
return -EINVAL; goto out;
rc = -EFAULT;
if (put_user(len, optlen)) if (put_user(len, optlen))
return -EFAULT; goto out;
return copy_to_user(optval, &val, len) ? -EFAULT : 0; val = x25_sk(sk)->qbitincl;
rc = copy_to_user(optval, &val, len) ? -EFAULT : 0;
out:
return rc;
} }
static int x25_listen(struct socket *sock, int backlog) static int x25_listen(struct socket *sock, int backlog)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
int rc = -EOPNOTSUPP;
if (sk->state != TCP_LISTEN) { if (sk->state != TCP_LISTEN) {
memset(&x25_sk(sk)->dest_addr, 0, X25_ADDR_LEN); memset(&x25_sk(sk)->dest_addr, 0, X25_ADDR_LEN);
sk->max_ack_backlog = backlog; sk->max_ack_backlog = backlog;
sk->state = TCP_LISTEN; sk->state = TCP_LISTEN;
return 0; rc = 0;
} }
return -EOPNOTSUPP; return rc;
} }
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;
...@@ -445,7 +447,7 @@ static struct sock *x25_alloc_socket(void) ...@@ -445,7 +447,7 @@ static struct sock *x25_alloc_socket(void)
if (!x25) if (!x25)
goto frees; goto frees;
memset(x25, 0x00, sizeof(*x25)); memset(x25, 0, sizeof(*x25));
x25->sk = sk; x25->sk = sk;
...@@ -455,23 +457,28 @@ static struct sock *x25_alloc_socket(void) ...@@ -455,23 +457,28 @@ static struct sock *x25_alloc_socket(void)
skb_queue_head_init(&x25->fragment_queue); skb_queue_head_init(&x25->fragment_queue);
skb_queue_head_init(&x25->interrupt_in_queue); skb_queue_head_init(&x25->interrupt_in_queue);
skb_queue_head_init(&x25->interrupt_out_queue); skb_queue_head_init(&x25->interrupt_out_queue);
out: return sk; out:
frees: sk_free(sk); return sk;
frees:
sk_free(sk);
sk = NULL; sk = NULL;
decmod: MOD_DEC_USE_COUNT; decmod:
MOD_DEC_USE_COUNT;
goto out; goto out;
} }
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;
if (sock->type != SOCK_SEQPACKET || protocol != 0) if (sock->type != SOCK_SEQPACKET || protocol)
return -ESOCKTNOSUPPORT; goto out;
rc = -ENOMEM;
if ((sk = x25_alloc_socket()) == NULL) if ((sk = x25_alloc_socket()) == NULL)
return -ENOMEM; goto out;
x25 = x25_sk(sk); x25 = x25_sk(sk);
...@@ -495,20 +502,21 @@ static int x25_create(struct socket *sock, int protocol) ...@@ -495,20 +502,21 @@ static int x25_create(struct socket *sock, int protocol)
x25->facilities.pacsize_out = X25_DEFAULT_PACKET_SIZE; x25->facilities.pacsize_out = X25_DEFAULT_PACKET_SIZE;
x25->facilities.throughput = X25_DEFAULT_THROUGHPUT; x25->facilities.throughput = X25_DEFAULT_THROUGHPUT;
x25->facilities.reverse = X25_DEFAULT_REVERSE; x25->facilities.reverse = X25_DEFAULT_REVERSE;
rc = 0;
return 0; out:
return rc;
} }
static struct sock *x25_make_new(struct sock *osk) static struct sock *x25_make_new(struct sock *osk)
{ {
struct sock *sk; struct sock *sk = NULL;
x25_cb *x25, *ox25; struct x25_opt *x25, *ox25;
if (osk->type != SOCK_SEQPACKET) if (osk->type != SOCK_SEQPACKET)
return NULL; goto out;
if ((sk = x25_alloc_socket()) == NULL) if ((sk = x25_alloc_socket()) == NULL)
return NULL; goto out;
x25 = x25_sk(sk); x25 = x25_sk(sk);
...@@ -533,16 +541,17 @@ static struct sock *x25_make_new(struct sock *osk) ...@@ -533,16 +541,17 @@ static struct sock *x25_make_new(struct sock *osk)
x25->qbitincl = ox25->qbitincl; x25->qbitincl = ox25->qbitincl;
init_timer(&x25->timer); init_timer(&x25->timer);
out:
return sk; return sk;
} }
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 == NULL) return 0; if (!sk)
goto out;
x25 = x25_sk(sk); x25 = x25_sk(sk);
...@@ -567,14 +576,11 @@ static int x25_release(struct socket *sock) ...@@ -567,14 +576,11 @@ static int x25_release(struct socket *sock)
sk->dead = 1; sk->dead = 1;
sk->destroy = 1; sk->destroy = 1;
break; break;
default:
break;
} }
sock->sk = NULL; sock->sk = NULL;
sk->socket = NULL; /* Not used, but we should do this */ sk->socket = NULL; /* Not used, but we should do this */
out:
return 0; return 0;
} }
...@@ -583,68 +589,98 @@ static int x25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) ...@@ -583,68 +589,98 @@ static int x25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr; struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr;
if (sk->zapped == 0) if (!sk->zapped ||
return -EINVAL; addr_len != sizeof(struct sockaddr_x25) ||
addr->sx25_family != AF_X25)
if (addr_len != sizeof(struct sockaddr_x25))
return -EINVAL;
if (addr->sx25_family != AF_X25)
return -EINVAL; return -EINVAL;
x25_sk(sk)->source_addr = addr->sx25_addr; x25_sk(sk)->source_addr = addr->sx25_addr;
x25_insert_socket(sk); x25_insert_socket(sk);
sk->zapped = 0; sk->zapped = 0;
SOCK_DEBUG(sk, "x25_bind: socket is bound\n"); SOCK_DEBUG(sk, "x25_bind: socket is bound\n");
return 0; return 0;
} }
static int x25_wait_for_connection_establishment(struct sock *sk)
{
DECLARE_WAITQUEUE(wait, current);
int rc;
add_wait_queue_exclusive(sk->sleep, &wait);
for (;;) {
__set_current_state(TASK_INTERRUPTIBLE);
rc = -ERESTARTSYS;
if (signal_pending(current))
break;
rc = sock_error(sk);
if (rc) {
sk->socket->state = SS_UNCONNECTED;
break;
}
rc = 0;
if (sk->state != TCP_ESTABLISHED) {
release_sock(sk);
schedule();
lock_sock(sk);
} else
break;
}
__set_current_state(TASK_RUNNING);
remove_wait_queue(sk->sleep, &wait);
return rc;
}
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;
lock_sock(sk);
if (sk->state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) { if (sk->state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) {
sock->state = SS_CONNECTED; sock->state = SS_CONNECTED;
return 0; /* Connect completed during a ERESTARTSYS event */ goto out; /* Connect completed during a ERESTARTSYS event */
} }
rc = -ECONNREFUSED;
if (sk->state == TCP_CLOSE && sock->state == SS_CONNECTING) { if (sk->state == TCP_CLOSE && sock->state == SS_CONNECTING) {
sock->state = SS_UNCONNECTED; sock->state = SS_UNCONNECTED;
return -ECONNREFUSED; goto out;
} }
rc = -EISCONN; /* No reconnect on a seqpacket socket */
if (sk->state == TCP_ESTABLISHED) if (sk->state == TCP_ESTABLISHED)
return -EISCONN; /* No reconnect on a seqpacket socket */ goto out;
sk->state = TCP_CLOSE; sk->state = TCP_CLOSE;
sock->state = SS_UNCONNECTED; sock->state = SS_UNCONNECTED;
if (addr_len != sizeof(struct sockaddr_x25)) rc = -EINVAL;
return -EINVAL; if (addr_len != sizeof(struct sockaddr_x25) ||
addr->sx25_family != AF_X25)
if (addr->sx25_family != AF_X25) goto out;
return -EINVAL;
if ((dev = x25_get_route(&addr->sx25_addr)) == NULL) rc = -ENETUNREACH;
return -ENETUNREACH; rt = x25_get_route(&addr->sx25_addr);
if (!rt)
goto out;
if ((x25->neighbour = x25_get_neigh(dev)) == NULL) x25->neighbour = x25_get_neigh(rt->dev);
return -ENETUNREACH; if (!x25->neighbour)
goto out_put_route;
x25_limit_facilities(&x25->facilities, x25->neighbour); x25_limit_facilities(&x25->facilities, x25->neighbour);
if ((x25->lci = x25_new_lci(x25->neighbour)) == 0) x25->lci = x25_new_lci(x25->neighbour);
return -ENETUNREACH; if (!x25->lci)
goto out_put_neigh;
rc = -EINVAL;
if (sk->zapped) /* Must bind first - autobinding does not work */ if (sk->zapped) /* Must bind first - autobinding does not work */
return -EINVAL; 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);
...@@ -663,113 +699,119 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len ...@@ -663,113 +699,119 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len
x25_start_t21timer(sk); x25_start_t21timer(sk);
/* Now the loop */ /* Now the loop */
rc = -EINPROGRESS;
if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
return -EINPROGRESS; goto out_put_neigh;
cli(); /* To avoid races on the sleep */
/* rc = x25_wait_for_connection_establishment(sk);
* A Clear Request or timeout or failed routing will go to closed. if (rc)
*/ goto out_put_neigh;
while (sk->state == TCP_SYN_SENT) {
interruptible_sleep_on(sk->sleep);
if (signal_pending(current)) {
sti();
return -ERESTARTSYS;
}
}
if (sk->state != TCP_ESTABLISHED) {
sti();
sock->state = SS_UNCONNECTED;
return sock_error(sk); /* Always set at this point */
}
sock->state = SS_CONNECTED; sock->state = SS_CONNECTED;
rc = 0;
out_put_neigh:
if (rc)
x25_neigh_put(x25->neighbour);
out_put_route:
x25_route_put(rt);
out:
release_sock(sk);
return rc;
}
sti(); static int x25_wait_for_data(struct sock *sk, int timeout)
{
DECLARE_WAITQUEUE(wait, current);
int rc = 0;
return 0; add_wait_queue_exclusive(sk->sleep, &wait);
for (;;) {
__set_current_state(TASK_INTERRUPTIBLE);
if (sk->shutdown & RCV_SHUTDOWN)
break;
rc = -ERESTARTSYS;
if (signal_pending(current))
break;
rc = -EAGAIN;
if (!timeout)
break;
rc = 0;
if (skb_queue_empty(&sk->receive_queue)) {
release_sock(sk);
timeout = schedule_timeout(timeout);
lock_sock(sk);
} else
break;
}
__set_current_state(TASK_RUNNING);
remove_wait_queue(sk->sleep, &wait);
return rc;
} }
static int x25_accept(struct socket *sock, struct socket *newsock, int flags) static int x25_accept(struct socket *sock, struct socket *newsock, int flags)
{ {
struct sock *sk; struct sock *sk = sock->sk;
struct sock *newsk; struct sock *newsk;
struct sk_buff *skb; struct sk_buff *skb;
int rc = -EINVAL;
if ((sk = sock->sk) == NULL) if (!sk || sk->state != TCP_LISTEN)
return -EINVAL; goto out;
rc = -EOPNOTSUPP;
if (sk->type != SOCK_SEQPACKET) if (sk->type != SOCK_SEQPACKET)
return -EOPNOTSUPP; goto out;
if (sk->state != TCP_LISTEN) rc = x25_wait_for_data(sk, sk->rcvtimeo);
return -EINVAL; if (rc)
goto out;
/* skb = skb_dequeue(&sk->receive_queue);
* The write queue this time is holding sockets ready to use rc = -EINVAL;
* hooked into the CALL INDICATION we saved if (!skb->sk)
*/ goto out;
do { newsk = skb->sk;
cli(); newsk->pair = NULL;
if ((skb = skb_dequeue(&sk->receive_queue)) == NULL) {
if (flags & O_NONBLOCK) {
sti();
return -EWOULDBLOCK;
}
interruptible_sleep_on(sk->sleep);
if (signal_pending(current)) {
sti();
return -ERESTARTSYS;
}
}
} while (skb == NULL);
newsk = skb->sk;
newsk->pair = NULL;
newsk->socket = newsock; newsk->socket = newsock;
newsk->sleep = &newsock->wait; newsk->sleep = &newsock->wait;
sti();
/* Now attach up the new socket */ /* Now attach up the new socket */
skb->sk = NULL; skb->sk = NULL;
kfree_skb(skb); kfree_skb(skb);
sk->ack_backlog--; sk->ack_backlog--;
newsock->sk = newsk; newsock->sk = newsk;
newsock->state = SS_CONNECTED; newsock->state = SS_CONNECTED;
rc = 0;
return 0; out:
return rc;
} }
static int x25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer) static int x25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer)
{ {
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 != 0) { if (peer) {
if (sk->state != TCP_ESTABLISHED) if (sk->state != TCP_ESTABLISHED)
return -ENOTCONN; return -ENOTCONN;
sx25->sx25_addr = x25->dest_addr; sx25->sx25_addr = x25->dest_addr;
} else { } else
sx25->sx25_addr = x25->source_addr; sx25->sx25_addr = x25->source_addr;
}
sx25->sx25_family = AF_X25; sx25->sx25_family = AF_X25;
*uaddr_len = sizeof(struct sockaddr_x25); *uaddr_len = sizeof(*sx25);
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;
x25_cb *makex25; struct x25_opt *makex25;
x25_address source_addr, dest_addr; struct x25_address source_addr, dest_addr;
struct x25_facilities facilities; struct x25_facilities facilities;
int len; int len, rc;
/* /*
* Remove the LCI and frame type. * Remove the LCI and frame type.
...@@ -790,33 +832,28 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned i ...@@ -790,33 +832,28 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned i
/* /*
* We can't accept the Call Request. * We can't accept the Call Request.
*/ */
if (sk == NULL || sk->ack_backlog == sk->max_ack_backlog) { if (!sk || sk->ack_backlog == sk->max_ack_backlog)
x25_transmit_clear_request(neigh, lci, 0x01); goto out_clear_request;
return 0;
}
/* /*
* Try to reach a compromise on the requested facilities. * Try to reach a compromise on the requested facilities.
*/ */
if ((len = x25_negotiate_facilities(skb, sk, &facilities)) == -1) { if ((len = x25_negotiate_facilities(skb, sk, &facilities)) == -1)
x25_transmit_clear_request(neigh, lci, 0x01); goto out_sock_put;
return 0;
}
/* /*
* current neighbour/link might impose additional limits * current neighbour/link might impose additional limits
* 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.
*/ */
if ((make = x25_make_new(sk)) == NULL) { make = x25_make_new(sk);
x25_transmit_clear_request(neigh, lci, 0x01); if (!make)
return 0; goto out_sock_put;
}
/* /*
* Remove the facilities, leaving any Call User Data. * Remove the facilities, leaving any Call User Data.
...@@ -830,7 +867,7 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned i ...@@ -830,7 +867,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;
...@@ -857,55 +894,70 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned i ...@@ -857,55 +894,70 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned i
if (!sk->dead) if (!sk->dead)
sk->data_ready(sk, skb->len); sk->data_ready(sk, skb->len);
rc = 1;
return 1; sock_put(sk);
out:
return rc;
out_sock_put:
sock_put(sk);
out_clear_request:
rc = 0;
x25_transmit_clear_request(nb, lci, 0x01);
goto out;
} }
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;
int err;
struct sockaddr_x25 sx25; struct sockaddr_x25 sx25;
struct sk_buff *skb; struct sk_buff *skb;
unsigned char *asmptr; unsigned char *asmptr;
int size, qbit = 0; int noblock = msg->msg_flags & MSG_DONTWAIT;
int size, qbit = 0, rc = -EINVAL;
if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_OOB | MSG_EOR)) if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_OOB | MSG_EOR))
return -EINVAL; goto out;
/* we currently don't support segmented records at the user interface */ /* we currently don't support segmented records at the user interface */
if (!(msg->msg_flags & (MSG_EOR|MSG_OOB))) if (!(msg->msg_flags & (MSG_EOR|MSG_OOB)))
return -EINVAL; goto out;
rc = -EADDRNOTAVAIL;
if (sk->zapped) if (sk->zapped)
return -EADDRNOTAVAIL; goto out;
rc = -EPIPE;
if (sk->shutdown & SEND_SHUTDOWN) { if (sk->shutdown & SEND_SHUTDOWN) {
send_sig(SIGPIPE, current, 0); send_sig(SIGPIPE, current, 0);
return -EPIPE; goto out;
} }
if (x25->neighbour == NULL) rc = -ENETUNREACH;
return -ENETUNREACH; if (!x25->neighbour)
goto out;
if (usx25 != NULL) { if (usx25) {
rc = -EINVAL;
if (msg->msg_namelen < sizeof(sx25)) if (msg->msg_namelen < sizeof(sx25))
return -EINVAL; goto out;
sx25 = *usx25; memcpy(&sx25, usx25, sizeof(sx25));
rc = -EISCONN;
if (strcmp(x25->dest_addr.x25_addr, sx25.sx25_addr.x25_addr)) if (strcmp(x25->dest_addr.x25_addr, sx25.sx25_addr.x25_addr))
return -EISCONN; goto out;
rc = -EINVAL;
if (sx25.sx25_family != AF_X25) if (sx25.sx25_family != AF_X25)
return -EINVAL; goto out;
} else { } else {
/* /*
* FIXME 1003.1g - if the socket is like this because * FIXME 1003.1g - if the socket is like this because
* it has become closed (not started closed) we ought * it has become closed (not started closed) we ought
* to SIGPIPE, EPIPE; * to SIGPIPE, EPIPE;
*/ */
rc = -ENOTCONN;
if (sk->state != TCP_ESTABLISHED) if (sk->state != TCP_ESTABLISHED)
return -ENOTCONN; goto out;
sx25.sx25_family = AF_X25; sx25.sx25_family = AF_X25;
sx25.sx25_addr = x25->dest_addr; sx25.sx25_addr = x25->dest_addr;
...@@ -921,8 +973,9 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct ...@@ -921,8 +973,9 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
size = len + X25_MAX_L2_LEN + X25_EXT_MIN_LEN; size = len + X25_MAX_L2_LEN + X25_EXT_MIN_LEN;
if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) skb = sock_alloc_send_skb(sk, size, noblock, &rc);
return err; if (!skb)
goto out;
X25_SKB_CB(skb)->flags = msg->msg_flags; X25_SKB_CB(skb)->flags = msg->msg_flags;
skb_reserve(skb, X25_MAX_L2_LEN + X25_EXT_MIN_LEN); skb_reserve(skb, X25_MAX_L2_LEN + X25_EXT_MIN_LEN);
...@@ -934,7 +987,9 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct ...@@ -934,7 +987,9 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
asmptr = skb->h.raw = skb_put(skb, len); asmptr = skb->h.raw = skb_put(skb, len);
memcpy_fromiovec(asmptr, msg->msg_iov, len); rc = memcpy_fromiovec(asmptr, msg->msg_iov, len);
if (rc)
goto out_kfree_skb;
/* /*
* If the Q BIT Include socket option is in force, the first * If the Q BIT Include socket option is in force, the first
...@@ -985,21 +1040,18 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct ...@@ -985,21 +1040,18 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
SOCK_DEBUG(sk, "x25_sendmsg: Built header.\n"); SOCK_DEBUG(sk, "x25_sendmsg: Built header.\n");
SOCK_DEBUG(sk, "x25_sendmsg: Transmitting buffer\n"); SOCK_DEBUG(sk, "x25_sendmsg: Transmitting buffer\n");
if (sk->state != TCP_ESTABLISHED) { rc = -ENOTCONN;
kfree_skb(skb); if (sk->state != TCP_ESTABLISHED)
return -ENOTCONN; goto out_kfree_skb;
}
if (msg->msg_flags & MSG_OOB) { if (msg->msg_flags & MSG_OOB)
skb_queue_tail(&x25->interrupt_out_queue, skb); skb_queue_tail(&x25->interrupt_out_queue, skb);
} else { else {
len = x25_output(sk, skb); len = x25_output(sk, skb);
if(len<0){ if (len < 0)
kfree_skb(skb); kfree_skb(skb);
} else { else if (x25->qbitincl)
if (x25->qbitincl) len++;
len++;
}
} }
/* /*
...@@ -1019,31 +1071,37 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct ...@@ -1019,31 +1071,37 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
lock_sock(sk); lock_sock(sk);
x25_kick(sk); x25_kick(sk);
release_sock(sk); release_sock(sk);
rc = len;
return len; out:
return rc;
out_kfree_skb:
kfree_skb(skb);
goto out;
} }
static int x25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags, struct scm_cookie *scm) static int x25_recvmsg(struct socket *sock, struct msghdr *msg, int size,
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;
unsigned char *asmptr; unsigned char *asmptr;
int er; int rc = -ENOTCONN;
/* /*
* This works for seqpacket too. The receiver has ordered the queue for * This works for seqpacket too. The receiver has ordered the queue for
* us! We do one quick check first though * us! We do one quick check first though
*/ */
if (sk->state != TCP_ESTABLISHED) if (sk->state != TCP_ESTABLISHED)
return -ENOTCONN; goto out;
if (flags & MSG_OOB) { if (flags & MSG_OOB) {
rc = -EINVAL;
if (sk->urginline || !skb_peek(&x25->interrupt_in_queue)) if (sk->urginline || !skb_peek(&x25->interrupt_in_queue))
return -EINVAL; goto out;
skb = skb_dequeue(&x25->interrupt_in_queue); skb = skb_dequeue(&x25->interrupt_in_queue);
...@@ -1060,8 +1118,9 @@ static int x25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int fl ...@@ -1060,8 +1118,9 @@ static int x25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int fl
msg->msg_flags |= MSG_OOB; msg->msg_flags |= MSG_OOB;
} else { } else {
/* Now we can treat all alike */ /* Now we can treat all alike */
if ((skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &er)) == NULL) skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &rc);
return er; if (!skb)
goto out;
qbit = (skb->data[0] & X25_Q_BIT) == X25_Q_BIT; qbit = (skb->data[0] & X25_Q_BIT) == X25_Q_BIT;
...@@ -1086,28 +1145,33 @@ static int x25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int fl ...@@ -1086,28 +1145,33 @@ static int x25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int fl
/* Currently, each datagram always contains a complete record */ /* Currently, each datagram always contains a complete record */
msg->msg_flags |= MSG_EOR; msg->msg_flags |= MSG_EOR;
skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); rc = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
if (rc)
goto out_free_dgram;
if (sx25 != NULL) { if (sx25) {
sx25->sx25_family = AF_X25; sx25->sx25_family = AF_X25;
sx25->sx25_addr = x25->dest_addr; sx25->sx25_addr = x25->dest_addr;
} }
msg->msg_namelen = sizeof(struct sockaddr_x25); msg->msg_namelen = sizeof(struct sockaddr_x25);
skb_free_datagram(sk, skb);
lock_sock(sk); lock_sock(sk);
x25_check_rbuf(sk); x25_check_rbuf(sk);
release_sock(sk); release_sock(sk);
rc = copied;
return copied; out_free_dgram:
skb_free_datagram(sk, skb);
out:
return rc;
} }
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;
switch (cmd) { switch (cmd) {
case TIOCOUTQ: { case TIOCOUTQ: {
...@@ -1115,26 +1179,33 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) ...@@ -1115,26 +1179,33 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
if (amount < 0) if (amount < 0)
amount = 0; amount = 0;
return put_user(amount, (unsigned int *)arg); rc = put_user(amount, (unsigned int *)arg);
break;
} }
case TIOCINQ: { case TIOCINQ: {
struct sk_buff *skb; struct sk_buff *skb;
int amount = 0; int amount = 0;
/* These two are safe on a single CPU system as only user tasks fiddle here */ /*
* These two are safe on a single CPU system as
* only user tasks fiddle here
*/
if ((skb = skb_peek(&sk->receive_queue)) != NULL) if ((skb = skb_peek(&sk->receive_queue)) != NULL)
amount = skb->len; amount = skb->len;
return put_user(amount, (unsigned int *)arg); rc = put_user(amount, (unsigned int *)arg);
break;
} }
case SIOCGSTAMP: case SIOCGSTAMP:
if (sk != NULL) { if (sk) {
if (sk->stamp.tv_sec == 0) rc = -ENOENT;
return -ENOENT; if (!sk->stamp.tv_sec)
return copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0; break;
rc = copy_to_user((void *)arg, &sk->stamp,
sizeof(struct timeval)) ? -EFAULT : 0;
} }
return -EINVAL; rc = -EINVAL;
break;
case SIOCGIFADDR: case SIOCGIFADDR:
case SIOCSIFADDR: case SIOCSIFADDR:
case SIOCGIFDSTADDR: case SIOCGIFDSTADDR:
...@@ -1145,74 +1216,90 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) ...@@ -1145,74 +1216,90 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
case SIOCSIFNETMASK: case SIOCSIFNETMASK:
case SIOCGIFMETRIC: case SIOCGIFMETRIC:
case SIOCSIFMETRIC: case SIOCSIFMETRIC:
return -EINVAL; rc = -EINVAL;
break;
case SIOCADDRT: case SIOCADDRT:
case SIOCDELRT: case SIOCDELRT:
if (!capable(CAP_NET_ADMIN)) return -EPERM; rc = -EPERM;
return x25_route_ioctl(cmd, (void *)arg); if (!capable(CAP_NET_ADMIN))
break;
rc = x25_route_ioctl(cmd, (void *)arg);
break;
case SIOCX25GSUBSCRIP: case SIOCX25GSUBSCRIP:
return x25_subscr_ioctl(cmd, (void *)arg); rc = x25_subscr_ioctl(cmd, (void *)arg);
break;
case SIOCX25SSUBSCRIP: case SIOCX25SSUBSCRIP:
if (!capable(CAP_NET_ADMIN)) return -EPERM; rc = -EPERM;
return x25_subscr_ioctl(cmd, (void *)arg); if (!capable(CAP_NET_ADMIN))
break;
rc = x25_subscr_ioctl(cmd, (void *)arg);
break;
case SIOCX25GFACILITIES: { case SIOCX25GFACILITIES: {
struct x25_facilities facilities; struct x25_facilities fac = x25->facilities;
facilities = x25->facilities; rc = copy_to_user((void *)arg, &fac, sizeof(fac)) ? -EFAULT : 0;
return copy_to_user((void *)arg, &facilities, sizeof(facilities)) ? -EFAULT : 0; break;
} }
case SIOCX25SFACILITIES: { case SIOCX25SFACILITIES: {
struct x25_facilities facilities; struct x25_facilities facilities;
rc = -EFAULT;
if (copy_from_user(&facilities, (void *)arg, sizeof(facilities))) if (copy_from_user(&facilities, (void *)arg, sizeof(facilities)))
return -EFAULT; break;
rc = -EINVAL;
if (sk->state != TCP_LISTEN && sk->state != TCP_CLOSE) if (sk->state != TCP_LISTEN && sk->state != TCP_CLOSE)
return -EINVAL; break;
if (facilities.pacsize_in < X25_PS16 || facilities.pacsize_in > X25_PS4096) if (facilities.pacsize_in < X25_PS16 ||
return -EINVAL; facilities.pacsize_in > X25_PS4096)
if (facilities.pacsize_out < X25_PS16 || facilities.pacsize_out > X25_PS4096) break;
return -EINVAL; if (facilities.pacsize_out < X25_PS16 ||
if (facilities.winsize_in < 1 || facilities.winsize_in > 127) facilities.pacsize_out > X25_PS4096)
return -EINVAL; break;
if (facilities.throughput < 0x03 || facilities.throughput > 0xDD) if (facilities.winsize_in < 1 ||
return -EINVAL; facilities.winsize_in > 127)
if (facilities.reverse != 0 && facilities.reverse != 1) break;
return -EINVAL; if (facilities.throughput < 0x03 ||
facilities.throughput > 0xDD)
break;
if (facilities.reverse && facilities.reverse != 1)
break;
x25->facilities = facilities; x25->facilities = facilities;
return 0; rc = 0;
break;
} }
case SIOCX25GCALLUSERDATA: { case SIOCX25GCALLUSERDATA: {
struct x25_calluserdata calluserdata; struct x25_calluserdata cud = x25->calluserdata;
calluserdata = x25->calluserdata; rc = copy_to_user((void *)arg, &cud, sizeof(cud)) ? -EFAULT : 0;
return copy_to_user((void *)arg, &calluserdata, sizeof(calluserdata)) ? -EFAULT : 0; break;
} }
case SIOCX25SCALLUSERDATA: { case SIOCX25SCALLUSERDATA: {
struct x25_calluserdata calluserdata; struct x25_calluserdata calluserdata;
rc = -EFAULT;
if (copy_from_user(&calluserdata, (void *)arg, sizeof(calluserdata))) if (copy_from_user(&calluserdata, (void *)arg, sizeof(calluserdata)))
return -EFAULT; break;
rc = -EINVAL;
if (calluserdata.cudlength > X25_MAX_CUD_LEN) if (calluserdata.cudlength > X25_MAX_CUD_LEN)
return -EINVAL; break;
x25->calluserdata = calluserdata; x25->calluserdata = calluserdata;
return 0; rc = 0;
break;
} }
case SIOCX25GCAUSEDIAG: { case SIOCX25GCAUSEDIAG: {
struct x25_causediag causediag; struct x25_causediag causediag;
causediag = x25->causediag; causediag = x25->causediag;
return copy_to_user((void *)arg, &causediag, sizeof(causediag)) ? -EFAULT : 0; rc = copy_to_user((void *)arg, &causediag, sizeof(causediag)) ? -EFAULT : 0;
break;
} }
default: default:
return dev_ioctl(cmd, (void *)arg); rc = dev_ioctl(cmd, (void *)arg);
break;
} }
/*NOTREACHED*/ return rc;
return 0;
} }
static int x25_get_info(char *buffer, char **start, off_t offset, int length) static int x25_get_info(char *buffer, char **start, off_t offset, int length)
...@@ -1220,23 +1307,24 @@ static int x25_get_info(char *buffer, char **start, off_t offset, int length) ...@@ -1220,23 +1307,24 @@ static int x25_get_info(char *buffer, char **start, off_t offset, int length)
struct sock *s; struct sock *s;
struct net_device *dev; struct net_device *dev;
const char *devname; const char *devname;
int len = 0;
off_t pos = 0; off_t pos = 0;
off_t begin = 0; off_t begin = 0;
int len = sprintf(buffer, "dest_addr src_addr dev lci st vs vr "
"va t t2 t21 t22 t23 Snd-Q Rcv-Q inode\n");
cli(); read_lock_bh(&x25_list_lock);
len += sprintf(buffer, "dest_addr src_addr dev lci st vs vr va t t2 t21 t22 t23 Snd-Q Rcv-Q inode\n"); for (s = x25_list; s; s = s->next) {
struct x25_opt *x25 = x25_sk(s);
for (s = x25_list; s != NULL; s = s->next) {
x25_cb *x25 = x25_sk(s);
if (!x25->neighbour || (dev = x25->neighbour->dev) == NULL) if (!x25->neighbour || (dev = x25->neighbour->dev) == NULL)
devname = "???"; devname = "???";
else else
devname = x25->neighbour->dev->name; devname = x25->neighbour->dev->name;
len += sprintf(buffer + len, "%-10s %-10s %-5s %3.3X %d %d %d %d %3lu %3lu %3lu %3lu %3lu %5d %5d %ld\n", len += sprintf(buffer + len, "%-10s %-10s %-5s %3.3X %d %d "
"%d %d %3lu %3lu %3lu %3lu %3lu "
"%5d %5d %ld\n",
!x25->dest_addr.x25_addr[0] ? "*" : !x25->dest_addr.x25_addr[0] ? "*" :
x25->dest_addr.x25_addr, x25->dest_addr.x25_addr,
!x25->source_addr.x25_addr[0] ? "*" : !x25->source_addr.x25_addr[0] ? "*" :
...@@ -1254,7 +1342,7 @@ static int x25_get_info(char *buffer, char **start, off_t offset, int length) ...@@ -1254,7 +1342,7 @@ static int x25_get_info(char *buffer, char **start, off_t offset, int length)
x25->t23 / HZ, x25->t23 / HZ,
atomic_read(&s->wmem_alloc), atomic_read(&s->wmem_alloc),
atomic_read(&s->rmem_alloc), atomic_read(&s->rmem_alloc),
s->socket != NULL ? SOCK_INODE(s->socket)->i_ino : 0L); s->socket ? SOCK_INODE(s->socket)->i_ino : 0L);
pos = begin + len; pos = begin + len;
...@@ -1267,14 +1355,15 @@ static int x25_get_info(char *buffer, char **start, off_t offset, int length) ...@@ -1267,14 +1355,15 @@ static int x25_get_info(char *buffer, char **start, off_t offset, int length)
break; break;
} }
sti(); read_unlock_bh(&x25_list_lock);
*start = buffer + (offset - begin); *start = buffer + (offset - begin);
len -= (offset - begin); len -= (offset - begin);
if (len > length) len = length; if (len > length)
len = length;
return(len); return len;
} }
struct net_proto_family x25_family_ops = { struct net_proto_family x25_family_ops = {
...@@ -1308,22 +1397,25 @@ SOCKOPS_WRAP(x25_proto, AF_X25); ...@@ -1308,22 +1397,25 @@ SOCKOPS_WRAP(x25_proto, AF_X25);
static struct packet_type x25_packet_type = { static struct packet_type x25_packet_type = {
.type = __constant_htons(ETH_P_X25), .type = __constant_htons(ETH_P_X25),
.func = x25_lapb_receive_frame, .func = x25_lapb_receive_frame,
}; };
struct notifier_block x25_dev_notifier = { 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 != NULL; s=s->next){ write_lock_bh(&x25_list_lock);
if (x25_sk(s)->neighbour == neigh)
for (s = x25_list; s; s = s->next)
if (x25_sk(s)->neighbour == nb)
x25_disconnect(s, ENETUNREACH, 0, 0); x25_disconnect(s, ENETUNREACH, 0, 0);
}
write_unlock_bh(&x25_list_lock);
} }
static int __init x25_init(void) static int __init x25_init(void)
...@@ -1351,7 +1443,7 @@ static int __init x25_init(void) ...@@ -1351,7 +1443,7 @@ static int __init x25_init(void)
* Register any pre existing devices. * Register any pre existing devices.
*/ */
read_lock(&dev_base_lock); read_lock(&dev_base_lock);
for (dev = dev_base; dev != NULL; dev = dev->next) { for (dev = dev_base; dev; dev = dev->next) {
if ((dev->flags & IFF_UP) && (dev->type == ARPHRD_X25 if ((dev->flags & IFF_UP) && (dev->type == ARPHRD_X25
#if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE) #if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE)
|| dev->type == ARPHRD_ETHER || dev->type == ARPHRD_ETHER
......
...@@ -13,38 +13,88 @@ ...@@ -13,38 +13,88 @@
#include <linux/init.h> #include <linux/init.h>
#include <net/x25.h> #include <net/x25.h>
static int min_timer[] = {1 * HZ}; static int min_timer[] = { 1 * HZ };
static int max_timer[] = {300 * HZ}; static int max_timer[] = { 300 * HZ };
static struct ctl_table_header *x25_table_header; static struct ctl_table_header *x25_table_header;
static ctl_table x25_table[] = { static struct ctl_table x25_table[] = {
{NET_X25_RESTART_REQUEST_TIMEOUT, "restart_request_timeout", {
&sysctl_x25_restart_request_timeout, sizeof(int), 0644, NULL, .ctl_name = NET_X25_RESTART_REQUEST_TIMEOUT,
&proc_dointvec_minmax, &sysctl_intvec, NULL, &min_timer, &max_timer}, .procname = "restart_request_timeout",
{NET_X25_CALL_REQUEST_TIMEOUT, "call_request_timeout", .data = &sysctl_x25_restart_request_timeout,
&sysctl_x25_call_request_timeout, sizeof(int), 0644, NULL, .maxlen = sizeof(int),
&proc_dointvec_minmax, &sysctl_intvec, NULL, &min_timer, &max_timer}, .mode = 0644,
{NET_X25_RESET_REQUEST_TIMEOUT, "reset_request_timeout", .proc_handler = &proc_dointvec_minmax,
&sysctl_x25_reset_request_timeout, sizeof(int), 0644, NULL, .strategy = &sysctl_intvec,
&proc_dointvec_minmax, &sysctl_intvec, NULL, &min_timer, &max_timer}, .extra1 = &min_timer,
{NET_X25_CLEAR_REQUEST_TIMEOUT, "clear_request_timeout", .extra2 = &max_timer,
&sysctl_x25_clear_request_timeout, sizeof(int), 0644, NULL, },
&proc_dointvec_minmax, &sysctl_intvec, NULL, &min_timer, &max_timer}, {
{NET_X25_ACK_HOLD_BACK_TIMEOUT, "acknowledgement_hold_back_timeout", .ctl_name = NET_X25_CALL_REQUEST_TIMEOUT,
&sysctl_x25_ack_holdback_timeout, sizeof(int), 0644, NULL, .procname = "call_request_timeout",
&proc_dointvec_minmax, &sysctl_intvec, NULL, &min_timer, &max_timer}, .data = &sysctl_x25_call_request_timeout,
{0} .maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec_minmax,
.strategy = &sysctl_intvec,
.extra1 = &min_timer,
.extra2 = &max_timer,
},
{
.ctl_name = NET_X25_RESET_REQUEST_TIMEOUT,
.procname = "reset_request_timeout",
.data = &sysctl_x25_reset_request_timeout,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec_minmax,
.strategy = &sysctl_intvec,
.extra1 = &min_timer,
.extra2 = &max_timer,
},
{
.ctl_name = NET_X25_CLEAR_REQUEST_TIMEOUT,
.procname = "clear_request_timeout",
.data = &sysctl_x25_clear_request_timeout,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec_minmax,
.strategy = &sysctl_intvec,
.extra1 = &min_timer,
.extra2 = &max_timer,
},
{
.ctl_name = NET_X25_ACK_HOLD_BACK_TIMEOUT,
.procname = "acknowledgement_hold_back_timeout",
.data = &sysctl_x25_ack_holdback_timeout,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec_minmax,
.strategy = &sysctl_intvec,
.extra1 = &min_timer,
.extra2 = &max_timer,
},
{ 0, },
}; };
static ctl_table x25_dir_table[] = { static struct ctl_table x25_dir_table[] = {
{NET_X25, "x25", NULL, 0, 0555, x25_table}, {
{0} .ctl_name = NET_X25,
.procname = "x25",
.mode = 0555,
.child = x25_table,
},
{ 0, },
}; };
static ctl_table x25_root_table[] = { static struct ctl_table x25_root_table[] = {
{CTL_NET, "net", NULL, 0, 0555, x25_dir_table}, {
{0} .ctl_name = CTL_NET,
.procname = "net",
.mode = 0555,
.child = x25_dir_table,
},
{ 0, },
}; };
void __init x25_register_sysctl(void) void __init x25_register_sysctl(void)
......
...@@ -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);
} }
/* /*
* X.25 Packet Layer release 002 * X.25 Packet Layer release 002
* *
* This is ALPHA test software. This code may break your machine, randomly fail to work with new * This is ALPHA test software. This code may break your machine,
* releases, misbehave and/or generally screw up. It might even work. * randomly fail to work with new releases, misbehave and/or generally
* screw up. It might even work.
* *
* This code REQUIRES 2.1.15 or higher * This code REQUIRES 2.1.15 or higher
* *
...@@ -42,65 +43,71 @@ ...@@ -42,65 +43,71 @@
* Parse a set of facilities into the facilities structure. Unrecognised * Parse a set of facilities into the facilities structure. Unrecognised
* facilities are written to the debug log file. * facilities are written to the debug log file.
*/ */
int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities, unsigned long *vc_fac_mask) int x25_parse_facilities(struct sk_buff *skb,
struct x25_facilities *facilities,
unsigned long *vc_fac_mask)
{ {
unsigned int len;
unsigned char *p = skb->data; unsigned char *p = skb->data;
unsigned int len = *p++;
len = *p++;
*vc_fac_mask = 0; *vc_fac_mask = 0;
while (len > 0) { while (len > 0) {
switch (*p & X25_FAC_CLASS_MASK) { switch (*p & X25_FAC_CLASS_MASK) {
case X25_FAC_CLASS_A: case X25_FAC_CLASS_A:
switch (*p) { switch (*p) {
case X25_FAC_REVERSE: case X25_FAC_REVERSE:
facilities->reverse = (p[1] & 0x01); facilities->reverse = p[1] & 0x01;
*vc_fac_mask |= X25_MASK_REVERSE; *vc_fac_mask |= X25_MASK_REVERSE;
break;
case X25_FAC_THROUGHPUT:
facilities->throughput = p[1];
*vc_fac_mask |= X25_MASK_THROUGHPUT;
break;
default:
printk(KERN_DEBUG "X.25: unknown facility %02X, value %02X\n", p[0], p[1]);
break;
}
p += 2;
len -= 2;
break; break;
case X25_FAC_THROUGHPUT:
case X25_FAC_CLASS_B: facilities->throughput = p[1];
switch (*p) { *vc_fac_mask |= X25_MASK_THROUGHPUT;
case X25_FAC_PACKET_SIZE:
facilities->pacsize_in = p[1];
facilities->pacsize_out = p[2];
*vc_fac_mask |= X25_MASK_PACKET_SIZE;
break;
case X25_FAC_WINDOW_SIZE:
facilities->winsize_in = p[1];
facilities->winsize_out = p[2];
*vc_fac_mask |= X25_MASK_WINDOW_SIZE;
break;
default:
printk(KERN_DEBUG "X.25: unknown facility %02X, values %02X, %02X\n", p[0], p[1], p[2]);
break;
}
p += 3;
len -= 3;
break; break;
default:
case X25_FAC_CLASS_C: printk(KERN_DEBUG "X.25: unknown facility "
printk(KERN_DEBUG "X.25: unknown facility %02X, values %02X, %02X, %02X\n", p[0], p[1], p[2], p[3]); "%02X, value %02X\n",
p += 4; p[0], p[1]);
len -= 4;
break; break;
}
case X25_FAC_CLASS_D: p += 2;
printk(KERN_DEBUG "X.25: unknown facility %02X, length %d, values %02X, %02X, %02X, %02X\n", p[0], p[1], p[2], p[3], p[4], p[5]); len -= 2;
p += p[1] + 2; break;
len -= p[1] + 2; case X25_FAC_CLASS_B:
switch (*p) {
case X25_FAC_PACKET_SIZE:
facilities->pacsize_in = p[1];
facilities->pacsize_out = p[2];
*vc_fac_mask |= X25_MASK_PACKET_SIZE;
break;
case X25_FAC_WINDOW_SIZE:
facilities->winsize_in = p[1];
facilities->winsize_out = p[2];
*vc_fac_mask |= X25_MASK_WINDOW_SIZE;
break; break;
default:
printk(KERN_DEBUG "X.25: unknown facility "
"%02X, values %02X, %02X\n",
p[0], p[1], p[2]);
break;
}
p += 3;
len -= 3;
break;
case X25_FAC_CLASS_C:
printk(KERN_DEBUG "X.25: unknown facility %02X, "
"values %02X, %02X, %02X\n",
p[0], p[1], p[2], p[3]);
p += 4;
len -= 4;
break;
case X25_FAC_CLASS_D:
printk(KERN_DEBUG "X.25: unknown facility %02X, "
"length %d, values %02X, %02X, %02X, %02X\n",
p[0], p[1], p[2], p[3], p[4], p[5]);
p += p[1] + 2;
len -= p[1] + 2;
break;
} }
} }
...@@ -110,37 +117,45 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities, ...@@ -110,37 +117,45 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
/* /*
* Create a set of facilities. * Create a set of facilities.
*/ */
int x25_create_facilities(unsigned char *buffer, struct x25_facilities *facilities, unsigned long facil_mask) int x25_create_facilities(unsigned char *buffer,
struct x25_facilities *facilities,
unsigned long facil_mask)
{ {
unsigned char *p = buffer + 1; unsigned char *p = buffer + 1;
int len; int len;
if (facil_mask == 0) { if (!facil_mask) {
buffer [0] = 0; /* length of the facilities field in call_req or call_accept packets */ /*
* Length of the facilities field in call_req or
* call_accept packets
*/
buffer[0] = 0;
len = 1; /* 1 byte for the length field */ len = 1; /* 1 byte for the length field */
return len; return len;
} }
if ((facilities->reverse != 0) && (facil_mask & X25_MASK_REVERSE)) { if (facilities->reverse && (facil_mask & X25_MASK_REVERSE)) {
*p++ = X25_FAC_REVERSE; *p++ = X25_FAC_REVERSE;
*p++ = (facilities->reverse) ? 0x01 : 0x00; *p++ = !!facilities->reverse;
} }
if ((facilities->throughput != 0) && (facil_mask & X25_MASK_THROUGHPUT)) { if (facilities->throughput && (facil_mask & X25_MASK_THROUGHPUT)) {
*p++ = X25_FAC_THROUGHPUT; *p++ = X25_FAC_THROUGHPUT;
*p++ = facilities->throughput; *p++ = facilities->throughput;
} }
if ((facilities->pacsize_in != 0 || facilities->pacsize_out != 0) && (facil_mask & X25_MASK_PACKET_SIZE)) { if ((facilities->pacsize_in || facilities->pacsize_out) &&
(facil_mask & X25_MASK_PACKET_SIZE)) {
*p++ = X25_FAC_PACKET_SIZE; *p++ = X25_FAC_PACKET_SIZE;
*p++ = (facilities->pacsize_in == 0) ? facilities->pacsize_out : facilities->pacsize_in; *p++ = facilities->pacsize_in ? : facilities->pacsize_out;
*p++ = (facilities->pacsize_out == 0) ? facilities->pacsize_in : facilities->pacsize_out; *p++ = facilities->pacsize_out ? : facilities->pacsize_in;
} }
if ((facilities->winsize_in != 0 || facilities->winsize_out != 0) && (facil_mask & X25_MASK_WINDOW_SIZE)) { if ((facilities->winsize_in || facilities->winsize_out) &&
(facil_mask & X25_MASK_WINDOW_SIZE)) {
*p++ = X25_FAC_WINDOW_SIZE; *p++ = X25_FAC_WINDOW_SIZE;
*p++ = (facilities->winsize_in == 0) ? facilities->winsize_out : facilities->winsize_in; *p++ = facilities->winsize_in ? : facilities->winsize_out;
*p++ = (facilities->winsize_out == 0) ? facilities->winsize_in : facilities->winsize_out; *p++ = facilities->winsize_out ? : facilities->winsize_in;
} }
len = p - buffer; len = p - buffer;
...@@ -154,39 +169,37 @@ int x25_create_facilities(unsigned char *buffer, struct x25_facilities *faciliti ...@@ -154,39 +169,37 @@ int x25_create_facilities(unsigned char *buffer, struct x25_facilities *faciliti
* *
* The only real problem is with reverse charging. * The only real problem is with reverse charging.
*/ */
int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk, struct x25_facilities *new) int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk,
struct x25_facilities *new)
{ {
x25_cb *x25 = x25_sk(sk); struct x25_opt *x25 = x25_sk(sk);
struct x25_facilities *ours; struct x25_facilities *ours = &x25->facilities;
struct x25_facilities theirs; struct x25_facilities theirs;
int len; int len;
memset(&theirs, 0x00, sizeof(struct x25_facilities)); memset(&theirs, 0, sizeof(theirs));
memcpy(new, ours, sizeof(*new));
ours = &x25->facilities;
*new = *ours;
len = x25_parse_facilities(skb, &theirs, &x25->vc_facil_mask); len = x25_parse_facilities(skb, &theirs, &x25->vc_facil_mask);
/* /*
* They want reverse charging, we won't accept it. * They want reverse charging, we won't accept it.
*/ */
if (theirs.reverse != 0 && ours->reverse == 0) { if (theirs.reverse && ours->reverse) {
SOCK_DEBUG(sk, "X.25: rejecting reverse charging request"); SOCK_DEBUG(sk, "X.25: rejecting reverse charging request");
return -1; return -1;
} }
new->reverse = theirs.reverse; new->reverse = theirs.reverse;
if (theirs.throughput != 0) { if (theirs.throughput) {
if (theirs.throughput < ours->throughput) { if (theirs.throughput < ours->throughput) {
SOCK_DEBUG(sk, "X.25: throughput negotiated down"); SOCK_DEBUG(sk, "X.25: throughput negotiated down");
new->throughput = theirs.throughput; new->throughput = theirs.throughput;
} }
} }
if (theirs.pacsize_in != 0 && theirs.pacsize_out != 0) { if (theirs.pacsize_in && theirs.pacsize_out) {
if (theirs.pacsize_in < ours->pacsize_in) { if (theirs.pacsize_in < ours->pacsize_in) {
SOCK_DEBUG(sk, "X.25: packet size inwards negotiated down"); SOCK_DEBUG(sk, "X.25: packet size inwards negotiated down");
new->pacsize_in = theirs.pacsize_in; new->pacsize_in = theirs.pacsize_in;
...@@ -197,7 +210,7 @@ int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk, struct x25_fa ...@@ -197,7 +210,7 @@ int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk, struct x25_fa
} }
} }
if (theirs.winsize_in != 0 && theirs.winsize_out != 0) { if (theirs.winsize_in && theirs.winsize_out) {
if (theirs.winsize_in < ours->winsize_in) { if (theirs.winsize_in < ours->winsize_in) {
SOCK_DEBUG(sk, "X.25: window size inwards negotiated down"); SOCK_DEBUG(sk, "X.25: window size inwards negotiated down");
new->winsize_in = theirs.winsize_in; new->winsize_in = theirs.winsize_in;
...@@ -216,15 +229,15 @@ int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk, struct x25_fa ...@@ -216,15 +229,15 @@ int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk, struct x25_fa
* 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;
} }
if( facilities->winsize_out > 7 ){ if (facilities->winsize_out > 7) {
facilities->winsize_out = 7; facilities->winsize_out = 7;
printk( KERN_DEBUG "X.25: outgoing winsize limited to 7\n"); printk( KERN_DEBUG "X.25: outgoing winsize limited to 7\n");
} }
......
/* /*
* X.25 Packet Layer release 002 * X.25 Packet Layer release 002
* *
* This is ALPHA test software. This code may break your machine, randomly fail to work with new * This is ALPHA test software. This code may break your machine,
* releases, misbehave and/or generally screw up. It might even work. * randomly fail to work with new releases, misbehave and/or generally
* screw up. It might even work.
* *
* This code REQUIRES 2.1.15 or higher * This code REQUIRES 2.1.15 or higher
* *
...@@ -47,7 +48,7 @@ ...@@ -47,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;
...@@ -86,7 +87,7 @@ static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more) ...@@ -86,7 +87,7 @@ static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
skb_set_owner_r(skbn, sk); skb_set_owner_r(skbn, sk);
skb_queue_tail(&sk->receive_queue, skbn); skb_queue_tail(&sk->receive_queue, skbn);
if (!sk->dead) if (!sk->dead)
sk->data_ready(sk,skbn->len); sk->data_ready(sk, skbn->len);
return 0; return 0;
} }
...@@ -98,11 +99,11 @@ static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more) ...@@ -98,11 +99,11 @@ static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
*/ */
static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype) static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype)
{ {
x25_address source_addr, dest_addr; struct x25_address source_addr, dest_addr;
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;
...@@ -178,7 +179,7 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp ...@@ -178,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;
...@@ -307,7 +308,7 @@ static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametyp ...@@ -307,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;
...@@ -334,7 +335,7 @@ static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametyp ...@@ -334,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)
...@@ -364,10 +365,10 @@ int x25_process_rx_frame(struct sock *sk, struct sk_buff *skb) ...@@ -364,10 +365,10 @@ int x25_process_rx_frame(struct sock *sk, struct sk_buff *skb)
int x25_backlog_rcv(struct sock *sk, struct sk_buff *skb) int x25_backlog_rcv(struct sock *sk, struct sk_buff *skb)
{ {
int queued; int queued = x25_process_rx_frame(sk, skb);
queued = x25_process_rx_frame(sk,skb); if (!queued)
if(!queued) kfree_skb(skb); kfree_skb(skb);
return 0; return 0;
} }
/* /*
* X.25 Packet Layer release 002 * X.25 Packet Layer release 002
* *
* This is ALPHA test software. This code may break your machine, randomly fail to work with new * This is ALPHA test software. This code may break your machine,
* releases, misbehave and/or generally screw up. It might even work. * randomly fail to work with new releases, misbehave and/or generally
* screw up. It might even work.
* *
* This code REQUIRES 2.1.15 or higher * This code REQUIRES 2.1.15 or higher
* *
...@@ -42,98 +43,102 @@ ...@@ -42,98 +43,102 @@
#include <linux/init.h> #include <linux/init.h>
#include <net/x25.h> #include <net/x25.h>
static struct x25_neigh *x25_neigh_list /* = NULL initially */; static struct list_head x25_neigh_list = LIST_HEAD_INIT(x25_neigh_list);
static rwlock_t x25_neigh_list_lock = RW_LOCK_UNLOCKED;
static void x25_t20timer_expiry(unsigned long); static void x25_t20timer_expiry(unsigned long);
/* /*
* Linux set/reset timer routines * Linux set/reset timer routines
*/ */
static void x25_start_t20timer(struct x25_neigh *neigh) static void x25_start_t20timer(struct x25_neigh *nb)
{ {
del_timer(&neigh->t20timer); del_timer(&nb->t20timer);
neigh->t20timer.data = (unsigned long)neigh; nb->t20timer.data = (unsigned long)nb;
neigh->t20timer.function = &x25_t20timer_expiry; nb->t20timer.function = &x25_t20timer_expiry;
neigh->t20timer.expires = jiffies + neigh->t20; nb->t20timer.expires = jiffies + nb->t20;
add_timer(&neigh->t20timer); add_timer(&nb->t20timer);
} }
static void x25_t20timer_expiry(unsigned long param) static void x25_t20timer_expiry(unsigned long param)
{ {
struct x25_neigh *neigh = (struct x25_neigh *)param; struct x25_neigh *nb = (struct x25_neigh *)param;
x25_transmit_restart_request(neigh); x25_transmit_restart_request(nb);
x25_start_t20timer(neigh); x25_start_t20timer(nb);
} }
static void x25_stop_t20timer(struct x25_neigh *neigh) static void x25_stop_t20timer(struct x25_neigh *nb)
{ {
del_timer(&neigh->t20timer); del_timer(&nb->t20timer);
} }
static int x25_t20timer_pending(struct x25_neigh *neigh) static int x25_t20timer_pending(struct x25_neigh *nb)
{ {
return timer_pending(&neigh->t20timer); return timer_pending(&nb->t20timer);
} }
/* /*
* This handles all restart and diagnostic frames. * This handles all restart and diagnostic frames.
*/ */
void x25_link_control(struct sk_buff *skb, struct x25_neigh *neigh, unsigned short frametype) void x25_link_control(struct sk_buff *skb, struct x25_neigh *nb,
unsigned short frametype)
{ {
struct sk_buff *skbn; struct sk_buff *skbn;
int confirm; int confirm;
switch (frametype) { switch (frametype) {
case X25_RESTART_REQUEST: case X25_RESTART_REQUEST:
confirm = !x25_t20timer_pending(neigh); confirm = !x25_t20timer_pending(nb);
x25_stop_t20timer(neigh); x25_stop_t20timer(nb);
neigh->state = X25_LINK_STATE_3; nb->state = X25_LINK_STATE_3;
if (confirm) x25_transmit_restart_confirmation(neigh); if (confirm)
x25_transmit_restart_confirmation(nb);
break; break;
case X25_RESTART_CONFIRMATION: case X25_RESTART_CONFIRMATION:
x25_stop_t20timer(neigh); x25_stop_t20timer(nb);
neigh->state = X25_LINK_STATE_3; nb->state = X25_LINK_STATE_3;
break; break;
case X25_DIAGNOSTIC: case X25_DIAGNOSTIC:
printk(KERN_WARNING "x25: diagnostic #%d - %02X %02X %02X\n", skb->data[3], skb->data[4], skb->data[5], skb->data[6]); printk(KERN_WARNING "x25: diagnostic #%d - "
"%02X %02X %02X\n",
skb->data[3], skb->data[4],
skb->data[5], skb->data[6]);
break; break;
default: default:
printk(KERN_WARNING "x25: received unknown %02X with LCI 000\n", frametype); printk(KERN_WARNING "x25: received unknown %02X "
"with LCI 000\n", frametype);
break; break;
} }
if (neigh->state == X25_LINK_STATE_3) { if (nb->state == X25_LINK_STATE_3)
while ((skbn = skb_dequeue(&neigh->queue)) != NULL) while ((skbn = skb_dequeue(&nb->queue)) != NULL)
x25_send_frame(skbn, neigh); x25_send_frame(skbn, nb);
}
} }
/* /*
* This routine is called when a Restart Request is needed * This routine is called when a Restart Request is needed
*/ */
void x25_transmit_restart_request(struct x25_neigh *neigh) void x25_transmit_restart_request(struct x25_neigh *nb)
{ {
struct sk_buff *skb;
unsigned char *dptr; unsigned char *dptr;
int len; int len = X25_MAX_L2_LEN + X25_STD_MIN_LEN + 2;
struct sk_buff *skb = alloc_skb(len, GFP_ATOMIC);
len = X25_MAX_L2_LEN + X25_STD_MIN_LEN + 2;
if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL) if (!skb)
return; return;
skb_reserve(skb, X25_MAX_L2_LEN); skb_reserve(skb, X25_MAX_L2_LEN);
dptr = skb_put(skb, X25_STD_MIN_LEN + 2); dptr = skb_put(skb, X25_STD_MIN_LEN + 2);
*dptr++ = (neigh->extended) ? X25_GFI_EXTSEQ : X25_GFI_STDSEQ; *dptr++ = nb->extended ? X25_GFI_EXTSEQ : X25_GFI_STDSEQ;
*dptr++ = 0x00; *dptr++ = 0x00;
*dptr++ = X25_RESTART_REQUEST; *dptr++ = X25_RESTART_REQUEST;
*dptr++ = 0x00; *dptr++ = 0x00;
...@@ -141,108 +146,104 @@ void x25_transmit_restart_request(struct x25_neigh *neigh) ...@@ -141,108 +146,104 @@ void x25_transmit_restart_request(struct x25_neigh *neigh)
skb->sk = NULL; skb->sk = NULL;
x25_send_frame(skb, neigh); x25_send_frame(skb, nb);
} }
/* /*
* This routine is called when a Restart Confirmation is needed * This routine is called when a Restart Confirmation is needed
*/ */
void x25_transmit_restart_confirmation(struct x25_neigh *neigh) void x25_transmit_restart_confirmation(struct x25_neigh *nb)
{ {
struct sk_buff *skb;
unsigned char *dptr; unsigned char *dptr;
int len; int len = X25_MAX_L2_LEN + X25_STD_MIN_LEN;
struct sk_buff *skb = alloc_skb(len, GFP_ATOMIC);
len = X25_MAX_L2_LEN + X25_STD_MIN_LEN; if (!skb)
if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
return; return;
skb_reserve(skb, X25_MAX_L2_LEN); skb_reserve(skb, X25_MAX_L2_LEN);
dptr = skb_put(skb, X25_STD_MIN_LEN); dptr = skb_put(skb, X25_STD_MIN_LEN);
*dptr++ = (neigh->extended) ? X25_GFI_EXTSEQ : X25_GFI_STDSEQ; *dptr++ = nb->extended ? X25_GFI_EXTSEQ : X25_GFI_STDSEQ;
*dptr++ = 0x00; *dptr++ = 0x00;
*dptr++ = X25_RESTART_CONFIRMATION; *dptr++ = X25_RESTART_CONFIRMATION;
skb->sk = NULL; skb->sk = NULL;
x25_send_frame(skb, neigh); x25_send_frame(skb, nb);
} }
/* /*
* This routine is called when a Diagnostic is required. * This routine is called when a Diagnostic is required.
*/ */
void x25_transmit_diagnostic(struct x25_neigh *neigh, unsigned char diag) void x25_transmit_diagnostic(struct x25_neigh *nb, unsigned char diag)
{ {
struct sk_buff *skb;
unsigned char *dptr; unsigned char *dptr;
int len; int len = X25_MAX_L2_LEN + X25_STD_MIN_LEN + 1;
struct sk_buff *skb = alloc_skb(len, GFP_ATOMIC);
len = X25_MAX_L2_LEN + X25_STD_MIN_LEN + 1;
if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL) if (!skb)
return; return;
skb_reserve(skb, X25_MAX_L2_LEN); skb_reserve(skb, X25_MAX_L2_LEN);
dptr = skb_put(skb, X25_STD_MIN_LEN + 1); dptr = skb_put(skb, X25_STD_MIN_LEN + 1);
*dptr++ = (neigh->extended) ? X25_GFI_EXTSEQ : X25_GFI_STDSEQ; *dptr++ = nb->extended ? X25_GFI_EXTSEQ : X25_GFI_STDSEQ;
*dptr++ = 0x00; *dptr++ = 0x00;
*dptr++ = X25_DIAGNOSTIC; *dptr++ = X25_DIAGNOSTIC;
*dptr++ = diag; *dptr++ = diag;
skb->sk = NULL; skb->sk = NULL;
x25_send_frame(skb, neigh); x25_send_frame(skb, nb);
} }
/* /*
* This routine is called when a Clear Request is needed outside of the context * This routine is called when a Clear Request is needed outside of the context
* of a connected socket. * of a connected socket.
*/ */
void x25_transmit_clear_request(struct x25_neigh *neigh, unsigned int lci, unsigned char cause) void x25_transmit_clear_request(struct x25_neigh *nb, unsigned int lci,
unsigned char cause)
{ {
struct sk_buff *skb;
unsigned char *dptr; unsigned char *dptr;
int len; int len = X25_MAX_L2_LEN + X25_STD_MIN_LEN + 2;
struct sk_buff *skb = alloc_skb(len, GFP_ATOMIC);
len = X25_MAX_L2_LEN + X25_STD_MIN_LEN + 2; if (!skb)
if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
return; return;
skb_reserve(skb, X25_MAX_L2_LEN); skb_reserve(skb, X25_MAX_L2_LEN);
dptr = skb_put(skb, X25_STD_MIN_LEN + 2); dptr = skb_put(skb, X25_STD_MIN_LEN + 2);
*dptr++ = ((lci >> 8) & 0x0F) | (neigh->extended) ? X25_GFI_EXTSEQ : X25_GFI_STDSEQ; *dptr++ = ((lci >> 8) & 0x0F) | nb->extended ? X25_GFI_EXTSEQ :
*dptr++ = ((lci >> 0) & 0xFF); X25_GFI_STDSEQ;
*dptr++ = (lci >> 0) & 0xFF;
*dptr++ = X25_CLEAR_REQUEST; *dptr++ = X25_CLEAR_REQUEST;
*dptr++ = cause; *dptr++ = cause;
*dptr++ = 0x00; *dptr++ = 0x00;
skb->sk = NULL; skb->sk = NULL;
x25_send_frame(skb, neigh); x25_send_frame(skb, nb);
} }
void x25_transmit_link(struct sk_buff *skb, struct x25_neigh *neigh) void x25_transmit_link(struct sk_buff *skb, struct x25_neigh *nb)
{ {
switch (neigh->state) { switch (nb->state) {
case X25_LINK_STATE_0: case X25_LINK_STATE_0:
skb_queue_tail(&neigh->queue, skb); skb_queue_tail(&nb->queue, skb);
neigh->state = X25_LINK_STATE_1; nb->state = X25_LINK_STATE_1;
x25_establish_link(neigh); x25_establish_link(nb);
break; break;
case X25_LINK_STATE_1: case X25_LINK_STATE_1:
case X25_LINK_STATE_2: case X25_LINK_STATE_2:
skb_queue_tail(&neigh->queue, skb); skb_queue_tail(&nb->queue, skb);
break; break;
case X25_LINK_STATE_3: case X25_LINK_STATE_3:
x25_send_frame(skb, neigh); x25_send_frame(skb, nb);
break; break;
} }
} }
...@@ -250,16 +251,16 @@ void x25_transmit_link(struct sk_buff *skb, struct x25_neigh *neigh) ...@@ -250,16 +251,16 @@ void x25_transmit_link(struct sk_buff *skb, struct x25_neigh *neigh)
/* /*
* Called when the link layer has become established. * Called when the link layer has become established.
*/ */
void x25_link_established(struct x25_neigh *neigh) void x25_link_established(struct x25_neigh *nb)
{ {
switch (neigh->state) { switch (nb->state) {
case X25_LINK_STATE_0: case X25_LINK_STATE_0:
neigh->state = X25_LINK_STATE_2; nb->state = X25_LINK_STATE_2;
break; break;
case X25_LINK_STATE_1: case X25_LINK_STATE_1:
x25_transmit_restart_request(neigh); x25_transmit_restart_request(nb);
neigh->state = X25_LINK_STATE_2; nb->state = X25_LINK_STATE_2;
x25_start_t20timer(neigh); x25_start_t20timer(nb);
break; break;
} }
} }
...@@ -269,11 +270,11 @@ void x25_link_established(struct x25_neigh *neigh) ...@@ -269,11 +270,11 @@ void x25_link_established(struct x25_neigh *neigh)
* request has failed. * request has failed.
*/ */
void x25_link_terminated(struct x25_neigh *neigh) void x25_link_terminated(struct x25_neigh *nb)
{ {
neigh->state = X25_LINK_STATE_0; nb->state = X25_LINK_STATE_0;
/* Out of order: clear existing virtual calls (X.25 03/93 4.6.3) */ /* Out of order: clear existing virtual calls (X.25 03/93 4.6.3) */
x25_kill_by_neigh(neigh); x25_kill_by_neigh(nb);
} }
/* /*
...@@ -281,59 +282,50 @@ void x25_link_terminated(struct x25_neigh *neigh) ...@@ -281,59 +282,50 @@ void x25_link_terminated(struct x25_neigh *neigh)
*/ */
void x25_link_device_up(struct net_device *dev) void x25_link_device_up(struct net_device *dev)
{ {
struct x25_neigh *x25_neigh; struct x25_neigh *nb = kmalloc(sizeof(*nb), GFP_ATOMIC);
unsigned long flags;
if ((x25_neigh = kmalloc(sizeof(*x25_neigh), GFP_ATOMIC)) == NULL) if (!nb)
return; return;
skb_queue_head_init(&x25_neigh->queue); skb_queue_head_init(&nb->queue);
init_timer(&x25_neigh->t20timer); init_timer(&nb->t20timer);
dev_hold(dev); dev_hold(dev);
x25_neigh->dev = dev; nb->dev = dev;
x25_neigh->state = X25_LINK_STATE_0; nb->state = X25_LINK_STATE_0;
x25_neigh->extended = 0; nb->extended = 0;
x25_neigh->global_facil_mask = (X25_MASK_REVERSE | X25_MASK_THROUGHPUT | X25_MASK_PACKET_SIZE | X25_MASK_WINDOW_SIZE); /* enables negotiation */ /*
x25_neigh->t20 = sysctl_x25_restart_request_timeout; * Enables negotiation
*/
save_flags(flags); cli(); nb->global_facil_mask = X25_MASK_REVERSE |
x25_neigh->next = x25_neigh_list; X25_MASK_THROUGHPUT |
x25_neigh_list = x25_neigh; X25_MASK_PACKET_SIZE |
restore_flags(flags); X25_MASK_WINDOW_SIZE;
nb->t20 = sysctl_x25_restart_request_timeout;
atomic_set(&nb->refcnt, 1);
write_lock_bh(&x25_neigh_list_lock);
list_add(&nb->node, &x25_neigh_list);
write_unlock_bh(&x25_neigh_list_lock);
} }
static void x25_remove_neigh(struct x25_neigh *x25_neigh) /**
* __x25_remove_neigh - remove neighbour from x25_neigh_list
* @nb - neigh to remove
*
* Remove neighbour from x25_neigh_list. If it was there.
* Caller must hold x25_neigh_list_lock.
*/
static void __x25_remove_neigh(struct x25_neigh *nb)
{ {
struct x25_neigh *s; skb_queue_purge(&nb->queue);
unsigned long flags; x25_stop_t20timer(nb);
skb_queue_purge(&x25_neigh->queue);
x25_stop_t20timer(x25_neigh); if (nb->node.next) {
list_del(&nb->node);
save_flags(flags); cli(); x25_neigh_put(nb);
if ((s = x25_neigh_list) == x25_neigh) {
x25_neigh_list = x25_neigh->next;
restore_flags(flags);
kfree(x25_neigh);
return;
}
while (s != NULL && s->next != NULL) {
if (s->next == x25_neigh) {
s->next = x25_neigh->next;
restore_flags(flags);
kfree(x25_neigh);
return;
}
s = s->next;
} }
restore_flags(flags);
} }
/* /*
...@@ -341,17 +333,21 @@ static void x25_remove_neigh(struct x25_neigh *x25_neigh) ...@@ -341,17 +333,21 @@ static void x25_remove_neigh(struct x25_neigh *x25_neigh)
*/ */
void x25_link_device_down(struct net_device *dev) void x25_link_device_down(struct net_device *dev)
{ {
struct x25_neigh *neigh, *x25_neigh = x25_neigh_list; struct x25_neigh *nb;
struct list_head *entry, *tmp;
while (x25_neigh != NULL) { write_lock_bh(&x25_neigh_list_lock);
neigh = x25_neigh;
x25_neigh = x25_neigh->next;
if (neigh->dev == dev){ list_for_each_safe(entry, tmp, &x25_neigh_list) {
x25_remove_neigh(neigh); nb = list_entry(entry, struct x25_neigh, node);
if (nb->dev == dev) {
__x25_remove_neigh(nb);
dev_put(dev); dev_put(dev);
} }
} }
write_unlock_bh(&x25_neigh_list_lock);
} }
/* /*
...@@ -359,13 +355,23 @@ void x25_link_device_down(struct net_device *dev) ...@@ -359,13 +355,23 @@ void x25_link_device_down(struct net_device *dev)
*/ */
struct x25_neigh *x25_get_neigh(struct net_device *dev) struct x25_neigh *x25_get_neigh(struct net_device *dev)
{ {
struct x25_neigh *x25_neigh; struct x25_neigh *nb, *use = NULL;
struct list_head *entry;
for (x25_neigh = x25_neigh_list; x25_neigh != NULL; x25_neigh = x25_neigh->next) read_lock_bh(&x25_neigh_list_lock);
if (x25_neigh->dev == dev) list_for_each(entry, &x25_neigh_list) {
return x25_neigh; nb = list_entry(entry, struct x25_neigh, node);
if (nb->dev == dev) {
use = nb;
break;
}
}
return NULL; if (use)
x25_neigh_hold(use);
read_unlock_bh(&x25_neigh_list_lock);
return use;
} }
/* /*
...@@ -374,48 +380,45 @@ struct x25_neigh *x25_get_neigh(struct net_device *dev) ...@@ -374,48 +380,45 @@ struct x25_neigh *x25_get_neigh(struct net_device *dev)
int x25_subscr_ioctl(unsigned int cmd, void *arg) int x25_subscr_ioctl(unsigned int cmd, void *arg)
{ {
struct x25_subscrip_struct x25_subscr; struct x25_subscrip_struct x25_subscr;
struct x25_neigh *x25_neigh; struct x25_neigh *nb;
struct net_device *dev; struct net_device *dev;
int rc = -EINVAL;
switch (cmd) {
if (cmd != SIOCX25GSUBSCRIP && cmd != SIOCX25SSUBSCRIP)
case SIOCX25GSUBSCRIP: goto out;
if (copy_from_user(&x25_subscr, arg, sizeof(struct x25_subscrip_struct)))
return -EFAULT; rc = -EFAULT;
if ((dev = x25_dev_get(x25_subscr.device)) == NULL) if (copy_from_user(&x25_subscr, arg, sizeof(x25_subscr)))
return -EINVAL; goto out;
if ((x25_neigh = x25_get_neigh(dev)) == NULL) {
dev_put(dev); rc = -EINVAL;
return -EINVAL; if ((dev = x25_dev_get(x25_subscr.device)) == NULL)
} goto out;
dev_put(dev);
x25_subscr.extended = x25_neigh->extended; if ((nb = x25_get_neigh(dev)) == NULL)
x25_subscr.global_facil_mask = x25_neigh->global_facil_mask; goto out_dev_put;
if (copy_to_user(arg, &x25_subscr, sizeof(struct x25_subscrip_struct)))
return -EFAULT; dev_put(dev);
break;
if (cmd == SIOCX25GSUBSCRIP) {
case SIOCX25SSUBSCRIP: x25_subscr.extended = nb->extended;
if (copy_from_user(&x25_subscr, arg, sizeof(struct x25_subscrip_struct))) x25_subscr.global_facil_mask = nb->global_facil_mask;
return -EFAULT; rc = copy_to_user(arg, &x25_subscr,
if ((dev = x25_dev_get(x25_subscr.device)) == NULL) sizeof(x25_subscr)) ? -EFAULT : 0;
return -EINVAL; } else {
if ((x25_neigh = x25_get_neigh(dev)) == NULL) { rc = -EINVAL;
dev_put(dev); if (!(x25_subscr.extended && x25_subscr.extended != 1)) {
return -EINVAL; rc = 0;
} nb->extended = x25_subscr.extended;
dev_put(dev); nb->global_facil_mask = x25_subscr.global_facil_mask;
if (x25_subscr.extended != 0 && x25_subscr.extended != 1) }
return -EINVAL;
x25_neigh->extended = x25_subscr.extended;
x25_neigh->global_facil_mask = x25_subscr.global_facil_mask;
break;
default:
return -EINVAL;
} }
x25_neigh_put(nb);
return 0; out:
return rc;
out_dev_put:
dev_put(dev);
goto out;
} }
...@@ -424,12 +427,14 @@ int x25_subscr_ioctl(unsigned int cmd, void *arg) ...@@ -424,12 +427,14 @@ int x25_subscr_ioctl(unsigned int cmd, void *arg)
*/ */
void __exit x25_link_free(void) void __exit x25_link_free(void)
{ {
struct x25_neigh *neigh, *x25_neigh = x25_neigh_list; struct x25_neigh *nb;
struct list_head *entry, *tmp;
while (x25_neigh != NULL) { write_lock_bh(&x25_neigh_list_lock);
neigh = x25_neigh;
x25_neigh = x25_neigh->next;
x25_remove_neigh(neigh); list_for_each_safe(entry, tmp, &x25_neigh_list) {
nb = list_entry(entry, struct x25_neigh, node);
__x25_remove_neigh(nb);
} }
write_unlock_bh(&x25_neigh_list_lock);
} }
/* /*
* X.25 Packet Layer release 002 * X.25 Packet Layer release 002
* *
* This is ALPHA test software. This code may break your machine, randomly fail to work with new * This is ALPHA test software. This code may break your machine,
* releases, misbehave and/or generally screw up. It might even work. * randomly fail to work with new releases, misbehave and/or generally
* screw up. It might even work.
* *
* This code REQUIRES 2.1.15 or higher * This code REQUIRES 2.1.15 or higher
* *
...@@ -45,7 +46,7 @@ static int x25_pacsize_to_bytes(unsigned int pacsize) ...@@ -45,7 +46,7 @@ static int x25_pacsize_to_bytes(unsigned int pacsize)
{ {
int bytes = 1; int bytes = 1;
if (pacsize == 0) if (!pacsize)
return 128; return 128;
while (pacsize-- > 0) while (pacsize-- > 0)
...@@ -66,7 +67,7 @@ int x25_output(struct sock *sk, struct sk_buff *skb) ...@@ -66,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);
...@@ -79,18 +80,21 @@ int x25_output(struct sock *sk, struct sk_buff *skb) ...@@ -79,18 +80,21 @@ int x25_output(struct sock *sk, struct sk_buff *skb)
frontlen = skb_headroom(skb); frontlen = skb_headroom(skb);
while (skb->len > 0) { while (skb->len > 0) {
if ((skbn = sock_alloc_send_skb(sk, frontlen + max_len, noblock, &err)) == NULL){ if ((skbn = sock_alloc_send_skb(sk, frontlen + max_len,
if(err == -EWOULDBLOCK && noblock){ noblock, &err)) == NULL){
if (err == -EWOULDBLOCK && noblock){
kfree_skb(skb); kfree_skb(skb);
return sent; return sent;
} }
SOCK_DEBUG(sk, "x25_output: fragment allocation failed, err=%d, %d bytes sent\n", err, sent); SOCK_DEBUG(sk, "x25_output: fragment alloc"
" failed, err=%d, %d bytes "
"sent\n", err, sent);
return err; return err;
} }
skb_reserve(skbn, frontlen); skb_reserve(skbn, frontlen);
len = (max_len > skb->len) ? skb->len : max_len; len = max_len > skb->len ? skb->len : max_len;
/* Copy the user data */ /* Copy the user data */
memcpy(skb_put(skbn, len), skb->data, len); memcpy(skb_put(skbn, len), skb->data, len);
...@@ -125,9 +129,9 @@ int x25_output(struct sock *sk, struct sk_buff *skb) ...@@ -125,9 +129,9 @@ 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 == NULL) if (!skb)
return; return;
if (x25->neighbour->extended) { if (x25->neighbour->extended) {
...@@ -148,7 +152,7 @@ void x25_kick(struct sock *sk) ...@@ -148,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;
...@@ -168,9 +172,9 @@ void x25_kick(struct sock *sk) ...@@ -168,9 +172,9 @@ void x25_kick(struct sock *sk)
if (skb_peek(&sk->write_queue) == NULL) if (skb_peek(&sk->write_queue) == NULL)
return; return;
modulus = (x25->neighbour->extended) ? X25_EMODULUS : X25_SMODULUS; modulus = x25->neighbour->extended ? X25_EMODULUS : X25_SMODULUS;
start = (skb_peek(&x25->ack_queue) == NULL) ? x25->va : x25->vs; start = skb_peek(&x25->ack_queue) ? x25->vs : x25->va;
end = (x25->va + x25->facilities.winsize_out) % modulus; end = (x25->va + x25->facilities.winsize_out) % modulus;
if (start == end) if (start == end)
...@@ -220,7 +224,7 @@ void x25_kick(struct sock *sk) ...@@ -220,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);
......
/* /*
* X.25 Packet Layer release 002 * X.25 Packet Layer release 002
* *
* This is ALPHA test software. This code may break your machine, randomly fail to work with new * This is ALPHA test software. This code may break your machine,
* releases, misbehave and/or generally screw up. It might even work. * randomly fail to work with new releases, misbehave and/or generally
* screw up. It might even work.
* *
* This code REQUIRES 2.1.15 or higher * This code REQUIRES 2.1.15 or higher
* *
...@@ -43,78 +44,85 @@ ...@@ -43,78 +44,85 @@
#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.
*/ */
static int x25_add_route(x25_address *address, unsigned int sigdigits, struct net_device *dev) static int x25_add_route(struct x25_address *address, unsigned int sigdigits,
struct net_device *dev)
{ {
struct x25_route *x25_route; struct x25_route *rt;
unsigned long flags; struct list_head *entry;
int rc = -EINVAL;
for (x25_route = x25_route_list; x25_route != NULL; x25_route = x25_route->next) write_lock_bh(&x25_route_list_lock);
if (memcmp(&x25_route->address, address, sigdigits) == 0 && x25_route->sigdigits == sigdigits)
return -EINVAL;
if ((x25_route = kmalloc(sizeof(*x25_route), GFP_ATOMIC)) == NULL) list_for_each(entry, &x25_route_list) {
return -ENOMEM; rt = list_entry(entry, struct x25_route, node);
strcpy(x25_route->address.x25_addr, "000000000000000"); if (!memcmp(&rt->address, address, sigdigits) &&
memcpy(x25_route->address.x25_addr, address->x25_addr, sigdigits); rt->sigdigits == sigdigits)
goto out;
}
rt = kmalloc(sizeof(*rt), GFP_ATOMIC);
rc = -ENOMEM;
if (!rt)
goto out;
x25_route->sigdigits = sigdigits; strcpy(rt->address.x25_addr, "000000000000000");
x25_route->dev = dev; memcpy(rt->address.x25_addr, address->x25_addr, sigdigits);
save_flags(flags); cli(); rt->sigdigits = sigdigits;
x25_route->next = x25_route_list; rt->dev = dev;
x25_route_list = x25_route; atomic_set(&rt->refcnt, 1);
restore_flags(flags);
return 0; list_add(&rt->node, &x25_route_list);
rc = 0;
out:
write_unlock_bh(&x25_route_list_lock);
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);
kfree(x25_route);
return;
} }
while (s != NULL && s->next != NULL) {
if (s->next == x25_route) {
s->next = x25_route->next;
restore_flags(flags);
kfree(x25_route);
return;
}
s = s->next;
}
restore_flags(flags);
} }
static int x25_del_route(x25_address *address, unsigned int sigdigits, struct net_device *dev) static int x25_del_route(struct x25_address *address, unsigned int sigdigits,
struct net_device *dev)
{ {
struct x25_route *x25_route; struct x25_route *rt;
struct list_head *entry;
int rc = -EINVAL;
write_lock_bh(&x25_route_list_lock);
list_for_each(entry, &x25_route_list) {
rt = list_entry(entry, struct x25_route, node);
for (x25_route = x25_route_list; x25_route != NULL; x25_route = x25_route->next) { if (!memcmp(&rt->address, address, sigdigits) &&
if (memcmp(&x25_route->address, address, sigdigits) == 0 && x25_route->sigdigits == sigdigits && x25_route->dev == dev) { rt->sigdigits == sigdigits && rt->dev == dev) {
x25_remove_route(x25_route); __x25_remove_route(rt);
return 0; rc = 0;
break;
} }
} }
return -EINVAL; write_unlock_bh(&x25_route_list_lock);
return rc;
} }
/* /*
...@@ -122,15 +130,18 @@ static int x25_del_route(x25_address *address, unsigned int sigdigits, struct ne ...@@ -122,15 +130,18 @@ static int x25_del_route(x25_address *address, unsigned int sigdigits, struct ne
*/ */
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;
write_lock_bh(&x25_route_list_lock);
while (x25_route != NULL) { list_for_each_safe(entry, tmp, &x25_route_list) {
route = x25_route; rt = list_entry(entry, struct x25_route, node);
x25_route = x25_route->next;
if (route->dev == dev) if (rt->dev == dev)
x25_remove_route(route); __x25_remove_route(rt);
} }
write_unlock_bh(&x25_route_list_lock);
} }
/* /*
...@@ -138,42 +149,48 @@ void x25_route_device_down(struct net_device *dev) ...@@ -138,42 +149,48 @@ void x25_route_device_down(struct net_device *dev)
*/ */
struct net_device *x25_dev_get(char *devname) struct net_device *x25_dev_get(char *devname)
{ {
struct net_device *dev; struct net_device *dev = dev_get_by_name(devname);
if ((dev = dev_get_by_name(devname)) == NULL)
return NULL;
if ((dev->flags & IFF_UP) && (dev->type == ARPHRD_X25 if (dev &&
(!(dev->flags & IFF_UP) || (dev->type != ARPHRD_X25
#if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE) #if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE)
|| dev->type == ARPHRD_ETHER && dev->type != ARPHRD_ETHER
#endif #endif
)) )))
return dev; dev_put(dev);
dev_put(dev); return dev;
return NULL;
} }
/* /**
* 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(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 != NULL; route = route->next) {
if (memcmp(&route->address, addr, route->sigdigits) == 0) { read_lock_bh(&x25_route_list_lock);
if (use == NULL) {
use = route; list_for_each(entry, &x25_route_list) {
} else { rt = list_entry(entry, struct x25_route, node);
if (route->sigdigits > use->sigdigits)
use = route; if (!memcmp(&rt->address, addr, rt->sigdigits)) {
} if (!use)
use = rt;
else if (rt->sigdigits > use->sigdigits)
use = rt;
} }
} }
return (use != NULL) ? use->dev : NULL; if (use)
x25_route_hold(use);
read_unlock_bh(&x25_route_list_lock);
return use;
} }
/* /*
...@@ -181,57 +198,50 @@ struct net_device *x25_get_route(x25_address *addr) ...@@ -181,57 +198,50 @@ struct net_device *x25_get_route(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 err; int rc = -EINVAL;
switch (cmd) { if (cmd != SIOCADDRT && cmd != SIOCDELRT)
goto out;
case SIOCADDRT:
if (copy_from_user(&x25_route, arg, sizeof(struct x25_route_struct))) rc = -EFAULT;
return -EFAULT; if (copy_from_user(&rt, arg, sizeof(rt)))
if (x25_route.sigdigits < 0 || x25_route.sigdigits > 15) goto out;
return -EINVAL;
if ((dev = x25_dev_get(x25_route.device)) == NULL) rc = -EINVAL;
return -EINVAL; if (rt.sigdigits < 0 || rt.sigdigits > 15)
err = x25_add_route(&x25_route.address, x25_route.sigdigits, dev); goto out;
dev_put(dev);
return err;
case SIOCDELRT:
if (copy_from_user(&x25_route, arg, sizeof(struct x25_route_struct)))
return -EFAULT;
if (x25_route.sigdigits < 0 || x25_route.sigdigits > 15)
return -EINVAL;
if ((dev = x25_dev_get(x25_route.device)) == NULL)
return -EINVAL;
err = x25_del_route(&x25_route.address, x25_route.sigdigits, dev);
dev_put(dev);
return err;
default:
return -EINVAL;
}
return 0; dev = x25_dev_get(rt.device);
if (!dev)
goto out;
if (cmd == SIOCADDRT)
rc = x25_add_route(&rt.address, rt.sigdigits, dev);
else
rc = x25_del_route(&rt.address, rt.sigdigits, dev);
dev_put(dev);
out:
return rc;
} }
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 = 0; 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"); list_for_each(entry, &x25_route_list) {
rt = list_entry(entry, struct x25_route, node);
for (x25_route = x25_route_list; x25_route != NULL; x25_route = x25_route->next) {
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 != NULL) ? x25_route->dev->name : "???"); rt->dev ? rt->dev->name : "???");
pos = begin + len; pos = begin + len;
...@@ -244,12 +254,13 @@ int x25_routes_get_info(char *buffer, char **start, off_t offset, int length) ...@@ -244,12 +254,13 @@ 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);
if (len > length) len = length; if (len > length)
len = length;
return len; return len;
} }
...@@ -259,12 +270,13 @@ int x25_routes_get_info(char *buffer, char **start, off_t offset, int length) ...@@ -259,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 != NULL) {
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);
} }
/* /*
* X.25 Packet Layer release 002 * X.25 Packet Layer release 002
* *
* This is ALPHA test software. This code may break your machine, randomly fail to work with new * This is ALPHA test software. This code may break your machine,
* releases, misbehave and/or generally screw up. It might even work. * randomly fail to work with new releases, misbehave and/or generally
* screw up. It might even work.
* *
* This code REQUIRES 2.1.15 or higher * This code REQUIRES 2.1.15 or higher
* *
...@@ -15,7 +16,7 @@ ...@@ -15,7 +16,7 @@
* History * History
* X.25 001 Jonathan Naylor Started coding. * X.25 001 Jonathan Naylor Started coding.
* X.25 002 Jonathan Naylor Centralised disconnection processing. * X.25 002 Jonathan Naylor Centralised disconnection processing.
* mar/20/00 Daniela Squassoni Disabling/enabling of facilities * mar/20/00 Daniela Squassoni Disabling/enabling of facilities
* negotiation. * negotiation.
* jun/24/01 Arnaldo C. Melo use skb_queue_purge, cleanups * jun/24/01 Arnaldo C. Melo use skb_queue_purge, cleanups
*/ */
...@@ -46,7 +47,7 @@ ...@@ -46,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);
...@@ -64,7 +65,7 @@ void x25_clear_queues(struct sock *sk) ...@@ -64,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;
/* /*
...@@ -88,7 +89,7 @@ void x25_requeue_frames(struct sock *sk) ...@@ -88,7 +89,7 @@ void x25_requeue_frames(struct sock *sk)
* output queue. * output queue.
*/ */
while ((skb = skb_dequeue(&x25_sk(sk)->ack_queue)) != NULL) { while ((skb = skb_dequeue(&x25_sk(sk)->ack_queue)) != NULL) {
if (skb_prev == NULL) if (!skb_prev)
skb_queue_head(&sk->write_queue, skb); skb_queue_head(&sk->write_queue, skb);
else else
skb_append(skb_prev, skb); skb_append(skb_prev, skb);
...@@ -102,36 +103,35 @@ void x25_requeue_frames(struct sock *sk) ...@@ -102,36 +103,35 @@ 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;
while (vc != x25->vs) { while (vc != x25->vs) {
if (nr == vc) return 1; if (nr == vc)
return 1;
vc = (vc + 1) % modulus; vc = (vc + 1) % modulus;
} }
return nr == x25->vs ? 1 : 0; return nr == x25->vs ? 1 : 0;
} }
/* /*
* This routine is called when the packet layer internally generates a * This routine is called when the packet layer internally generates a
* control frame. * control frame.
*/ */
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];
unsigned char addresses[1 + X25_ADDR_LEN]; unsigned char addresses[1 + X25_ADDR_LEN];
unsigned char lci1, lci2; unsigned char lci1, lci2;
int len;
/* /*
* Default safe frame size. * Default safe frame size.
*/ */
len = X25_MAX_L2_LEN + X25_EXT_MIN_LEN; int len = X25_MAX_L2_LEN + X25_EXT_MIN_LEN;
/* /*
* Adjust frame size. * Adjust frame size.
...@@ -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)) {
......
/* /*
* X.25 Packet Layer release 002 * X.25 Packet Layer release 002
* *
* This is ALPHA test software. This code may break your machine, randomly fail to work with new * This is ALPHA test software. This code may break your machine,
* releases, misbehave and/or generally screw up. It might even work. * randomly fail to work with new releases, misbehave and/or generally
* screw up. It might even work.
* *
* This code REQUIRES 2.1.15 or higher * This code REQUIRES 2.1.15 or higher
* *
...@@ -60,7 +61,7 @@ void x25_stop_heartbeat(struct sock *sk) ...@@ -60,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);
...@@ -73,7 +74,7 @@ void x25_start_t2timer(struct sock *sk) ...@@ -73,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);
...@@ -86,7 +87,7 @@ void x25_start_t21timer(struct sock *sk) ...@@ -86,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);
...@@ -99,7 +100,7 @@ void x25_start_t22timer(struct sock *sk) ...@@ -99,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);
...@@ -117,7 +118,7 @@ void x25_stop_timer(struct sock *sk) ...@@ -117,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;
...@@ -130,9 +131,8 @@ static void x25_heartbeat_expiry(unsigned long param) ...@@ -130,9 +131,8 @@ static void x25_heartbeat_expiry(unsigned long param)
struct sock *sk = (struct sock *)param; struct sock *sk = (struct sock *)param;
bh_lock_sock(sk); bh_lock_sock(sk);
if (sk->lock.users) { /* can currently only occur in state 3 */ if (sk->lock.users) /* can currently only occur in state 3 */
goto restart_heartbeat; goto restart_heartbeat;
}
switch (x25_sk(sk)->state) { switch (x25_sk(sk)->state) {
...@@ -152,9 +152,9 @@ static void x25_heartbeat_expiry(unsigned long param) ...@@ -152,9 +152,9 @@ static void x25_heartbeat_expiry(unsigned long param)
x25_check_rbuf(sk); x25_check_rbuf(sk);
break; break;
} }
restart_heartbeat: restart_heartbeat:
x25_start_heartbeat(sk); x25_start_heartbeat(sk);
unlock: unlock:
bh_unlock_sock(sk); bh_unlock_sock(sk);
} }
...@@ -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) {
...@@ -194,11 +194,9 @@ static void x25_timer_expiry(unsigned long param) ...@@ -194,11 +194,9 @@ static void x25_timer_expiry(unsigned long param)
bh_lock_sock(sk); bh_lock_sock(sk);
if (sk->lock.users) { /* can currently only occur in state 3 */ if (sk->lock.users) { /* can currently only occur in state 3 */
if (x25_sk(sk)->state == X25_STATE_3) { if (x25_sk(sk)->state == X25_STATE_3)
x25_start_t2timer(sk); x25_start_t2timer(sk);
} } else
} else {
x25_do_timer_expiry(sk); x25_do_timer_expiry(sk);
}
bh_unlock_sock(sk); bh_unlock_sock(sk);
} }
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