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 @@
#include <linux/lapb.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
* in lapbeth_new_device is large enough to store the probe device name.*/
#define MAXLAPBDEV 100
static struct lapbethdev {
struct lapbethdev *next;
struct lapbethdev {
struct list_head node;
char ethname[14]; /* ether device name */
struct net_device *ethdev; /* link to ethernet device */
struct net_device axdev; /* lapbeth device (lapb#) */
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
*/
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;
for (lapbeth = lapbeth_devices; lapbeth != NULL; lapbeth = lapbeth->next)
if (lapbeth->ethdev == dev)
return &lapbeth->axdev;
read_lock(&lapbeth_devices_lock);
return NULL;
list_for_each(entry, &lapbeth_devices) {
lapbeth = list_entry(entry, struct lapbethdev, node);
if (lapbeth->ethdev == dev) {
use = lapbeth;
break;
}
}
if (use)
lapbeth_hold(use);
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 (
dev->type == ARPHRD_ETHER
&& strncmp(dev->name, "dummy", 5)
);
return dev->type == ARPHRD_ETHER && strncmp(dev->name, "dummy", 5);
}
/*
......@@ -88,35 +109,26 @@ static inline int dev_is_ethdev(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;
unsigned long flags;
save_flags(flags);
cli();
write_lock(&lapbeth_devices_lock);
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 (lapbeth_prev)
lapbeth_prev->next = lapbeth->next;
else
lapbeth_devices = lapbeth->next;
if (&lapbeth->axdev == dev)
result = 1;
unregister_netdev(&lapbeth->axdev);
dev_put(lapbeth->ethdev);
kfree(lapbeth);
list_del(&lapbeth->node);
lapbeth_put(lapbeth);
}
else
lapbeth_prev = lapbeth;
}
restore_flags(flags);
write_unlock(&lapbeth_devices_lock);
return result;
}
......@@ -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 */
dev = lapbeth_get_x25_dev(dev);
if (dev == NULL || !netif_running(dev)) {
kfree_skb(skb);
return 0;
}
lapbeth = lapbeth_get_x25_dev(dev);
lapbeth = (struct lapbethdev *) dev->priv;
if (!lapbeth)
goto drop;
if (!netif_running(&lapbeth->axdev))
goto put_drop;
lapbeth->stats.rx_packets++;
......@@ -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 */
if ((err = lapb_data_received(lapbeth, skb)) != LAPB_OK) {
kfree_skb(skb);
printk(KERN_DEBUG "lapbether: lapb_data_received err - %d\n", err);
goto put_drop;
}
lapbeth_put(lapbeth);
out:
return 0;
put_drop:
lapbeth_put(lapbeth);
drop:
kfree_skb(skb);
goto out;
}
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;
ptr = skb_push(skb, 1);
......@@ -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)
{
struct lapbethdev *lapbeth = (struct lapbethdev *) dev->priv;
int err;
struct lapbethdev *lapbeth = (struct lapbethdev *)dev->priv;
int err = -ENODEV;
/*
* 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)
*/
if (!netif_running(dev)) {
lapbeth_check_devices(dev);
kfree_skb(skb);
return -ENODEV;
goto drop;
}
switch (skb->data[0]) {
case 0x00:
err = 0;
break;
case 0x01:
if ((err = lapb_connect_request(lapbeth)) != LAPB_OK)
printk(KERN_ERR "lapbeth: lapb_connect_request error - %d\n", err);
kfree_skb(skb);
return 0;
printk(KERN_ERR "lapbeth: lapb_connect_request "
"error: %d\n", err);
goto drop_ok;
case 0x02:
if ((err = lapb_disconnect_request(lapbeth)) != LAPB_OK)
printk(KERN_ERR "lapbeth: lapb_disconnect_request err - %d\n", err);
kfree_skb(skb);
return 0;
printk(KERN_ERR "lapbeth: lapb_disconnect_request "
"err: %d\n", err);
/* Fall thru */
default:
kfree_skb(skb);
return 0;
goto drop_ok;
}
skb_pull(skb, 1);
if ((err = lapb_data_request(lapbeth, skb)) != LAPB_OK) {
printk(KERN_ERR "lapbeth: lapb_data_request error - %d\n", err);
kfree_skb(skb);
return -ENOMEM;
err = -ENOMEM;
goto drop;
}
return 0;
err = 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)
{
struct lapbethdev *lapbeth = (struct lapbethdev *) token;
struct lapbethdev *lapbeth = (struct lapbethdev *)token;
unsigned char *ptr;
struct net_device *dev;
int size;
int size = skb->len;
skb->protocol = htons(ETH_P_X25);
size = skb->len;
ptr = skb_push(skb, 2);
*ptr++ = size % 256;
......@@ -247,11 +266,11 @@ static void lapbeth_data_transmit(void *token, struct sk_buff *skb)
static void lapbeth_connected(void *token, int reason)
{
struct lapbethdev *lapbeth = (struct lapbethdev *) token;
struct sk_buff *skb;
struct lapbethdev *lapbeth = (struct lapbethdev *)token;
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");
return;
}
......@@ -269,11 +288,11 @@ static void lapbeth_connected(void *token, int reason)
static void lapbeth_disconnected(void *token, int reason)
{
struct lapbethdev *lapbeth = (struct lapbethdev *) token;
struct sk_buff *skb;
struct lapbethdev *lapbeth = (struct lapbethdev *)token;
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");
return;
}
......@@ -294,7 +313,7 @@ static void lapbeth_disconnected(void *token, int reason)
*/
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;
}
......@@ -303,7 +322,7 @@ static struct net_device_stats *lapbeth_get_stats(struct net_device *dev)
*/
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);
return 0;
}
......@@ -320,7 +339,7 @@ static int lapbeth_open(struct net_device *dev)
if (lapbeth_check_devices(dev))
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_indication = lapbeth_connected;
......@@ -340,7 +359,7 @@ static int lapbeth_open(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;
netif_stop_queue(dev);
......@@ -358,20 +377,21 @@ static int lapbeth_close(struct net_device *dev)
*/
static int lapbeth_new_device(struct net_device *dev)
{
int k;
unsigned char buf[14];
struct lapbethdev *lapbeth, *lapbeth2;
struct lapbethdev *lapbeth;
int k, rc = -ENOMEM;
if ((lapbeth = kmalloc(sizeof(struct lapbethdev), GFP_KERNEL)) == NULL)
return -ENOMEM;
if ((lapbeth = kmalloc(sizeof(struct lapbethdev), GFP_ATOMIC)) == NULL)
goto out;
memset(lapbeth, 0, sizeof(struct lapbethdev));
dev_hold(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;
SET_MODULE_OWNER(dev);
......@@ -381,24 +401,21 @@ static int lapbeth_new_device(struct net_device *dev)
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;
}
if (k == MAXLAPBDEV) {
dev_put(dev);
kfree(lapbeth);
return -ENODEV;
}
rc = -ENODEV;
if (k == MAXLAPBDEV)
goto fail;
dev->priv = (void *)lapbeth; /* pointer back */
strcpy(dev->name, buf);
if (register_netdev(dev) != 0) {
dev_put(dev);
kfree(lapbeth);
return -EIO;
}
rc = -EIO;
if (register_netdev(dev))
goto fail;
dev->hard_start_xmit = lapbeth_xmit;
dev->open = lapbeth_open;
......@@ -410,26 +427,27 @@ static int lapbeth_new_device(struct net_device *dev)
dev->mtu = 1000;
dev->addr_len = 0;
cli();
if (lapbeth_devices == NULL) {
lapbeth_devices = lapbeth;
} else {
for (lapbeth2 = lapbeth_devices; lapbeth2->next != NULL; lapbeth2 = lapbeth2->next);
lapbeth2->next = lapbeth;
}
sti();
return 0;
write_lock(&lapbeth_devices_lock);
list_add(&lapbeth->node, &lapbeth_devices);
lapbeth_hold(lapbeth);
write_unlock(&lapbeth_devices_lock);
rc = 0;
out:
return rc;
fail:
dev_put(dev);
kfree(lapbeth);
goto out;
}
/*
* 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))
return NOTIFY_DONE;
......@@ -437,18 +455,25 @@ static int lapbeth_device_event(struct notifier_block *this, unsigned long event
lapbeth_check_devices(NULL);
switch (event) {
case NETDEV_UP: /* new ethernet device -> new LAPB interface */
if (lapbeth_get_x25_dev(dev) == NULL)
case NETDEV_UP:
/*
* New ethernet device -> new LAPB interface
*/
lapbeth = lapbeth_get_x25_dev(dev);
if (lapbeth)
lapbeth_put(lapbeth);
else
lapbeth_new_device(dev);
break;
case NETDEV_GOING_DOWN:
case NETDEV_DOWN: /* ethernet device closed -> close LAPB interface */
if ((dev = lapbeth_get_x25_dev(dev)) != NULL)
dev_close(dev);
break;
lapbeth = lapbeth_get_x25_dev(dev);
default:
if (lapbeth) {
dev_close(lapbeth->ethdev);
lapbeth_put(lapbeth);
}
break;
}
......@@ -466,7 +491,7 @@ static struct notifier_block lapbeth_dev_notifier = {
.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)
{
......@@ -479,7 +504,7 @@ static int __init lapbeth_init_driver(void)
printk(banner);
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)) {
read_unlock_bh(&dev_base_lock);
lapbeth_new_device(dev);
......@@ -495,18 +520,24 @@ module_init(lapbeth_init_driver);
static void __exit lapbeth_cleanup_driver(void)
{
struct lapbethdev *lapbeth;
struct list_head *entry, *tmp;
dev_remove_pack(&lapbeth_packet_type);
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);
list_del(&lapbeth->node);
lapbeth_put(lapbeth);
}
write_unlock(&lapbeth_devices_lock);
}
module_exit(lapbeth_cleanup_driver);
MODULE_AUTHOR("Jonathan Naylor <g4klx@g4klx.demon.co.uk>");
MODULE_DESCRIPTION("The unofficial LAPB over Ethernet driver");
MODULE_LICENSE("GPL");
......@@ -39,16 +39,16 @@
* An X.121 address, it is held as ASCII text, null terminated, up to 15
* digits and a null terminator.
*/
typedef struct {
struct x25_address {
char x25_addr[16];
} x25_address;
};
/*
* Linux X.25 Address structure, used for bind, and connect mostly.
*/
struct sockaddr_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,7 +78,7 @@ struct x25_subscrip_struct {
* Routing table control structure.
*/
struct x25_route_struct {
x25_address address;
struct x25_address address;
unsigned int sigdigits;
char device[200];
};
......
......@@ -78,8 +78,8 @@ struct lapb_frame {
/*
* The per LAPB connection control structure.
*/
typedef struct lapb_cb {
struct lapb_cb *next;
struct lapb_cb {
struct list_head node;
void *token;
/* Link status fields */
......@@ -100,43 +100,45 @@ typedef struct lapb_cb {
/* FRMR control information */
struct lapb_frame frmr_data;
unsigned char frmr_type;
} lapb_cb;
atomic_t refcnt;
};
/* lapb_iface.c */
extern void lapb_connect_confirmation(lapb_cb *, int);
extern void lapb_connect_indication(lapb_cb *, int);
extern void lapb_disconnect_confirmation(lapb_cb *, int);
extern void lapb_disconnect_indication(lapb_cb *, int);
extern int lapb_data_indication(lapb_cb *, struct sk_buff *);
extern int lapb_data_transmit(lapb_cb *, struct sk_buff *);
extern void lapb_connect_confirmation(struct lapb_cb *lapb, int);
extern void lapb_connect_indication(struct lapb_cb *lapb, int);
extern void lapb_disconnect_confirmation(struct lapb_cb *lapb, int);
extern void lapb_disconnect_indication(struct lapb_cb *lapb, int);
extern int lapb_data_indication(struct lapb_cb *lapb, struct sk_buff *);
extern int lapb_data_transmit(struct lapb_cb *lapb, struct sk_buff *);
/* 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 */
extern void lapb_kick(lapb_cb *);
extern void lapb_transmit_buffer(lapb_cb *, struct sk_buff *, int);
extern void lapb_establish_data_link(lapb_cb *);
extern void lapb_enquiry_response(lapb_cb *);
extern void lapb_timeout_response(lapb_cb *);
extern void lapb_check_iframes_acked(lapb_cb *, unsigned short);
extern void lapb_check_need_response(lapb_cb *, int, int);
extern void lapb_kick(struct lapb_cb *lapb);
extern void lapb_transmit_buffer(struct lapb_cb *lapb, struct sk_buff *, int);
extern void lapb_establish_data_link(struct lapb_cb *lapb);
extern void lapb_enquiry_response(struct lapb_cb *lapb);
extern void lapb_timeout_response(struct lapb_cb *lapb);
extern void lapb_check_iframes_acked(struct lapb_cb *lapb, unsigned short);
extern void lapb_check_need_response(struct lapb_cb *lapb, int, int);
/* lapb_subr.c */
extern void lapb_clear_queues(lapb_cb *);
extern void lapb_frames_acked(lapb_cb *, unsigned short);
extern void lapb_requeue_frames(lapb_cb *);
extern int lapb_validate_nr(lapb_cb *, unsigned short);
extern void lapb_decode(lapb_cb *, struct sk_buff *, struct lapb_frame *);
extern void lapb_send_control(lapb_cb *, int, int, int);
extern void lapb_transmit_frmr(lapb_cb *);
extern void lapb_clear_queues(struct lapb_cb *lapb);
extern void lapb_frames_acked(struct lapb_cb *lapb, unsigned short);
extern void lapb_requeue_frames(struct lapb_cb *lapb);
extern int lapb_validate_nr(struct lapb_cb *lapb, unsigned short);
extern void lapb_decode(struct lapb_cb *lapb, struct sk_buff *, struct lapb_frame *);
extern void lapb_send_control(struct lapb_cb *lapb, int, int, int);
extern void lapb_transmit_frmr(struct lapb_cb *lapb);
/* lapb_timer.c */
extern void lapb_start_t1timer(lapb_cb *);
extern void lapb_start_t2timer(lapb_cb *);
extern void lapb_stop_t1timer(lapb_cb *);
extern void lapb_stop_t2timer(lapb_cb *);
extern int lapb_t1timer_running(lapb_cb *);
extern void lapb_start_t1timer(struct lapb_cb *lapb);
extern void lapb_start_t2timer(struct lapb_cb *lapb);
extern void lapb_stop_t1timer(struct lapb_cb *lapb);
extern void lapb_stop_t2timer(struct lapb_cb *lapb);
extern int lapb_t1timer_running(struct lapb_cb *lapb);
/*
* Debug levels.
......
......@@ -101,15 +101,24 @@ enum {
#define X25_MAX_FAC_LEN 20 /* Plenty to spare */
#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 *next;
x25_address address; /* Start of address range */
unsigned int sigdigits; /* Number of sig digits */
struct net_device *dev; /* More than one for MLP */
struct list_head node;
struct x25_address address;
unsigned int sigdigits;
struct net_device *dev;
atomic_t refcnt;
};
struct x25_neigh {
struct x25_neigh *next;
struct list_head node;
struct net_device *dev;
unsigned int state;
unsigned int extended;
......@@ -117,10 +126,11 @@ struct x25_neigh {
unsigned long t20;
struct timer_list t20timer;
unsigned long global_facil_mask;
atomic_t refcnt;
};
typedef struct {
x25_address source_addr, dest_addr;
struct x25_opt {
struct x25_address source_addr, dest_addr;
struct x25_neigh *neighbour;
unsigned int lci;
unsigned char state, condition, qbitincl, intflag;
......@@ -137,9 +147,9 @@ typedef struct {
struct x25_facilities facilities;
struct x25_calluserdata calluserdata;
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 */
extern int sysctl_x25_restart_request_timeout;
......@@ -148,8 +158,10 @@ extern int sysctl_x25_reset_request_timeout;
extern int sysctl_x25_clear_request_timeout;
extern int sysctl_x25_ack_holdback_timeout;
extern int x25_addr_ntoa(unsigned char *, x25_address *, x25_address *);
extern int x25_addr_aton(unsigned char *, x25_address *, x25_address *);
extern int x25_addr_ntoa(unsigned char *, struct 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 struct sock *x25_find_socket(unsigned int, struct x25_neigh *);
extern void x25_destroy_socket(struct sock *);
......@@ -188,19 +200,42 @@ extern int x25_subscr_ioctl(unsigned int, void *);
extern struct x25_neigh *x25_get_neigh(struct net_device *);
extern void x25_link_free(void);
/* x25_neigh.c */
static __inline__ void x25_neigh_hold(struct x25_neigh *nb)
{
atomic_inc(&nb->refcnt);
}
static __inline__ void x25_neigh_put(struct x25_neigh *nb)
{
if (atomic_dec_and_test(&nb->refcnt))
kfree(nb);
}
/* x25_out.c */
extern int x25_output(struct sock *, struct sk_buff *);
extern void x25_kick(struct sock *);
extern void x25_enquiry_response(struct sock *);
/* 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 void x25_route_device_down(struct net_device *);
extern int x25_route_ioctl(unsigned int, void *);
extern int x25_routes_get_info(char *, char **, off_t, int);
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 */
extern void x25_clear_queues(struct sock *);
extern void x25_frames_acked(struct sock *, unsigned short);
......
......@@ -39,87 +39,93 @@
#include <linux/init.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
* the MOD count code.
*/
static void lapb_free_cb(lapb_cb *lapb)
static void lapb_free_cb(struct lapb_cb *lapb)
{
kfree(lapb);
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.
*/
static void lapb_remove_cb(lapb_cb *lapb)
static void __lapb_remove_cb(struct lapb_cb *lapb)
{
lapb_cb *s;
unsigned long flags;
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;
if (lapb->node.next) {
list_del(&lapb->node);
lapb_put(lapb);
}
s = s->next;
}
restore_flags(flags);
}
/*
* 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;
save_flags(flags); cli();
lapb->next = lapb_list;
lapb_list = lapb;
restore_flags(flags);
list_add(&lapb->node, &lapb_list);
lapb_hold(lapb);
}
/*
* Convert the integer token used by the device driver into a pointer
* 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 (lapb->token == token)
return lapb;
if (use)
lapb_hold(use);
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.
*/
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)
return NULL;
if (!lapb)
goto out;
MOD_INC_USE_COUNT;
......@@ -137,55 +143,73 @@ static lapb_cb *lapb_create_cb(void)
lapb->mode = LAPB_DEFAULT_MODE;
lapb->window = LAPB_DEFAULT_WINDOW;
lapb->state = LAPB_STATE_0;
atomic_set(&lapb->refcnt, 1);
out:
return lapb;
}
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)
return LAPB_BADTOKEN;
lapb = __lapb_tokentostruct(token);
if (lapb) {
lapb_put(lapb);
goto out;
}
if ((lapb = lapb_create_cb()) == NULL)
return LAPB_NOMEM;
lapb = lapb_create_cb();
rc = LAPB_NOMEM;
if (!lapb)
goto out;
lapb->token = token;
lapb->callbacks = *callbacks;
lapb_insert_cb(lapb);
__lapb_insert_cb(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)
{
lapb_cb *lapb;
struct lapb_cb *lapb;
int rc = LAPB_BADTOKEN;
if ((lapb = lapb_tokentostruct(token)) == NULL)
return LAPB_BADTOKEN;
write_unlock_bh(&lapb_list_lock);
lapb = __lapb_tokentostruct(token);
if (!lapb)
goto out;
lapb_stop_t1timer(lapb);
lapb_stop_t2timer(lapb);
lapb_clear_queues(lapb);
lapb_remove_cb(lapb);
__lapb_remove_cb(lapb);
lapb_free_cb(lapb);
return LAPB_OK;
lapb_put(lapb);
rc = LAPB_OK;
out:
write_unlock_bh(&lapb_list_lock);
return rc;
}
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)
return LAPB_BADTOKEN;
if (!lapb)
goto out;
parms->t1 = lapb->t1 / HZ;
parms->t2 = lapb->t2 / HZ;
......@@ -205,33 +229,29 @@ int lapb_getparms(void *token, struct lapb_parms_struct *parms)
else
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)
{
lapb_cb *lapb;
if ((lapb = lapb_tokentostruct(token)) == NULL)
return LAPB_BADTOKEN;
int rc = LAPB_BADTOKEN;
struct lapb_cb *lapb = lapb_tokentostruct(token);
if (parms->t1 < 1)
return LAPB_INVALUE;
if (!lapb)
goto out;
if (parms->t2 < 1)
return LAPB_INVALUE;
if (parms->n2 < 1)
return LAPB_INVALUE;
rc = LAPB_INVALUE;
if (parms->t1 < 1 || parms->t2 < 1 || parms->n2 < 1)
goto out_put;
if (lapb->state == LAPB_STATE_0) {
if (parms->mode & LAPB_EXTENDED) {
if (parms->window < 1 || parms->window > 127)
return LAPB_INVALUE;
} else {
if (parms->window < 1 || parms->window > 7)
return LAPB_INVALUE;
}
if (((parms->mode & LAPB_EXTENDED) &&
(parms->window < 1 || parms->window > 127)) ||
(parms->window < 1 || parms->window > 7))
goto out_put;
lapb->mode = parms->mode;
lapb->window = parms->window;
......@@ -241,45 +261,55 @@ int lapb_setparms(void *token, struct lapb_parms_struct *parms)
lapb->t2 = parms->t2 * HZ;
lapb->n2 = parms->n2;
return LAPB_OK;
rc = LAPB_OK;
out_put:
lapb_put(lapb);
out:
return rc;
}
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)
return LAPB_BADTOKEN;
if (!lapb)
goto out;
switch (lapb->state) {
case LAPB_STATE_1:
return LAPB_OK;
case LAPB_STATE_3:
case LAPB_STATE_4:
return LAPB_CONNECTED;
}
rc = LAPB_OK;
if (lapb->state == LAPB_STATE_1)
goto out_put;
rc = LAPB_CONNECTED;
if (lapb->state == LAPB_STATE_3 || lapb->state == LAPB_STATE_4)
goto out_put;
lapb_establish_data_link(lapb);
#if LAPB_DEBUG > 0
printk(KERN_DEBUG "lapb: (%p) S0 -> S1\n", lapb->token);
#endif
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)
{
lapb_cb *lapb;
struct lapb_cb *lapb = lapb_tokentostruct(token);
int rc = LAPB_BADTOKEN;
if ((lapb = lapb_tokentostruct(token)) == NULL)
return LAPB_BADTOKEN;
if (!lapb)
goto out;
switch (lapb->state) {
case LAPB_STATE_0:
return LAPB_NOTCONNECTED;
rc = LAPB_NOTCONNECTED;
goto out_put;
case LAPB_STATE_1:
#if LAPB_DEBUG > 1
......@@ -291,10 +321,12 @@ int lapb_disconnect_request(void *token)
lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND);
lapb->state = LAPB_STATE_0;
lapb_start_t1timer(lapb);
return LAPB_NOTCONNECTED;
rc = LAPB_NOTCONNECTED;
goto out_put;
case LAPB_STATE_2:
return LAPB_OK;
rc = LAPB_OK;
goto out_put;
}
lapb_clear_queues(lapb);
......@@ -311,77 +343,87 @@ int lapb_disconnect_request(void *token)
printk(KERN_DEBUG "lapb: (%p) S3 -> S2\n", lapb->token);
#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)
{
lapb_cb *lapb;
struct lapb_cb *lapb = lapb_tokentostruct(token);
int rc = LAPB_BADTOKEN;
if ((lapb = lapb_tokentostruct(token)) == NULL)
return LAPB_BADTOKEN;
if (!lapb)
goto out;
rc = LAPB_NOTCONNECTED;
if (lapb->state != LAPB_STATE_3 && lapb->state != LAPB_STATE_4)
return LAPB_NOTCONNECTED;
goto out_put;
skb_queue_tail(&lapb->write_queue, skb);
lapb_kick(lapb);
return LAPB_OK;
rc = LAPB_OK;
out_put:
lapb_put(lapb);
out:
return rc;
}
int lapb_data_received(void *token, struct sk_buff *skb)
{
lapb_cb *lapb;
if ((lapb = lapb_tokentostruct(token)) == NULL)
return LAPB_BADTOKEN;
struct lapb_cb *lapb = lapb_tokentostruct(token);
int rc = LAPB_BADTOKEN;
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)
(lapb->callbacks.connect_confirmation)(lapb->token, reason);
if (lapb->callbacks.connect_confirmation)
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)
(lapb->callbacks.connect_indication)(lapb->token, reason);
if (lapb->callbacks.connect_indication)
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)
(lapb->callbacks.disconnect_confirmation)(lapb->token, reason);
if (lapb->callbacks.disconnect_confirmation)
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)
(lapb->callbacks.disconnect_indication)(lapb->token, reason);
if (lapb->callbacks.disconnect_indication)
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) {
return (lapb->callbacks.data_indication)(lapb->token, skb);
}
if (lapb->callbacks.data_indication)
return lapb->callbacks.data_indication(lapb->token, skb);
kfree_skb(skb);
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;
if (lapb->callbacks.data_transmit != NULL) {
(lapb->callbacks.data_transmit)(lapb->token, skb);
if (lapb->callbacks.data_transmit) {
lapb->callbacks.data_transmit(lapb->token, skb);
used = 1;
}
......
......@@ -40,26 +40,33 @@
* State machine for state 0, Disconnected State.
* 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) {
case LAPB_SABM:
#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
if (lapb->mode & LAPB_EXTENDED) {
#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
lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE);
lapb_send_control(lapb, LAPB_DM, frame->pf,
LAPB_RESPONSE);
} else {
#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
#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
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_t2timer(lapb);
lapb->state = LAPB_STATE_3;
......@@ -74,16 +81,20 @@ static void lapb_state0_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
case LAPB_SABME:
#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
if (lapb->mode & LAPB_EXTENDED) {
#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
#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
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_t2timer(lapb);
lapb->state = LAPB_STATE_3;
......@@ -95,18 +106,23 @@ static void lapb_state0_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
lapb_connect_indication(lapb, LAPB_OK);
} else {
#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
lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE);
lapb_send_control(lapb, LAPB_DM, frame->pf,
LAPB_RESPONSE);
}
break;
case LAPB_DISC:
#if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S0 RX DISC(%d)\n", lapb->token, frame->pf);
printk(KERN_DEBUG "lapb: (%p) S0 TX UA(%d)\n", lapb->token, frame->pf);
printk(KERN_DEBUG "lapb: (%p) S0 RX DISC(%d)\n",
lapb->token, frame->pf);
printk(KERN_DEBUG "lapb: (%p) S0 TX UA(%d)\n",
lapb->token, frame->pf);
#endif
lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE);
lapb_send_control(lapb, LAPB_UA, frame->pf,
LAPB_RESPONSE);
break;
default:
......@@ -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.
* 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) {
case LAPB_SABM:
#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
if (lapb->mode & LAPB_EXTENDED) {
#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
lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE);
lapb_send_control(lapb, LAPB_DM, frame->pf,
LAPB_RESPONSE);
} else {
#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
lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE);
lapb_send_control(lapb, LAPB_UA, frame->pf,
LAPB_RESPONSE);
}
break;
case LAPB_SABME:
#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
if (lapb->mode & LAPB_EXTENDED) {
#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
lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE);
lapb_send_control(lapb, LAPB_UA, frame->pf,
LAPB_RESPONSE);
} else {
#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
lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE);
lapb_send_control(lapb, LAPB_DM, frame->pf,
LAPB_RESPONSE);
}
break;
case LAPB_DISC:
#if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S1 RX DISC(%d)\n", lapb->token, frame->pf);
printk(KERN_DEBUG "lapb: (%p) S1 TX DM(%d)\n", lapb->token, frame->pf);
printk(KERN_DEBUG "lapb: (%p) S1 RX DISC(%d)\n",
lapb->token, frame->pf);
printk(KERN_DEBUG "lapb: (%p) S1 TX DM(%d)\n",
lapb->token, frame->pf);
#endif
lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE);
lapb_send_control(lapb, LAPB_DM, frame->pf,
LAPB_RESPONSE);
break;
case LAPB_UA:
#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
if (frame->pf) {
#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
lapb_stop_t1timer(lapb);
lapb_stop_t2timer(lapb);
......@@ -187,11 +219,13 @@ static void lapb_state1_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
case LAPB_DM:
#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
if (frame->pf) {
#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
lapb_clear_queues(lapb);
lapb->state = LAPB_STATE_0;
......@@ -200,9 +234,6 @@ static void lapb_state1_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
lapb_disconnect_indication(lapb, LAPB_REFUSED);
}
break;
default:
break;
}
kfree_skb(skb);
......@@ -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.
* 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) {
case LAPB_SABM:
case LAPB_SABME:
#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 TX DM(%d)\n", lapb->token, frame->pf);
printk(KERN_DEBUG "lapb: (%p) S2 RX {SABM,SABME}(%d)\n",
lapb->token, frame->pf);
printk(KERN_DEBUG "lapb: (%p) S2 TX DM(%d)\n",
lapb->token, frame->pf);
#endif
lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE);
lapb_send_control(lapb, LAPB_DM, frame->pf,
LAPB_RESPONSE);
break;
case LAPB_DISC:
#if LAPB_DEBUG > 1
printk(KERN_DEBUG "lapb: (%p) S2 RX DISC(%d)\n", lapb->token, frame->pf);
printk(KERN_DEBUG "lapb: (%p) S2 TX UA(%d)\n", lapb->token, frame->pf);
printk(KERN_DEBUG "lapb: (%p) S2 RX DISC(%d)\n",
lapb->token, frame->pf);
printk(KERN_DEBUG "lapb: (%p) S2 TX UA(%d)\n",
lapb->token, frame->pf);
#endif
lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE);
lapb_send_control(lapb, LAPB_UA, frame->pf,
LAPB_RESPONSE);
break;
case LAPB_UA:
#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
if (frame->pf) {
#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
lapb->state = LAPB_STATE_0;
lapb_start_t1timer(lapb);
......@@ -249,16 +289,19 @@ static void lapb_state2_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
case LAPB_DM:
#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
if (frame->pf) {
#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
lapb->state = LAPB_STATE_0;
lapb_start_t1timer(lapb);
lapb_stop_t2timer(lapb);
lapb_disconnect_confirmation(lapb, LAPB_NOTCONNECTED);
lapb_disconnect_confirmation(lapb,
LAPB_NOTCONNECTED);
}
break;
......@@ -267,13 +310,14 @@ static void lapb_state2_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
case LAPB_RNR:
case LAPB_RR:
#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 DM(%d)\n", lapb->token, frame->pf);
printk(KERN_DEBUG "lapb: (%p) S2 RX {I,REJ,RNR,RR}"
"(%d)\n", lapb->token, frame->pf);
printk(KERN_DEBUG "lapb: (%p) S2 RX DM(%d)\n",
lapb->token, frame->pf);
#endif
if (frame->pf) lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE);
break;
default:
if (frame->pf)
lapb_send_control(lapb, LAPB_DM, frame->pf,
LAPB_RESPONSE);
break;
}
......@@ -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.
* 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 modulus;
modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS : LAPB_SMODULUS;
int modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS :
LAPB_SMODULUS;
switch (frame->type) {
case LAPB_SABM:
#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
if (lapb->mode & LAPB_EXTENDED) {
#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
lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE);
lapb_send_control(lapb, LAPB_DM, frame->pf,
LAPB_RESPONSE);
} else {
#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
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_t2timer(lapb);
lapb->condition = 0x00;
......@@ -319,13 +368,16 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
case LAPB_SABME:
#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
if (lapb->mode & LAPB_EXTENDED) {
#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
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_t2timer(lapb);
lapb->condition = 0x00;
......@@ -336,21 +388,26 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
lapb_requeue_frames(lapb);
} else {
#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
lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE);
lapb_send_control(lapb, LAPB_DM, frame->pf,
LAPB_RESPONSE);
}
break;
case LAPB_DISC:
#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
#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
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_stop_t2timer(lapb);
lapb->state = LAPB_STATE_0;
......@@ -359,10 +416,12 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
case LAPB_DM:
#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
#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
lapb_clear_queues(lapb);
lapb->state = LAPB_STATE_0;
......@@ -373,7 +432,8 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
case LAPB_RNR:
#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
lapb->condition |= LAPB_PEER_RX_BUSY_CONDITION;
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_
lapb->frmr_type = LAPB_FRMR_Z;
lapb_transmit_frmr(lapb);
#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
lapb_start_t1timer(lapb);
lapb_stop_t2timer(lapb);
......@@ -395,7 +456,8 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
case LAPB_RR:
#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
lapb->condition &= ~LAPB_PEER_RX_BUSY_CONDITION;
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_
lapb->frmr_type = LAPB_FRMR_Z;
lapb_transmit_frmr(lapb);
#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
lapb_start_t1timer(lapb);
lapb_stop_t2timer(lapb);
......@@ -417,7 +480,8 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
case LAPB_REJ:
#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
lapb->condition &= ~LAPB_PEER_RX_BUSY_CONDITION;
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_
lapb->frmr_type = LAPB_FRMR_Z;
lapb_transmit_frmr(lapb);
#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
lapb_start_t1timer(lapb);
lapb_stop_t2timer(lapb);
......@@ -442,14 +507,16 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
case LAPB_I:
#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
if (!lapb_validate_nr(lapb, frame->nr)) {
lapb->frmr_data = *frame;
lapb->frmr_type = LAPB_FRMR_Z;
lapb_transmit_frmr(lapb);
#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
lapb_start_t1timer(lapb);
lapb_stop_t2timer(lapb);
......@@ -457,11 +524,11 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
lapb->n2count = 0;
break;
}
if (lapb->condition & LAPB_PEER_RX_BUSY_CONDITION) {
if (lapb->condition & LAPB_PEER_RX_BUSY_CONDITION)
lapb_frames_acked(lapb, frame->nr);
} else {
else
lapb_check_iframes_acked(lapb, frame->nr);
}
if (frame->ns == lapb->vr) {
int cn;
cn = lapb_data_indication(lapb, skb);
......@@ -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
* a frame lost on the wire.
*/
if(cn == NET_RX_DROP){
printk(KERN_DEBUG "LAPB: rx congestion\n");
if (cn == NET_RX_DROP) {
printk(KERN_DEBUG
"LAPB: rx congestion\n");
break;
}
lapb->vr = (lapb->vr + 1) % modulus;
lapb->condition &= ~LAPB_REJECT_CONDITION;
if (frame->pf) {
if (frame->pf)
lapb_enquiry_response(lapb);
} else {
if (!(lapb->condition & LAPB_ACK_PENDING_CONDITION)) {
else {
if (!(lapb->condition &
LAPB_ACK_PENDING_CONDITION)) {
lapb->condition |= LAPB_ACK_PENDING_CONDITION;
lapb_start_t2timer(lapb);
}
......@@ -493,10 +562,14 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
lapb_enquiry_response(lapb);
} else {
#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
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;
}
}
......@@ -504,11 +577,15 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
case LAPB_FRMR:
#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
lapb_establish_data_link(lapb);
#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
lapb_requeue_frames(lapb);
lapb->state = LAPB_STATE_1;
......@@ -516,7 +593,8 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
case LAPB_ILLEGAL:
#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
lapb->frmr_data = *frame;
lapb->frmr_type = LAPB_FRMR_W;
......@@ -529,9 +607,6 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
lapb->state = LAPB_STATE_4;
lapb->n2count = 0;
break;
default:
break;
}
if (!queued)
......@@ -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.
* 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) {
case LAPB_SABM:
#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
if (lapb->mode & LAPB_EXTENDED) {
#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
lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE);
lapb_send_control(lapb, LAPB_DM, frame->pf,
LAPB_RESPONSE);
} else {
#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
#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
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_t2timer(lapb);
lapb->state = LAPB_STATE_3;
......@@ -576,16 +658,20 @@ static void lapb_state4_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
case LAPB_SABME:
#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
if (lapb->mode & LAPB_EXTENDED) {
#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
#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
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_t2timer(lapb);
lapb->state = LAPB_STATE_3;
......@@ -597,14 +683,13 @@ static void lapb_state4_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
lapb_connect_indication(lapb, LAPB_OK);
} else {
#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
lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE);
lapb_send_control(lapb, LAPB_DM, frame->pf,
LAPB_RESPONSE);
}
break;
default:
break;
}
kfree_skb(skb);
......@@ -613,7 +698,7 @@ static void lapb_state4_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
/*
* 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;
......@@ -621,20 +706,15 @@ void lapb_data_input(lapb_cb *lapb, struct sk_buff *skb)
switch (lapb->state) {
case LAPB_STATE_0:
lapb_state0_machine(lapb, skb, &frame);
break;
lapb_state0_machine(lapb, skb, &frame); break;
case LAPB_STATE_1:
lapb_state1_machine(lapb, skb, &frame);
break;
lapb_state1_machine(lapb, skb, &frame); break;
case LAPB_STATE_2:
lapb_state2_machine(lapb, skb, &frame);
break;
lapb_state2_machine(lapb, skb, &frame); break;
case LAPB_STATE_3:
lapb_state3_machine(lapb, skb, &frame);
break;
lapb_state3_machine(lapb, skb, &frame); break;
case LAPB_STATE_4:
lapb_state4_machine(lapb, skb, &frame);
break;
lapb_state4_machine(lapb, skb, &frame); break;
}
lapb_kick(lapb);
......
......@@ -38,50 +38,48 @@
* 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.
*/
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;
if (skb == NULL)
if (!skb)
return;
if (lapb->mode & LAPB_EXTENDED) {
frame = skb_push(skb, 2);
frame[0] = LAPB_I;
frame[0] |= (lapb->vs << 1);
frame[1] = (poll_bit) ? LAPB_EPF : 0;
frame[1] |= (lapb->vr << 1);
frame[0] |= lapb->vs << 1;
frame[1] = poll_bit ? LAPB_EPF : 0;
frame[1] |= lapb->vr << 1;
} else {
frame = skb_push(skb, 1);
*frame = LAPB_I;
*frame |= (poll_bit) ? LAPB_SPF : 0;
*frame |= (lapb->vr << 5);
*frame |= (lapb->vs << 1);
*frame |= poll_bit ? LAPB_SPF : 0;
*frame |= lapb->vr << 5;
*frame |= lapb->vs << 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
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;
unsigned short modulus, start, end;
modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS : LAPB_SMODULUS;
start = (skb_peek(&lapb->ack_queue) == NULL) ? lapb->va : lapb->vs;
start = !skb_peek(&lapb->ack_queue) ? lapb->va : lapb->vs;
end = (lapb->va + lapb->window) % modulus;
if (!(lapb->condition & LAPB_PEER_RX_BUSY_CONDITION) &&
start != end &&
skb_peek(&lapb->write_queue) != NULL) {
start != end && skb_peek(&lapb->write_queue)) {
lapb->vs = start;
/*
......@@ -95,7 +93,7 @@ void lapb_kick(lapb_cb *lapb)
break;
}
if (skb->sk != NULL)
if (skb->sk)
skb_set_owner_w(skbn, skb->sk);
/*
......@@ -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;
......@@ -152,26 +150,30 @@ void lapb_transmit_buffer(lapb_cb *lapb, struct sk_buff *skb, int type)
}
#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
if (!lapb_data_transmit(lapb, 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->n2count = 0;
if (lapb->mode & LAPB_EXTENDED) {
#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
lapb_send_control(lapb, LAPB_SABME, LAPB_POLLON, LAPB_COMMAND);
} else {
#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
lapb_send_control(lapb, LAPB_SABM, LAPB_POLLON, LAPB_COMMAND);
}
......@@ -180,10 +182,11 @@ void lapb_establish_data_link(lapb_cb *lapb)
lapb_stop_t2timer(lapb);
}
void lapb_enquiry_response(lapb_cb *lapb)
void lapb_enquiry_response(struct lapb_cb *lapb)
{
#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
lapb_send_control(lapb, LAPB_RR, LAPB_POLLON, LAPB_RESPONSE);
......@@ -191,32 +194,30 @@ void lapb_enquiry_response(lapb_cb *lapb)
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
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
lapb_send_control(lapb, LAPB_RR, LAPB_POLLOFF, LAPB_RESPONSE);
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) {
lapb_frames_acked(lapb, nr);
lapb_stop_t1timer(lapb);
lapb->n2count = 0;
} else {
if (lapb->va != nr) {
} else if (lapb->va != nr) {
lapb_frames_acked(lapb, nr);
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)
lapb_enquiry_response(lapb);
......
......@@ -36,7 +36,7 @@
/*
* 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->ack_queue);
......@@ -47,7 +47,7 @@ void lapb_clear_queues(lapb_cb *lapb)
* acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the
* 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;
int modulus;
......@@ -57,16 +57,15 @@ void lapb_frames_acked(lapb_cb *lapb, unsigned short nr)
/*
* Remove all the ack-ed frames from the ack queue.
*/
if (lapb->va != nr) {
while (skb_peek(&lapb->ack_queue) != NULL && lapb->va != nr) {
if (lapb->va != nr)
while (skb_peek(&lapb->ack_queue) && lapb->va != nr) {
skb = skb_dequeue(&lapb->ack_queue);
kfree_skb(skb);
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;
......@@ -76,7 +75,7 @@ void lapb_requeue_frames(lapb_cb *lapb)
* possibility of an empty output queue.
*/
while ((skb = skb_dequeue(&lapb->ack_queue)) != NULL) {
if (skb_prev == NULL)
if (!skb_prev)
skb_queue_head(&lapb->write_queue, skb);
else
skb_append(skb_prev, skb);
......@@ -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
* 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;
int modulus;
......@@ -96,25 +95,27 @@ int lapb_validate_nr(lapb_cb *lapb, unsigned short nr)
modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS : LAPB_SMODULUS;
while (vc != lapb->vs) {
if (nr == vc) return 1;
if (nr == vc)
return 1;
vc = (vc + 1) % modulus;
}
if (nr == lapb->vs) return 1;
return 0;
return nr == lapb->vs;
}
/*
* This routine is the centralised routine for parsing the control
* 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;
#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
if (lapb->mode & LAPB_MLP) {
......@@ -146,22 +147,31 @@ void lapb_decode(lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame)
skb_pull(skb, 1);
if (lapb->mode & LAPB_EXTENDED) {
if ((skb->data[0] & LAPB_S) == 0) {
frame->type = LAPB_I; /* I frame - carries NR/NS/PF */
if (!(skb->data[0] & LAPB_S)) {
/*
* I frame - carries NR/NS/PF
*/
frame->type = LAPB_I;
frame->ns = (skb->data[0] >> 1) & 0x7F;
frame->nr = (skb->data[1] >> 1) & 0x7F;
frame->pf = skb->data[1] & LAPB_EPF;
frame->control[0] = skb->data[0];
frame->control[1] = skb->data[1];
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->nr = (skb->data[1] >> 1) & 0x7F;
frame->pf = skb->data[1] & LAPB_EPF;
frame->control[0] = skb->data[0];
frame->control[1] = skb->data[1];
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->pf = skb->data[0] & LAPB_SPF;
frame->control[0] = skb->data[0];
......@@ -169,16 +179,25 @@ void lapb_decode(lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame)
skb_pull(skb, 1);
}
} else {
if ((skb->data[0] & LAPB_S) == 0) {
frame->type = LAPB_I; /* I frame - carries NR/NS/PF */
if (!(skb->data[0] & LAPB_S)) {
/*
* I frame - carries NR/NS/PF
*/
frame->type = LAPB_I;
frame->ns = (skb->data[0] >> 1) & 0x07;
frame->nr = (skb->data[0] >> 5) & 0x07;
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->nr = (skb->data[0] >> 5) & 0x07;
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->pf = skb->data[0] & LAPB_SPF;
}
......@@ -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
* 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;
unsigned char *dptr;
......@@ -209,17 +229,17 @@ void lapb_send_control(lapb_cb *lapb, int frametype, int poll_bit, int type)
if ((frametype & LAPB_U) == LAPB_U) {
dptr = skb_put(skb, 1);
*dptr = frametype;
*dptr |= (poll_bit) ? LAPB_SPF : 0;
*dptr |= poll_bit ? LAPB_SPF : 0;
} else {
dptr = skb_put(skb, 2);
dptr[0] = frametype;
dptr[1] = (lapb->vr << 1);
dptr[1] |= (poll_bit) ? LAPB_EPF : 0;
dptr[1] |= poll_bit ? LAPB_EPF : 0;
}
} else {
dptr = skb_put(skb, 1);
*dptr = frametype;
*dptr |= (poll_bit) ? LAPB_SPF : 0;
*dptr |= poll_bit ? LAPB_SPF : 0;
if ((frametype & LAPB_U) == LAPB_S) /* S frames carry NR */
*dptr |= (lapb->vr << 5);
}
......@@ -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
* the LAPB control block.
*/
void lapb_transmit_frmr(lapb_cb *lapb)
void lapb_transmit_frmr(struct lapb_cb *lapb)
{
struct sk_buff *skb;
unsigned char *dptr;
......@@ -254,7 +274,10 @@ void lapb_transmit_frmr(lapb_cb *lapb)
*dptr++ = lapb->frmr_type;
#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
} else {
dptr = skb_put(skb, 4);
......@@ -268,7 +291,9 @@ void lapb_transmit_frmr(lapb_cb *lapb)
*dptr++ = lapb->frmr_type;
#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
}
......
......@@ -37,7 +37,7 @@
static void lapb_t1timer_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);
......@@ -48,7 +48,7 @@ void lapb_start_t1timer(lapb_cb *lapb)
add_timer(&lapb->t1timer);
}
void lapb_start_t2timer(lapb_cb *lapb)
void lapb_start_t2timer(struct lapb_cb *lapb)
{
del_timer(&lapb->t2timer);
......@@ -59,24 +59,24 @@ void lapb_start_t2timer(lapb_cb *lapb)
add_timer(&lapb->t2timer);
}
void lapb_stop_t1timer(lapb_cb *lapb)
void lapb_stop_t1timer(struct lapb_cb *lapb)
{
del_timer(&lapb->t1timer);
}
void lapb_stop_t2timer(lapb_cb *lapb)
void lapb_stop_t2timer(struct lapb_cb *lapb)
{
del_timer(&lapb->t2timer);
}
int lapb_t1timer_running(lapb_cb *lapb)
int lapb_t1timer_running(struct lapb_cb *lapb)
{
return timer_pending(&lapb->t1timer);
}
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) {
lapb->condition &= ~LAPB_ACK_PENDING_CONDITION;
......@@ -86,7 +86,7 @@ static void lapb_t2timer_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) {
......
/*
* X.25 Packet Layer release 002
*
* This is ALPHA test software. This code may break your machine, randomly fail to work with new
* releases, misbehave and/or generally screw up. It might even work.
* This is ALPHA test software. This code may break your machine,
* 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
*
......@@ -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_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 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;
char *called, *calling;
......@@ -101,13 +104,13 @@ int x25_addr_ntoa(unsigned char *p, x25_address *called_addr, x25_address *calli
}
}
*called = '\0';
*calling = '\0';
*called = *calling = '\0';
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;
char *called, *calling;
......@@ -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)
{
struct sock *s;
unsigned long flags;
save_flags(flags);
cli();
write_lock_bh(&x25_list_lock);
if ((s = x25_list) == sk) {
if ((s = x25_list) == sk)
x25_list = s->next;
restore_flags(flags);
return;
}
while (s != NULL && s->next != NULL) {
else while (s && s->next) {
if (s->next == sk) {
s->next = sk->next;
restore_flags(flags);
return;
sock_put(sk);
break;
}
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)
{
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)
x25_disconnect(s, ENETUNREACH, 0, 0);
write_unlock_bh(&x25_list_lock);
}
/*
* 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 x25_neigh *neigh;
struct net_device *dev = ptr;
struct x25_neigh *nb;
if (dev->type == ARPHRD_X25
#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
x25_link_device_up(dev);
break;
case NETDEV_GOING_DOWN:
if ((neigh = x25_get_neigh(dev)))
x25_terminate_link(neigh);
nb = x25_get_neigh(dev);
if (nb) {
x25_terminate_link(nb);
x25_neigh_put(nb);
}
break;
case NETDEV_DOWN:
x25_kill_by_device(dev);
......@@ -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)
{
unsigned long flags;
save_flags(flags);
cli();
write_lock_bh(&x25_list_lock);
sk->next = x25_list;
x25_list = sk;
restore_flags(flags);
sock_hold(sk);
write_unlock_bh(&x25_list_lock);
}
/*
* Find a socket that wants to accept the Call Request we just
* 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;
save_flags(flags);
cli();
read_lock_bh(&x25_list_lock);
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) ||
strcmp(addr->x25_addr, null_x25_address.x25_addr) == 0) &&
s->state == TCP_LISTEN) {
restore_flags(flags);
return s;
}
}
!strcmp(addr->x25_addr, null_x25_address.x25_addr)) &&
s->state == TCP_LISTEN)
break;
restore_flags(flags);
return NULL;
if (s)
sock_hold(s);
read_unlock_bh(&x25_list_lock);
return s;
}
/*
* Find a connected X.25 socket given my LCI and neighbour.
*/
struct sock *x25_find_socket(unsigned int lci, struct x25_neigh *neigh)
struct sock *__x25_find_socket(unsigned int lci, struct x25_neigh *nb)
{
struct sock *s;
unsigned long flags;
save_flags(flags);
cli();
for (s = x25_list; s != NULL; s = s->next) {
if (x25_sk(s)->lci == lci && x25_sk(s)->neighbour == neigh) {
restore_flags(flags);
for (s = x25_list; s; s = s->next)
if (x25_sk(s)->lci == lci && x25_sk(s)->neighbour == nb)
break;
if (s)
sock_hold(s);
return s;
}
}
}
restore_flags(flags);
return NULL;
struct sock *x25_find_socket(unsigned int lci, struct x25_neigh *nb)
{
struct sock *s;
read_lock_bh(&x25_list_lock);
s = __x25_find_socket(lci, nb);
read_unlock_bh(&x25_list_lock);
return s;
}
/*
* 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;
struct sock *sk;
read_lock_bh(&x25_list_lock);
while (x25_find_socket(lci, neigh) != NULL) {
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;
}
......@@ -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 */
{
struct sk_buff *skb;
unsigned long flags;
save_flags(flags);
cli();
sock_hold(sk);
lock_sock(sk);
x25_stop_heartbeat(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
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 */
init_timer(&sk->timer);
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
sk_free(sk);
MOD_DEC_USE_COUNT;
}
restore_flags(flags);
release_sock(sk);
sock_put(sk);
}
/*
......@@ -362,79 +368,75 @@ 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,
char *optval, int optlen)
{
struct sock *sk = sock->sk;
int opt;
struct sock *sk = sock->sk;
int rc = -ENOPROTOOPT;
if (level != SOL_X25)
return -ENOPROTOOPT;
if (level != SOL_X25 || optname != X25_QBITINCL)
goto out;
rc = -EINVAL;
if (optlen < sizeof(int))
return-EINVAL;
goto out;
rc = -EFAULT;
if (get_user(opt, (int *)optval))
return -EFAULT;
switch (optname) {
case X25_QBITINCL:
x25_sk(sk)->qbitincl = opt ? 1 : 0;
return 0;
goto out;
default:
return -ENOPROTOOPT;
}
x25_sk(sk)->qbitincl = !!opt;
rc = 0;
out:
return rc;
}
static int x25_getsockopt(struct socket *sock, int level, int optname,
char *optval, int *optlen)
{
struct sock *sk = sock->sk;
int val = 0;
int len;
int val, len, rc = -ENOPROTOOPT;
if (level != SOL_X25)
return -ENOPROTOOPT;
if (level != SOL_X25 || optname != X25_QBITINCL)
goto out;
rc = -EFAULT;
if (get_user(len, optlen))
return -EFAULT;
switch (optname) {
case X25_QBITINCL:
val = x25_sk(sk)->qbitincl;
break;
default:
return -ENOPROTOOPT;
}
goto out;
len = min_t(unsigned int, len, sizeof(int));
rc = -EINVAL;
if (len < 0)
return -EINVAL;
goto out;
rc = -EFAULT;
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)
{
struct sock *sk = sock->sk;
int rc = -EOPNOTSUPP;
if (sk->state != TCP_LISTEN) {
memset(&x25_sk(sk)->dest_addr, 0, X25_ADDR_LEN);
sk->max_ack_backlog = backlog;
sk->state = TCP_LISTEN;
return 0;
rc = 0;
}
return -EOPNOTSUPP;
return rc;
}
static struct sock *x25_alloc_socket(void)
{
struct sock *sk;
x25_cb *x25;
struct x25_opt *x25;
MOD_INC_USE_COUNT;
......@@ -445,7 +447,7 @@ static struct sock *x25_alloc_socket(void)
if (!x25)
goto frees;
memset(x25, 0x00, sizeof(*x25));
memset(x25, 0, sizeof(*x25));
x25->sk = sk;
......@@ -455,23 +457,28 @@ static struct sock *x25_alloc_socket(void)
skb_queue_head_init(&x25->fragment_queue);
skb_queue_head_init(&x25->interrupt_in_queue);
skb_queue_head_init(&x25->interrupt_out_queue);
out: return sk;
frees: sk_free(sk);
out:
return sk;
frees:
sk_free(sk);
sk = NULL;
decmod: MOD_DEC_USE_COUNT;
decmod:
MOD_DEC_USE_COUNT;
goto out;
}
static int x25_create(struct socket *sock, int protocol)
{
struct sock *sk;
x25_cb *x25;
struct x25_opt *x25;
int rc = -ESOCKTNOSUPPORT;
if (sock->type != SOCK_SEQPACKET || protocol != 0)
return -ESOCKTNOSUPPORT;
if (sock->type != SOCK_SEQPACKET || protocol)
goto out;
rc = -ENOMEM;
if ((sk = x25_alloc_socket()) == NULL)
return -ENOMEM;
goto out;
x25 = x25_sk(sk);
......@@ -495,20 +502,21 @@ static int x25_create(struct socket *sock, int protocol)
x25->facilities.pacsize_out = X25_DEFAULT_PACKET_SIZE;
x25->facilities.throughput = X25_DEFAULT_THROUGHPUT;
x25->facilities.reverse = X25_DEFAULT_REVERSE;
return 0;
rc = 0;
out:
return rc;
}
static struct sock *x25_make_new(struct sock *osk)
{
struct sock *sk;
x25_cb *x25, *ox25;
struct sock *sk = NULL;
struct x25_opt *x25, *ox25;
if (osk->type != SOCK_SEQPACKET)
return NULL;
goto out;
if ((sk = x25_alloc_socket()) == NULL)
return NULL;
goto out;
x25 = x25_sk(sk);
......@@ -533,16 +541,17 @@ static struct sock *x25_make_new(struct sock *osk)
x25->qbitincl = ox25->qbitincl;
init_timer(&x25->timer);
out:
return sk;
}
static int x25_release(struct socket *sock)
{
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);
......@@ -567,14 +576,11 @@ static int x25_release(struct socket *sock)
sk->dead = 1;
sk->destroy = 1;
break;
default:
break;
}
sock->sk = NULL;
sk->socket = NULL; /* Not used, but we should do this */
out:
return 0;
}
......@@ -583,68 +589,98 @@ static int x25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
struct sock *sk = sock->sk;
struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr;
if (sk->zapped == 0)
return -EINVAL;
if (addr_len != sizeof(struct sockaddr_x25))
return -EINVAL;
if (addr->sx25_family != AF_X25)
if (!sk->zapped ||
addr_len != sizeof(struct sockaddr_x25) ||
addr->sx25_family != AF_X25)
return -EINVAL;
x25_sk(sk)->source_addr = addr->sx25_addr;
x25_insert_socket(sk);
sk->zapped = 0;
SOCK_DEBUG(sk, "x25_bind: socket is bound\n");
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)
{
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 net_device *dev;
struct x25_route *rt;
int rc = 0;
lock_sock(sk);
if (sk->state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) {
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) {
sock->state = SS_UNCONNECTED;
return -ECONNREFUSED;
goto out;
}
rc = -EISCONN; /* No reconnect on a seqpacket socket */
if (sk->state == TCP_ESTABLISHED)
return -EISCONN; /* No reconnect on a seqpacket socket */
goto out;
sk->state = TCP_CLOSE;
sock->state = SS_UNCONNECTED;
if (addr_len != sizeof(struct sockaddr_x25))
return -EINVAL;
if (addr->sx25_family != AF_X25)
return -EINVAL;
rc = -EINVAL;
if (addr_len != sizeof(struct sockaddr_x25) ||
addr->sx25_family != AF_X25)
goto out;
if ((dev = x25_get_route(&addr->sx25_addr)) == NULL)
return -ENETUNREACH;
rc = -ENETUNREACH;
rt = x25_get_route(&addr->sx25_addr);
if (!rt)
goto out;
if ((x25->neighbour = x25_get_neigh(dev)) == NULL)
return -ENETUNREACH;
x25->neighbour = x25_get_neigh(rt->dev);
if (!x25->neighbour)
goto out_put_route;
x25_limit_facilities(&x25->facilities, x25->neighbour);
if ((x25->lci = x25_new_lci(x25->neighbour)) == 0)
return -ENETUNREACH;
x25->lci = x25_new_lci(x25->neighbour);
if (!x25->lci)
goto out_put_neigh;
rc = -EINVAL;
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))
memset(&x25->source_addr, '\0', X25_ADDR_LEN);
......@@ -663,74 +699,80 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len
x25_start_t21timer(sk);
/* Now the loop */
rc = -EINPROGRESS;
if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
return -EINPROGRESS;
goto out_put_neigh;
cli(); /* To avoid races on the sleep */
/*
* A Clear Request or timeout or failed routing will go to closed.
*/
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 */
}
rc = x25_wait_for_connection_establishment(sk);
if (rc)
goto out_put_neigh;
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)
{
struct sock *sk;
struct sock *sk = sock->sk;
struct sock *newsk;
struct sk_buff *skb;
int rc = -EINVAL;
if ((sk = sock->sk) == NULL)
return -EINVAL;
if (!sk || sk->state != TCP_LISTEN)
goto out;
rc = -EOPNOTSUPP;
if (sk->type != SOCK_SEQPACKET)
return -EOPNOTSUPP;
if (sk->state != TCP_LISTEN)
return -EINVAL;
/*
* The write queue this time is holding sockets ready to use
* hooked into the CALL INDICATION we saved
*/
do {
cli();
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);
goto out;
rc = x25_wait_for_data(sk, sk->rcvtimeo);
if (rc)
goto out;
skb = skb_dequeue(&sk->receive_queue);
rc = -EINVAL;
if (!skb->sk)
goto out;
newsk = skb->sk;
newsk->pair = NULL;
newsk->socket = newsock;
newsk->sleep = &newsock->wait;
sti();
/* Now attach up the new socket */
skb->sk = NULL;
......@@ -738,38 +780,38 @@ static int x25_accept(struct socket *sock, struct socket *newsock, int flags)
sk->ack_backlog--;
newsock->sk = newsk;
newsock->state = SS_CONNECTED;
return 0;
rc = 0;
out:
return rc;
}
static int x25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer)
{
struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)uaddr;
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)
return -ENOTCONN;
sx25->sx25_addr = x25->dest_addr;
} else {
} else
sx25->sx25_addr = x25->source_addr;
}
sx25->sx25_family = AF_X25;
*uaddr_len = sizeof(struct sockaddr_x25);
*uaddr_len = sizeof(*sx25);
return 0;
}
int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned int lci)
int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb, unsigned int lci)
{
struct sock *sk;
struct sock *make;
x25_cb *makex25;
x25_address source_addr, dest_addr;
struct x25_opt *makex25;
struct x25_address source_addr, dest_addr;
struct x25_facilities facilities;
int len;
int len, rc;
/*
* 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
/*
* We can't accept the Call Request.
*/
if (sk == NULL || sk->ack_backlog == sk->max_ack_backlog) {
x25_transmit_clear_request(neigh, lci, 0x01);
return 0;
}
if (!sk || sk->ack_backlog == sk->max_ack_backlog)
goto out_clear_request;
/*
* Try to reach a compromise on the requested facilities.
*/
if ((len = x25_negotiate_facilities(skb, sk, &facilities)) == -1) {
x25_transmit_clear_request(neigh, lci, 0x01);
return 0;
}
if ((len = x25_negotiate_facilities(skb, sk, &facilities)) == -1)
goto out_sock_put;
/*
* current neighbour/link might impose additional limits
* on certain facilties
*/
x25_limit_facilities(&facilities,neigh);
x25_limit_facilities(&facilities, nb);
/*
* Try to create a new socket.
*/
if ((make = x25_make_new(sk)) == NULL) {
x25_transmit_clear_request(neigh, lci, 0x01);
return 0;
}
make = x25_make_new(sk);
if (!make)
goto out_sock_put;
/*
* 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
makex25->lci = lci;
makex25->dest_addr = dest_addr;
makex25->source_addr = source_addr;
makex25->neighbour = neigh;
makex25->neighbour = nb;
makex25->facilities = facilities;
makex25->vc_facil_mask = x25_sk(sk)->vc_facil_mask;
......@@ -857,55 +894,70 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned i
if (!sk->dead)
sk->data_ready(sk, skb->len);
return 1;
rc = 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)
{
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;
int err;
struct sockaddr_x25 sx25;
struct sk_buff *skb;
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))
return -EINVAL;
goto out;
/* we currently don't support segmented records at the user interface */
if (!(msg->msg_flags & (MSG_EOR|MSG_OOB)))
return -EINVAL;
goto out;
rc = -EADDRNOTAVAIL;
if (sk->zapped)
return -EADDRNOTAVAIL;
goto out;
rc = -EPIPE;
if (sk->shutdown & SEND_SHUTDOWN) {
send_sig(SIGPIPE, current, 0);
return -EPIPE;
goto out;
}
if (x25->neighbour == NULL)
return -ENETUNREACH;
rc = -ENETUNREACH;
if (!x25->neighbour)
goto out;
if (usx25 != NULL) {
if (usx25) {
rc = -EINVAL;
if (msg->msg_namelen < sizeof(sx25))
return -EINVAL;
sx25 = *usx25;
goto out;
memcpy(&sx25, usx25, sizeof(sx25));
rc = -EISCONN;
if (strcmp(x25->dest_addr.x25_addr, sx25.sx25_addr.x25_addr))
return -EISCONN;
goto out;
rc = -EINVAL;
if (sx25.sx25_family != AF_X25)
return -EINVAL;
goto out;
} else {
/*
* FIXME 1003.1g - if the socket is like this because
* it has become closed (not started closed) we ought
* to SIGPIPE, EPIPE;
*/
rc = -ENOTCONN;
if (sk->state != TCP_ESTABLISHED)
return -ENOTCONN;
goto out;
sx25.sx25_family = AF_X25;
sx25.sx25_addr = x25->dest_addr;
......@@ -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;
if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
return err;
skb = sock_alloc_send_skb(sk, size, noblock, &rc);
if (!skb)
goto out;
X25_SKB_CB(skb)->flags = msg->msg_flags;
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
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
......@@ -985,22 +1040,19 @@ 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: Transmitting buffer\n");
if (sk->state != TCP_ESTABLISHED) {
kfree_skb(skb);
return -ENOTCONN;
}
rc = -ENOTCONN;
if (sk->state != TCP_ESTABLISHED)
goto out_kfree_skb;
if (msg->msg_flags & MSG_OOB) {
if (msg->msg_flags & MSG_OOB)
skb_queue_tail(&x25->interrupt_out_queue, skb);
} else {
else {
len = x25_output(sk, skb);
if(len<0){
if (len < 0)
kfree_skb(skb);
} else {
if (x25->qbitincl)
else if (x25->qbitincl)
len++;
}
}
/*
* lock_sock() is currently only used to serialize this x25_kick()
......@@ -1019,31 +1071,37 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
lock_sock(sk);
x25_kick(sk);
release_sock(sk);
return len;
rc = 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;
x25_cb *x25 = x25_sk(sk);
struct x25_opt *x25 = x25_sk(sk);
struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)msg->msg_name;
int copied, qbit;
struct sk_buff *skb;
unsigned char *asmptr;
int er;
int rc = -ENOTCONN;
/*
* This works for seqpacket too. The receiver has ordered the queue for
* us! We do one quick check first though
*/
if (sk->state != TCP_ESTABLISHED)
return -ENOTCONN;
goto out;
if (flags & MSG_OOB) {
rc = -EINVAL;
if (sk->urginline || !skb_peek(&x25->interrupt_in_queue))
return -EINVAL;
goto out;
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
msg->msg_flags |= MSG_OOB;
} else {
/* Now we can treat all alike */
if ((skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &er)) == NULL)
return er;
skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &rc);
if (!skb)
goto out;
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
/* Currently, each datagram always contains a complete record */
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_addr = x25->dest_addr;
}
msg->msg_namelen = sizeof(struct sockaddr_x25);
skb_free_datagram(sk, skb);
lock_sock(sk);
x25_check_rbuf(sk);
release_sock(sk);
return copied;
rc = 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)
{
struct sock *sk = sock->sk;
x25_cb *x25 = x25_sk(sk);
struct x25_opt *x25 = x25_sk(sk);
int rc;
switch (cmd) {
case TIOCOUTQ: {
......@@ -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);
if (amount < 0)
amount = 0;
return put_user(amount, (unsigned int *)arg);
rc = put_user(amount, (unsigned int *)arg);
break;
}
case TIOCINQ: {
struct sk_buff *skb;
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)
amount = skb->len;
return put_user(amount, (unsigned int *)arg);
rc = put_user(amount, (unsigned int *)arg);
break;
}
case SIOCGSTAMP:
if (sk != NULL) {
if (sk->stamp.tv_sec == 0)
return -ENOENT;
return copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0;
if (sk) {
rc = -ENOENT;
if (!sk->stamp.tv_sec)
break;
rc = copy_to_user((void *)arg, &sk->stamp,
sizeof(struct timeval)) ? -EFAULT : 0;
}
return -EINVAL;
rc = -EINVAL;
break;
case SIOCGIFADDR:
case SIOCSIFADDR:
case SIOCGIFDSTADDR:
......@@ -1145,74 +1216,90 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
case SIOCSIFNETMASK:
case SIOCGIFMETRIC:
case SIOCSIFMETRIC:
return -EINVAL;
rc = -EINVAL;
break;
case SIOCADDRT:
case SIOCDELRT:
if (!capable(CAP_NET_ADMIN)) return -EPERM;
return x25_route_ioctl(cmd, (void *)arg);
rc = -EPERM;
if (!capable(CAP_NET_ADMIN))
break;
rc = x25_route_ioctl(cmd, (void *)arg);
break;
case SIOCX25GSUBSCRIP:
return x25_subscr_ioctl(cmd, (void *)arg);
rc = x25_subscr_ioctl(cmd, (void *)arg);
break;
case SIOCX25SSUBSCRIP:
if (!capable(CAP_NET_ADMIN)) return -EPERM;
return x25_subscr_ioctl(cmd, (void *)arg);
rc = -EPERM;
if (!capable(CAP_NET_ADMIN))
break;
rc = x25_subscr_ioctl(cmd, (void *)arg);
break;
case SIOCX25GFACILITIES: {
struct x25_facilities facilities;
facilities = x25->facilities;
return copy_to_user((void *)arg, &facilities, sizeof(facilities)) ? -EFAULT : 0;
struct x25_facilities fac = x25->facilities;
rc = copy_to_user((void *)arg, &fac, sizeof(fac)) ? -EFAULT : 0;
break;
}
case SIOCX25SFACILITIES: {
struct x25_facilities facilities;
rc = -EFAULT;
if (copy_from_user(&facilities, (void *)arg, sizeof(facilities)))
return -EFAULT;
break;
rc = -EINVAL;
if (sk->state != TCP_LISTEN && sk->state != TCP_CLOSE)
return -EINVAL;
if (facilities.pacsize_in < X25_PS16 || facilities.pacsize_in > X25_PS4096)
return -EINVAL;
if (facilities.pacsize_out < X25_PS16 || facilities.pacsize_out > X25_PS4096)
return -EINVAL;
if (facilities.winsize_in < 1 || facilities.winsize_in > 127)
return -EINVAL;
if (facilities.throughput < 0x03 || facilities.throughput > 0xDD)
return -EINVAL;
if (facilities.reverse != 0 && facilities.reverse != 1)
return -EINVAL;
break;
if (facilities.pacsize_in < X25_PS16 ||
facilities.pacsize_in > X25_PS4096)
break;
if (facilities.pacsize_out < X25_PS16 ||
facilities.pacsize_out > X25_PS4096)
break;
if (facilities.winsize_in < 1 ||
facilities.winsize_in > 127)
break;
if (facilities.throughput < 0x03 ||
facilities.throughput > 0xDD)
break;
if (facilities.reverse && facilities.reverse != 1)
break;
x25->facilities = facilities;
return 0;
rc = 0;
break;
}
case SIOCX25GCALLUSERDATA: {
struct x25_calluserdata calluserdata;
calluserdata = x25->calluserdata;
return copy_to_user((void *)arg, &calluserdata, sizeof(calluserdata)) ? -EFAULT : 0;
struct x25_calluserdata cud = x25->calluserdata;
rc = copy_to_user((void *)arg, &cud, sizeof(cud)) ? -EFAULT : 0;
break;
}
case SIOCX25SCALLUSERDATA: {
struct x25_calluserdata calluserdata;
rc = -EFAULT;
if (copy_from_user(&calluserdata, (void *)arg, sizeof(calluserdata)))
return -EFAULT;
break;
rc = -EINVAL;
if (calluserdata.cudlength > X25_MAX_CUD_LEN)
return -EINVAL;
break;
x25->calluserdata = calluserdata;
return 0;
rc = 0;
break;
}
case SIOCX25GCAUSEDIAG: {
struct x25_causediag 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:
return dev_ioctl(cmd, (void *)arg);
rc = dev_ioctl(cmd, (void *)arg);
break;
}
/*NOTREACHED*/
return 0;
return rc;
}
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 net_device *dev;
const char *devname;
int len = 0;
off_t pos = 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 != NULL; s = s->next) {
x25_cb *x25 = x25_sk(s);
for (s = x25_list; s; s = s->next) {
struct x25_opt *x25 = x25_sk(s);
if (!x25->neighbour || (dev = x25->neighbour->dev) == NULL)
devname = "???";
else
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,
!x25->source_addr.x25_addr[0] ? "*" :
......@@ -1254,7 +1342,7 @@ static int x25_get_info(char *buffer, char **start, off_t offset, int length)
x25->t23 / HZ,
atomic_read(&s->wmem_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;
......@@ -1267,14 +1355,15 @@ static int x25_get_info(char *buffer, char **start, off_t offset, int length)
break;
}
sti();
read_unlock_bh(&x25_list_lock);
*start = buffer + (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 = {
......@@ -1313,17 +1402,20 @@ static struct packet_type x25_packet_type = {
};
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;
for( s=x25_list; s != NULL; s=s->next){
if (x25_sk(s)->neighbour == neigh)
write_lock_bh(&x25_list_lock);
for (s = x25_list; s; s = s->next)
if (x25_sk(s)->neighbour == nb)
x25_disconnect(s, ENETUNREACH, 0, 0);
}
write_unlock_bh(&x25_list_lock);
}
static int __init x25_init(void)
......@@ -1351,7 +1443,7 @@ static int __init x25_init(void)
* Register any pre existing devices.
*/
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 defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE)
|| dev->type == ARPHRD_ETHER
......
......@@ -13,38 +13,88 @@
#include <linux/init.h>
#include <net/x25.h>
static int min_timer[] = {1 * HZ};
static int max_timer[] = {300 * HZ};
static int min_timer[] = { 1 * HZ };
static int max_timer[] = { 300 * HZ };
static struct ctl_table_header *x25_table_header;
static ctl_table x25_table[] = {
{NET_X25_RESTART_REQUEST_TIMEOUT, "restart_request_timeout",
&sysctl_x25_restart_request_timeout, sizeof(int), 0644, NULL,
&proc_dointvec_minmax, &sysctl_intvec, NULL, &min_timer, &max_timer},
{NET_X25_CALL_REQUEST_TIMEOUT, "call_request_timeout",
&sysctl_x25_call_request_timeout, sizeof(int), 0644, NULL,
&proc_dointvec_minmax, &sysctl_intvec, NULL, &min_timer, &max_timer},
{NET_X25_RESET_REQUEST_TIMEOUT, "reset_request_timeout",
&sysctl_x25_reset_request_timeout, sizeof(int), 0644, NULL,
&proc_dointvec_minmax, &sysctl_intvec, NULL, &min_timer, &max_timer},
{NET_X25_CLEAR_REQUEST_TIMEOUT, "clear_request_timeout",
&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",
&sysctl_x25_ack_holdback_timeout, sizeof(int), 0644, NULL,
&proc_dointvec_minmax, &sysctl_intvec, NULL, &min_timer, &max_timer},
{0}
static struct ctl_table x25_table[] = {
{
.ctl_name = NET_X25_RESTART_REQUEST_TIMEOUT,
.procname = "restart_request_timeout",
.data = &sysctl_x25_restart_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_CALL_REQUEST_TIMEOUT,
.procname = "call_request_timeout",
.data = &sysctl_x25_call_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_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[] = {
{NET_X25, "x25", NULL, 0, 0555, x25_table},
{0}
static struct ctl_table x25_dir_table[] = {
{
.ctl_name = NET_X25,
.procname = "x25",
.mode = 0555,
.child = x25_table,
},
{ 0, },
};
static ctl_table x25_root_table[] = {
{CTL_NET, "net", NULL, 0, 0555, x25_dir_table},
{0}
static struct ctl_table x25_root_table[] = {
{
.ctl_name = CTL_NET,
.procname = "net",
.mode = 0555,
.child = x25_dir_table,
},
{ 0, },
};
void __init x25_register_sysctl(void)
......
......@@ -44,7 +44,7 @@
#include <linux/if_arp.h>
#include <net/x25.h>
static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *neigh)
static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *nb)
{
struct sock *sk;
unsigned short frametype;
......@@ -58,14 +58,14 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *neigh)
* frame.
*/
if (lci == 0) {
x25_link_control(skb, neigh, frametype);
x25_link_control(skb, nb, frametype);
return 0;
}
/*
* Find an existing socket.
*/
if ((sk = x25_find_socket(lci, neigh)) != NULL) {
if ((sk = x25_find_socket(lci, nb)) != NULL) {
int queued = 1;
skb->h.raw = skb->data;
......@@ -83,91 +83,87 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *neigh)
* Is is a Call Request ? if so process it.
*/
if (frametype == X25_CALL_REQUEST)
return x25_rx_call_request(skb, neigh, lci);
return x25_rx_call_request(skb, nb, lci);
/*
* Its not a Call Request, nor is it a control frame.
* Let caller throw it away.
*/
/*
x25_transmit_clear_request(neigh, lci, 0x0D);
x25_transmit_clear_request(nb, lci, 0x0D);
*/
printk(KERN_DEBUG "x25_receive_data(): unknown frame type %2x\n",frametype);
return 0;
}
int x25_lapb_receive_frame(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype)
int x25_lapb_receive_frame(struct sk_buff *skb, struct net_device *dev,
struct packet_type *ptype)
{
struct x25_neigh *neigh;
int queued;
struct x25_neigh *nb;
skb->sk = NULL;
/*
* Packet received from unrecognised device, throw it away.
*/
if ((neigh = x25_get_neigh(dev)) == NULL) {
nb = x25_get_neigh(dev);
if (!nb) {
printk(KERN_DEBUG "X.25: unknown neighbour - %s\n", dev->name);
kfree_skb(skb);
return 0;
goto drop;
}
switch (skb->data[0]) {
case 0x00:
skb_pull(skb, 1);
queued = x25_receive_data(skb, neigh);
if( ! queued )
/* We need to free the skb ourselves because
* net_bh() won't care about our return code.
*/
kfree_skb(skb);
return 0;
if (x25_receive_data(skb, nb)) {
x25_neigh_put(nb);
goto out;
}
break;
case 0x01:
x25_link_established(neigh);
kfree_skb(skb);
return 0;
x25_link_established(nb);
break;
case 0x02:
x25_link_terminated(neigh);
kfree_skb(skb);
return 0;
case 0x03:
kfree_skb(skb);
return 0;
default:
x25_link_terminated(nb);
break;
}
x25_neigh_put(nb);
drop:
kfree_skb(skb);
out:
return 0;
}
}
int x25_llc_receive_frame(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype)
int x25_llc_receive_frame(struct sk_buff *skb, struct net_device *dev,
struct packet_type *ptype)
{
struct x25_neigh *neigh;
struct x25_neigh *nb;
int rc = 0;
skb->sk = NULL;
/*
* Packet received from unrecognised device, throw it away.
*/
if ((neigh = x25_get_neigh(dev)) == NULL) {
nb = x25_get_neigh(dev);
if (!nb) {
printk(KERN_DEBUG "X.25: unknown_neighbour - %s\n", dev->name);
kfree_skb(skb);
return 0;
} else {
rc = x25_receive_data(skb, nb);
x25_neigh_put(nb);
}
return x25_receive_data(skb, neigh);
return rc;
}
void x25_establish_link(struct x25_neigh *neigh)
void x25_establish_link(struct x25_neigh *nb)
{
struct sk_buff *skb;
unsigned char *ptr;
switch (neigh->dev->type) {
switch (nb->dev->type) {
case ARPHRD_X25:
if ((skb = alloc_skb(1, GFP_ATOMIC)) == NULL) {
printk(KERN_ERR "x25_dev: out of memory\n");
......@@ -186,47 +182,44 @@ void x25_establish_link(struct x25_neigh *neigh)
}
skb->protocol = htons(ETH_P_X25);
skb->dev = neigh->dev;
skb->dev = nb->dev;
dev_queue_xmit(skb);
}
void x25_terminate_link(struct x25_neigh *neigh)
void x25_terminate_link(struct x25_neigh *nb)
{
struct sk_buff *skb;
unsigned char *ptr;
switch (neigh->dev->type) {
case ARPHRD_X25:
if ((skb = alloc_skb(1, GFP_ATOMIC)) == NULL) {
printk(KERN_ERR "x25_dev: out of memory\n");
return;
}
ptr = skb_put(skb, 1);
*ptr = 0x02;
break;
#if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE)
case ARPHRD_ETHER:
if (nb->dev->type == ARPHRD_ETHER)
return;
#endif
default:
if (nb->dev->type != ARPHRD_X25)
return;
skb = alloc_skb(1, GFP_ATOMIC);
if (!skb) {
printk(KERN_ERR "x25_dev: out of memory\n");
return;
}
skb->protocol = htons(ETH_P_X25);
skb->dev = neigh->dev;
ptr = skb_put(skb, 1);
*ptr = 0x02;
skb->protocol = htons(ETH_P_X25);
skb->dev = nb->dev;
dev_queue_xmit(skb);
}
void x25_send_frame(struct sk_buff *skb, struct x25_neigh *neigh)
void x25_send_frame(struct sk_buff *skb, struct x25_neigh *nb)
{
unsigned char *dptr;
skb->nh.raw = skb->data;
switch (neigh->dev->type) {
switch (nb->dev->type) {
case ARPHRD_X25:
dptr = skb_push(skb, 1);
*dptr = 0x00;
......@@ -243,7 +236,7 @@ void x25_send_frame(struct sk_buff *skb, struct x25_neigh *neigh)
}
skb->protocol = htons(ETH_P_X25);
skb->dev = neigh->dev;
skb->dev = nb->dev;
dev_queue_xmit(skb);
}
/*
* X.25 Packet Layer release 002
*
* This is ALPHA test software. This code may break your machine, randomly fail to work with new
* releases, misbehave and/or generally screw up. It might even work.
* This is ALPHA test software. This code may break your machine,
* 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
*
......@@ -42,12 +43,13 @@
* Parse a set of facilities into the facilities structure. Unrecognised
* 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 int len = *p++;
len = *p++;
*vc_fac_mask = 0;
while (len > 0) {
......@@ -55,7 +57,7 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
case X25_FAC_CLASS_A:
switch (*p) {
case X25_FAC_REVERSE:
facilities->reverse = (p[1] & 0x01);
facilities->reverse = p[1] & 0x01;
*vc_fac_mask |= X25_MASK_REVERSE;
break;
case X25_FAC_THROUGHPUT:
......@@ -63,13 +65,14 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
*vc_fac_mask |= X25_MASK_THROUGHPUT;
break;
default:
printk(KERN_DEBUG "X.25: unknown facility %02X, value %02X\n", p[0], p[1]);
printk(KERN_DEBUG "X.25: unknown facility "
"%02X, value %02X\n",
p[0], p[1]);
break;
}
p += 2;
len -= 2;
break;
case X25_FAC_CLASS_B:
switch (*p) {
case X25_FAC_PACKET_SIZE:
......@@ -83,21 +86,25 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
*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]);
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]);
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]);
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,
/*
* 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;
int len;
if (facil_mask == 0) {
buffer [0] = 0; /* length of the facilities field in call_req or call_accept packets */
if (!facil_mask) {
/*
* Length of the facilities field in call_req or
* call_accept packets
*/
buffer[0] = 0;
len = 1; /* 1 byte for the length field */
return len;
}
if ((facilities->reverse != 0) && (facil_mask & X25_MASK_REVERSE)) {
if (facilities->reverse && (facil_mask & X25_MASK_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++ = 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++ = (facilities->pacsize_in == 0) ? facilities->pacsize_out : facilities->pacsize_in;
*p++ = (facilities->pacsize_out == 0) ? facilities->pacsize_in : facilities->pacsize_out;
*p++ = 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++ = (facilities->winsize_in == 0) ? facilities->winsize_out : facilities->winsize_in;
*p++ = (facilities->winsize_out == 0) ? facilities->winsize_in : facilities->winsize_out;
*p++ = facilities->winsize_in ? : facilities->winsize_out;
*p++ = facilities->winsize_out ? : facilities->winsize_in;
}
len = p - buffer;
......@@ -154,39 +169,37 @@ int x25_create_facilities(unsigned char *buffer, struct x25_facilities *faciliti
*
* 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_facilities *ours;
struct x25_opt *x25 = x25_sk(sk);
struct x25_facilities *ours = &x25->facilities;
struct x25_facilities theirs;
int len;
memset(&theirs, 0x00, sizeof(struct x25_facilities));
ours = &x25->facilities;
*new = *ours;
memset(&theirs, 0, sizeof(theirs));
memcpy(new, ours, sizeof(*new));
len = x25_parse_facilities(skb, &theirs, &x25->vc_facil_mask);
/*
* 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");
return -1;
}
new->reverse = theirs.reverse;
if (theirs.throughput != 0) {
if (theirs.throughput) {
if (theirs.throughput < ours->throughput) {
SOCK_DEBUG(sk, "X.25: throughput negotiated down");
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) {
SOCK_DEBUG(sk, "X.25: packet size inwards negotiated down");
new->pacsize_in = theirs.pacsize_in;
......@@ -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) {
SOCK_DEBUG(sk, "X.25: window size inwards negotiated down");
new->winsize_in = theirs.winsize_in;
......@@ -216,15 +229,15 @@ int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk, struct x25_fa
* currently attached x25 link.
*/
void x25_limit_facilities(struct x25_facilities *facilities,
struct x25_neigh *neighbour)
struct x25_neigh *nb)
{
if( ! neighbour->extended ){
if( facilities->winsize_in > 7 ){
if (!nb->extended) {
if (facilities->winsize_in > 7) {
printk(KERN_DEBUG "X.25: incoming winsize limited to 7\n");
facilities->winsize_in = 7;
}
if( facilities->winsize_out > 7 ){
if (facilities->winsize_out > 7) {
facilities->winsize_out = 7;
printk( KERN_DEBUG "X.25: outgoing winsize limited to 7\n");
}
......
/*
* X.25 Packet Layer release 002
*
* This is ALPHA test software. This code may break your machine, randomly fail to work with new
* releases, misbehave and/or generally screw up. It might even work.
* This is ALPHA test software. This code may break your machine,
* 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
*
......@@ -47,7 +48,7 @@
static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
{
struct sk_buff *skbo, *skbn = skb;
x25_cb *x25 = x25_sk(sk);
struct x25_opt *x25 = x25_sk(sk);
if (more) {
x25->fraglen += skb->len;
......@@ -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_queue_tail(&sk->receive_queue, skbn);
if (!sk->dead)
sk->data_ready(sk,skbn->len);
sk->data_ready(sk, skbn->len);
return 0;
}
......@@ -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)
{
x25_address source_addr, dest_addr;
struct x25_address source_addr, dest_addr;
switch (frametype) {
case X25_CALL_ACCEPTED: {
x25_cb *x25 = x25_sk(sk);
struct x25_opt *x25 = x25_sk(sk);
x25_stop_timer(sk);
x25->condition = 0x00;
......@@ -178,7 +179,7 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
{
int queued = 0;
int modulus;
x25_cb *x25 = x25_sk(sk);
struct x25_opt *x25 = x25_sk(sk);
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
case X25_RESET_REQUEST:
x25_write_internal(sk, 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->condition = 0x00;
......@@ -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 */
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;
if (x25->state == X25_STATE_0)
......@@ -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 queued;
int queued = x25_process_rx_frame(sk, skb);
queued = x25_process_rx_frame(sk,skb);
if(!queued) kfree_skb(skb);
if (!queued)
kfree_skb(skb);
return 0;
}
/*
* X.25 Packet Layer release 002
*
* This is ALPHA test software. This code may break your machine, randomly fail to work with new
* releases, misbehave and/or generally screw up. It might even work.
* This is ALPHA test software. This code may break your machine,
* 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
*
......@@ -42,98 +43,102 @@
#include <linux/init.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);
/*
* 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;
neigh->t20timer.function = &x25_t20timer_expiry;
neigh->t20timer.expires = jiffies + neigh->t20;
nb->t20timer.data = (unsigned long)nb;
nb->t20timer.function = &x25_t20timer_expiry;
nb->t20timer.expires = jiffies + nb->t20;
add_timer(&neigh->t20timer);
add_timer(&nb->t20timer);
}
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.
*/
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;
int confirm;
switch (frametype) {
case X25_RESTART_REQUEST:
confirm = !x25_t20timer_pending(neigh);
x25_stop_t20timer(neigh);
neigh->state = X25_LINK_STATE_3;
if (confirm) x25_transmit_restart_confirmation(neigh);
confirm = !x25_t20timer_pending(nb);
x25_stop_t20timer(nb);
nb->state = X25_LINK_STATE_3;
if (confirm)
x25_transmit_restart_confirmation(nb);
break;
case X25_RESTART_CONFIRMATION:
x25_stop_t20timer(neigh);
neigh->state = X25_LINK_STATE_3;
x25_stop_t20timer(nb);
nb->state = X25_LINK_STATE_3;
break;
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;
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;
}
if (neigh->state == X25_LINK_STATE_3) {
while ((skbn = skb_dequeue(&neigh->queue)) != NULL)
x25_send_frame(skbn, neigh);
}
if (nb->state == X25_LINK_STATE_3)
while ((skbn = skb_dequeue(&nb->queue)) != NULL)
x25_send_frame(skbn, nb);
}
/*
* 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;
int len;
len = X25_MAX_L2_LEN + X25_STD_MIN_LEN + 2;
int len = X25_MAX_L2_LEN + X25_STD_MIN_LEN + 2;
struct sk_buff *skb = alloc_skb(len, GFP_ATOMIC);
if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
if (!skb)
return;
skb_reserve(skb, X25_MAX_L2_LEN);
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++ = X25_RESTART_REQUEST;
*dptr++ = 0x00;
......@@ -141,108 +146,104 @@ void x25_transmit_restart_request(struct x25_neigh *neigh)
skb->sk = NULL;
x25_send_frame(skb, neigh);
x25_send_frame(skb, nb);
}
/*
* 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;
int len;
len = X25_MAX_L2_LEN + X25_STD_MIN_LEN;
int len = X25_MAX_L2_LEN + X25_STD_MIN_LEN;
struct sk_buff *skb = alloc_skb(len, GFP_ATOMIC);
if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
if (!skb)
return;
skb_reserve(skb, X25_MAX_L2_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++ = X25_RESTART_CONFIRMATION;
skb->sk = NULL;
x25_send_frame(skb, neigh);
x25_send_frame(skb, nb);
}
/*
* 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;
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;
skb_reserve(skb, X25_MAX_L2_LEN);
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++ = X25_DIAGNOSTIC;
*dptr++ = diag;
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
* 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;
int len;
len = X25_MAX_L2_LEN + X25_STD_MIN_LEN + 2;
int len = X25_MAX_L2_LEN + X25_STD_MIN_LEN + 2;
struct sk_buff *skb = alloc_skb(len, GFP_ATOMIC);
if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
if (!skb)
return;
skb_reserve(skb, X25_MAX_L2_LEN);
dptr = skb_put(skb, X25_STD_MIN_LEN + 2);
*dptr++ = ((lci >> 8) & 0x0F) | (neigh->extended) ? X25_GFI_EXTSEQ : X25_GFI_STDSEQ;
*dptr++ = ((lci >> 0) & 0xFF);
*dptr++ = ((lci >> 8) & 0x0F) | nb->extended ? X25_GFI_EXTSEQ :
X25_GFI_STDSEQ;
*dptr++ = (lci >> 0) & 0xFF;
*dptr++ = X25_CLEAR_REQUEST;
*dptr++ = cause;
*dptr++ = 0x00;
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:
skb_queue_tail(&neigh->queue, skb);
neigh->state = X25_LINK_STATE_1;
x25_establish_link(neigh);
skb_queue_tail(&nb->queue, skb);
nb->state = X25_LINK_STATE_1;
x25_establish_link(nb);
break;
case X25_LINK_STATE_1:
case X25_LINK_STATE_2:
skb_queue_tail(&neigh->queue, skb);
skb_queue_tail(&nb->queue, skb);
break;
case X25_LINK_STATE_3:
x25_send_frame(skb, neigh);
x25_send_frame(skb, nb);
break;
}
}
......@@ -250,16 +251,16 @@ void x25_transmit_link(struct sk_buff *skb, struct x25_neigh *neigh)
/*
* 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:
neigh->state = X25_LINK_STATE_2;
nb->state = X25_LINK_STATE_2;
break;
case X25_LINK_STATE_1:
x25_transmit_restart_request(neigh);
neigh->state = X25_LINK_STATE_2;
x25_start_t20timer(neigh);
x25_transmit_restart_request(nb);
nb->state = X25_LINK_STATE_2;
x25_start_t20timer(nb);
break;
}
}
......@@ -269,11 +270,11 @@ void x25_link_established(struct x25_neigh *neigh)
* 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) */
x25_kill_by_neigh(neigh);
x25_kill_by_neigh(nb);
}
/*
......@@ -281,59 +282,50 @@ void x25_link_terminated(struct x25_neigh *neigh)
*/
void x25_link_device_up(struct net_device *dev)
{
struct x25_neigh *x25_neigh;
unsigned long flags;
struct x25_neigh *nb = kmalloc(sizeof(*nb), GFP_ATOMIC);
if ((x25_neigh = kmalloc(sizeof(*x25_neigh), GFP_ATOMIC)) == NULL)
if (!nb)
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);
x25_neigh->dev = dev;
x25_neigh->state = X25_LINK_STATE_0;
x25_neigh->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;
save_flags(flags); cli();
x25_neigh->next = x25_neigh_list;
x25_neigh_list = x25_neigh;
restore_flags(flags);
nb->dev = dev;
nb->state = X25_LINK_STATE_0;
nb->extended = 0;
/*
* Enables negotiation
*/
nb->global_facil_mask = X25_MASK_REVERSE |
X25_MASK_THROUGHPUT |
X25_MASK_PACKET_SIZE |
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;
unsigned long flags;
skb_queue_purge(&x25_neigh->queue);
x25_stop_t20timer(x25_neigh);
skb_queue_purge(&nb->queue);
x25_stop_t20timer(nb);
save_flags(flags); cli();
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;
if (nb->node.next) {
list_del(&nb->node);
x25_neigh_put(nb);
}
s = s->next;
}
restore_flags(flags);
}
/*
......@@ -341,17 +333,21 @@ static void x25_remove_neigh(struct x25_neigh *x25_neigh)
*/
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;
write_lock_bh(&x25_neigh_list_lock);
while (x25_neigh != NULL) {
neigh = x25_neigh;
x25_neigh = x25_neigh->next;
list_for_each_safe(entry, tmp, &x25_neigh_list) {
nb = list_entry(entry, struct x25_neigh, node);
if (neigh->dev == dev){
x25_remove_neigh(neigh);
if (nb->dev == dev) {
__x25_remove_neigh(nb);
dev_put(dev);
}
}
write_unlock_bh(&x25_neigh_list_lock);
}
/*
......@@ -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_neigh;
struct x25_neigh *nb, *use = NULL;
struct list_head *entry;
read_lock_bh(&x25_neigh_list_lock);
list_for_each(entry, &x25_neigh_list) {
nb = list_entry(entry, struct x25_neigh, node);
for (x25_neigh = x25_neigh_list; x25_neigh != NULL; x25_neigh = x25_neigh->next)
if (x25_neigh->dev == dev)
return x25_neigh;
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)
int x25_subscr_ioctl(unsigned int cmd, void *arg)
{
struct x25_subscrip_struct x25_subscr;
struct x25_neigh *x25_neigh;
struct x25_neigh *nb;
struct net_device *dev;
int rc = -EINVAL;
switch (cmd) {
if (cmd != SIOCX25GSUBSCRIP && cmd != SIOCX25SSUBSCRIP)
goto out;
case SIOCX25GSUBSCRIP:
if (copy_from_user(&x25_subscr, arg, sizeof(struct x25_subscrip_struct)))
return -EFAULT;
if ((dev = x25_dev_get(x25_subscr.device)) == NULL)
return -EINVAL;
if ((x25_neigh = x25_get_neigh(dev)) == NULL) {
dev_put(dev);
return -EINVAL;
}
dev_put(dev);
x25_subscr.extended = x25_neigh->extended;
x25_subscr.global_facil_mask = x25_neigh->global_facil_mask;
if (copy_to_user(arg, &x25_subscr, sizeof(struct x25_subscrip_struct)))
return -EFAULT;
break;
rc = -EFAULT;
if (copy_from_user(&x25_subscr, arg, sizeof(x25_subscr)))
goto out;
case SIOCX25SSUBSCRIP:
if (copy_from_user(&x25_subscr, arg, sizeof(struct x25_subscrip_struct)))
return -EFAULT;
rc = -EINVAL;
if ((dev = x25_dev_get(x25_subscr.device)) == NULL)
return -EINVAL;
if ((x25_neigh = x25_get_neigh(dev)) == NULL) {
dev_put(dev);
return -EINVAL;
}
goto out;
if ((nb = x25_get_neigh(dev)) == NULL)
goto out_dev_put;
dev_put(dev);
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;
if (cmd == SIOCX25GSUBSCRIP) {
x25_subscr.extended = nb->extended;
x25_subscr.global_facil_mask = nb->global_facil_mask;
rc = copy_to_user(arg, &x25_subscr,
sizeof(x25_subscr)) ? -EFAULT : 0;
} else {
rc = -EINVAL;
if (!(x25_subscr.extended && x25_subscr.extended != 1)) {
rc = 0;
nb->extended = x25_subscr.extended;
nb->global_facil_mask = x25_subscr.global_facil_mask;
}
return 0;
}
x25_neigh_put(nb);
out:
return rc;
out_dev_put:
dev_put(dev);
goto out;
}
......@@ -424,12 +427,14 @@ int x25_subscr_ioctl(unsigned int cmd, void *arg)
*/
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) {
neigh = x25_neigh;
x25_neigh = x25_neigh->next;
write_lock_bh(&x25_neigh_list_lock);
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
*
* This is ALPHA test software. This code may break your machine, randomly fail to work with new
* releases, misbehave and/or generally screw up. It might even work.
* This is ALPHA test software. This code may break your machine,
* 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
*
......@@ -45,7 +46,7 @@ static int x25_pacsize_to_bytes(unsigned int pacsize)
{
int bytes = 1;
if (pacsize == 0)
if (!pacsize)
return 128;
while (pacsize-- > 0)
......@@ -66,7 +67,7 @@ int x25_output(struct sock *sk, struct sk_buff *skb)
unsigned char header[X25_EXT_MIN_LEN];
int err, frontlen, len;
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 :
X25_STD_MIN_LEN;
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)
frontlen = skb_headroom(skb);
while (skb->len > 0) {
if ((skbn = sock_alloc_send_skb(sk, frontlen + max_len, noblock, &err)) == NULL){
if(err == -EWOULDBLOCK && noblock){
if ((skbn = sock_alloc_send_skb(sk, frontlen + max_len,
noblock, &err)) == NULL){
if (err == -EWOULDBLOCK && noblock){
kfree_skb(skb);
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;
}
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 */
memcpy(skb_put(skbn, len), skb->data, len);
......@@ -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)
{
x25_cb *x25 = x25_sk(sk);
struct x25_opt *x25 = x25_sk(sk);
if (skb == NULL)
if (!skb)
return;
if (x25->neighbour->extended) {
......@@ -148,7 +152,7 @@ void x25_kick(struct sock *sk)
struct sk_buff *skb, *skbn;
unsigned short start, end;
int modulus;
x25_cb *x25 = x25_sk(sk);
struct x25_opt *x25 = x25_sk(sk);
if (x25->state != X25_STATE_3)
return;
......@@ -168,9 +172,9 @@ void x25_kick(struct sock *sk)
if (skb_peek(&sk->write_queue) == NULL)
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;
if (start == end)
......@@ -220,7 +224,7 @@ void x25_kick(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)
x25_write_internal(sk, X25_RNR);
......
/*
* X.25 Packet Layer release 002
*
* This is ALPHA test software. This code may break your machine, randomly fail to work with new
* releases, misbehave and/or generally screw up. It might even work.
* This is ALPHA test software. This code may break your machine,
* 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
*
......@@ -43,78 +44,85 @@
#include <linux/init.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.
*/
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;
unsigned long flags;
struct x25_route *rt;
struct list_head *entry;
int rc = -EINVAL;
for (x25_route = x25_route_list; x25_route != NULL; x25_route = x25_route->next)
if (memcmp(&x25_route->address, address, sigdigits) == 0 && x25_route->sigdigits == sigdigits)
return -EINVAL;
write_lock_bh(&x25_route_list_lock);
if ((x25_route = kmalloc(sizeof(*x25_route), GFP_ATOMIC)) == NULL)
return -ENOMEM;
list_for_each(entry, &x25_route_list) {
rt = list_entry(entry, struct x25_route, node);
strcpy(x25_route->address.x25_addr, "000000000000000");
memcpy(x25_route->address.x25_addr, address->x25_addr, sigdigits);
if (!memcmp(&rt->address, address, sigdigits) &&
rt->sigdigits == sigdigits)
goto out;
}
rt = kmalloc(sizeof(*rt), GFP_ATOMIC);
rc = -ENOMEM;
if (!rt)
goto out;
x25_route->sigdigits = sigdigits;
x25_route->dev = dev;
strcpy(rt->address.x25_addr, "000000000000000");
memcpy(rt->address.x25_addr, address->x25_addr, sigdigits);
save_flags(flags); cli();
x25_route->next = x25_route_list;
x25_route_list = x25_route;
restore_flags(flags);
rt->sigdigits = sigdigits;
rt->dev = dev;
atomic_set(&rt->refcnt, 1);
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;
unsigned long flags;
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;
if (rt->node.next) {
list_del(&rt->node);
x25_route_put(rt);
}
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);
for (x25_route = x25_route_list; x25_route != NULL; x25_route = x25_route->next) {
if (memcmp(&x25_route->address, address, sigdigits) == 0 && x25_route->sigdigits == sigdigits && x25_route->dev == dev) {
x25_remove_route(x25_route);
return 0;
list_for_each(entry, &x25_route_list) {
rt = list_entry(entry, struct x25_route, node);
if (!memcmp(&rt->address, address, sigdigits) &&
rt->sigdigits == sigdigits && rt->dev == dev) {
__x25_remove_route(rt);
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
*/
void x25_route_device_down(struct net_device *dev)
{
struct x25_route *route, *x25_route = x25_route_list;
struct x25_route *rt;
struct list_head *entry, *tmp;
while (x25_route != NULL) {
route = x25_route;
x25_route = x25_route->next;
write_lock_bh(&x25_route_list_lock);
if (route->dev == dev)
x25_remove_route(route);
list_for_each_safe(entry, tmp, &x25_route_list) {
rt = list_entry(entry, struct x25_route, node);
if (rt->dev == dev)
__x25_remove_route(rt);
}
write_unlock_bh(&x25_route_list_lock);
}
/*
......@@ -138,42 +149,48 @@ void x25_route_device_down(struct net_device *dev)
*/
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)
|| dev->type == ARPHRD_ETHER
&& dev->type != ARPHRD_ETHER
#endif
))
return dev;
)))
dev_put(dev);
return NULL;
return dev;
}
/*
* Find a device given an X.25 address.
/**
* x25_get_route - Find a route given an X.25 address.
* @addr - address to find a route for
*
* Find a route given an X.25 address.
*/
struct net_device *x25_get_route(x25_address *addr)
struct x25_route *x25_get_route(struct x25_address *addr)
{
struct x25_route *route, *use = NULL;
for (route = x25_route_list; route != NULL; route = route->next) {
if (memcmp(&route->address, addr, route->sigdigits) == 0) {
if (use == NULL) {
use = route;
} else {
if (route->sigdigits > use->sigdigits)
use = route;
}
struct x25_route *rt, *use = NULL;
struct list_head *entry;
read_lock_bh(&x25_route_list_lock);
list_for_each(entry, &x25_route_list) {
rt = list_entry(entry, struct x25_route, node);
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)
*/
int x25_route_ioctl(unsigned int cmd, void *arg)
{
struct x25_route_struct x25_route;
struct x25_route_struct rt;
struct net_device *dev;
int err;
switch (cmd) {
case SIOCADDRT:
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_add_route(&x25_route.address, x25_route.sigdigits, dev);
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;
int rc = -EINVAL;
default:
return -EINVAL;
}
if (cmd != SIOCADDRT && cmd != SIOCDELRT)
goto out;
rc = -EFAULT;
if (copy_from_user(&rt, arg, sizeof(rt)))
goto out;
rc = -EINVAL;
if (rt.sigdigits < 0 || rt.sigdigits > 15)
goto out;
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)
{
struct x25_route *x25_route;
int len = 0;
struct x25_route *rt;
struct list_head *entry;
off_t pos = 0;
off_t begin = 0;
int len = sprintf(buffer, "address digits device\n");
cli();
read_lock_bh(&x25_route_list_lock);
len += sprintf(buffer, "address digits device\n");
for (x25_route = x25_route_list; x25_route != NULL; x25_route = x25_route->next) {
list_for_each(entry, &x25_route_list) {
rt = list_entry(entry, struct x25_route, node);
len += sprintf(buffer + len, "%-15s %-6d %-5s\n",
x25_route->address.x25_addr,
x25_route->sigdigits,
(x25_route->dev != NULL) ? x25_route->dev->name : "???");
rt->address.x25_addr,
rt->sigdigits,
rt->dev ? rt->dev->name : "???");
pos = begin + len;
......@@ -244,12 +254,13 @@ int x25_routes_get_info(char *buffer, char **start, off_t offset, int length)
break;
}
sti();
read_unlock_bh(&x25_route_list_lock);
*start = buffer + (offset - begin);
len -= (offset - begin);
if (len > length) len = length;
if (len > length)
len = length;
return len;
}
......@@ -259,12 +270,13 @@ int x25_routes_get_info(char *buffer, char **start, off_t offset, int length)
*/
void __exit x25_route_free(void)
{
struct x25_route *route, *x25_route = x25_route_list;
while (x25_route != NULL) {
route = x25_route;
x25_route = x25_route->next;
struct x25_route *rt;
struct list_head *entry, *tmp;
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
*
* This is ALPHA test software. This code may break your machine, randomly fail to work with new
* releases, misbehave and/or generally screw up. It might even work.
* This is ALPHA test software. This code may break your machine,
* 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
*
......@@ -46,7 +47,7 @@
*/
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(&x25->ack_queue);
......@@ -64,7 +65,7 @@ void x25_clear_queues(struct sock *sk)
void x25_frames_acked(struct sock *sk, unsigned short nr)
{
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;
/*
......@@ -88,7 +89,7 @@ void x25_requeue_frames(struct sock *sk)
* output queue.
*/
while ((skb = skb_dequeue(&x25_sk(sk)->ack_queue)) != NULL) {
if (skb_prev == NULL)
if (!skb_prev)
skb_queue_head(&sk->write_queue, skb);
else
skb_append(skb_prev, skb);
......@@ -102,12 +103,13 @@ void x25_requeue_frames(struct sock *sk)
*/
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;
int modulus = x25->neighbour->extended ? X25_EMODULUS : X25_SMODULUS;
while (vc != x25->vs) {
if (nr == vc) return 1;
if (nr == vc)
return 1;
vc = (vc + 1) % modulus;
}
......@@ -120,18 +122,16 @@ int x25_validate_nr(struct sock *sk, unsigned short nr)
*/
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;
unsigned char *dptr;
unsigned char facilities[X25_MAX_FAC_LEN];
unsigned char addresses[1 + X25_ADDR_LEN];
unsigned char lci1, lci2;
int len;
/*
* 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.
......@@ -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 *d, int *m)
{
x25_cb *x25 = x25_sk(sk);
struct x25_opt *x25 = x25_sk(sk);
unsigned char *frame = skb->data;
*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,
void x25_disconnect(struct sock *sk, int reason, unsigned char cause,
unsigned char diagnostic)
{
x25_cb *x25 = x25_sk(sk);
struct x25_opt *x25 = x25_sk(sk);
x25_clear_queues(sk);
x25_stop_timer(sk);
......@@ -356,7 +356,7 @@ void x25_disconnect(struct sock *sk, int reason, unsigned char cause,
*/
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) &&
(x25->condition & X25_COND_OWN_RX_BUSY)) {
......
/*
* X.25 Packet Layer release 002
*
* This is ALPHA test software. This code may break your machine, randomly fail to work with new
* releases, misbehave and/or generally screw up. It might even work.
* This is ALPHA test software. This code may break your machine,
* 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
*
......@@ -60,7 +61,7 @@ void x25_stop_heartbeat(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);
......@@ -73,7 +74,7 @@ void x25_start_t2timer(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);
......@@ -86,7 +87,7 @@ void x25_start_t21timer(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);
......@@ -99,7 +100,7 @@ void x25_start_t22timer(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);
......@@ -117,7 +118,7 @@ void x25_stop_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))
return 0;
......@@ -130,9 +131,8 @@ static void x25_heartbeat_expiry(unsigned long param)
struct sock *sk = (struct sock *)param;
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;
}
switch (x25_sk(sk)->state) {
......@@ -152,9 +152,9 @@ static void x25_heartbeat_expiry(unsigned long param)
x25_check_rbuf(sk);
break;
}
restart_heartbeat:
restart_heartbeat:
x25_start_heartbeat(sk);
unlock:
unlock:
bh_unlock_sock(sk);
}
......@@ -164,7 +164,7 @@ static void x25_heartbeat_expiry(unsigned long param)
*/
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) {
......@@ -194,11 +194,9 @@ static void x25_timer_expiry(unsigned long param)
bh_lock_sock(sk);
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);
}
} else {
} else
x25_do_timer_expiry(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