11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* $Id: isdn_x25iface.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Linux ISDN subsystem, X.25 related functions
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This software may be used and distributed according to the terms
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of the GNU General Public License, incorporated herein by reference.
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * stuff needed to support the Linux X.25 PLP code on top of devices that
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * can provide a lab_b service using the concap_proto mechanism.
10c30fe7f73194650148b58ee80908c1bc38246397Uwe Zeisberger * This module supports a network interface which provides lapb_sematics
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * -- as defined in Documentation/networking/x25-iface.txt -- to
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the upper layer and assumes that the lower layer provides a reliable
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * data link service by means of the concap_device_ops callbacks.
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Only protocol specific stuff goes here. Device specific stuff
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * goes to another -- device related -- concap_proto support source file.
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* #include <linux/isdn.h> */
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/concap.h>
235a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/wanrouter.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/x25device.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "isdn_x25iface.h"
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* for debugging messages not to cause an oops when device pointer is NULL*/
29475be4d85a274d0961593db41cf85689db1d583cJoe Perches#define MY_DEVNAME(dev)  ((dev) ? (dev)->name : "DEVICE UNSPECIFIED")
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstypedef struct isdn_x25iface_proto_data {
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int magic;
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	enum wan_states state;
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Private stuff, not to be accessed via proto_data. We provide the
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   other storage for the concap_proto instance here as well,
37475be4d85a274d0961593db41cf85689db1d583cJoe Perches	   enabling us to allocate both with just one kmalloc(): */
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct concap_proto priv;
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} ix25_pdata_t;
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* is now in header file (extern): struct concap_proto * isdn_x25iface_proto_new(void); */
44475be4d85a274d0961593db41cf85689db1d583cJoe Perchesstatic void isdn_x25iface_proto_del(struct concap_proto *);
45475be4d85a274d0961593db41cf85689db1d583cJoe Perchesstatic int isdn_x25iface_proto_close(struct concap_proto *);
46475be4d85a274d0961593db41cf85689db1d583cJoe Perchesstatic int isdn_x25iface_proto_restart(struct concap_proto *,
47475be4d85a274d0961593db41cf85689db1d583cJoe Perches				       struct net_device *,
48475be4d85a274d0961593db41cf85689db1d583cJoe Perches				       struct concap_device_ops *);
49475be4d85a274d0961593db41cf85689db1d583cJoe Perchesstatic int isdn_x25iface_xmit(struct concap_proto *, struct sk_buff *);
50475be4d85a274d0961593db41cf85689db1d583cJoe Perchesstatic int isdn_x25iface_receive(struct concap_proto *, struct sk_buff *);
51475be4d85a274d0961593db41cf85689db1d583cJoe Perchesstatic int isdn_x25iface_connect_ind(struct concap_proto *);
52475be4d85a274d0961593db41cf85689db1d583cJoe Perchesstatic int isdn_x25iface_disconn_ind(struct concap_proto *);
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct concap_proto_ops ix25_pops = {
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&isdn_x25iface_proto_new,
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&isdn_x25iface_proto_del,
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&isdn_x25iface_proto_restart,
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&isdn_x25iface_proto_close,
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&isdn_x25iface_xmit,
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&isdn_x25iface_receive,
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&isdn_x25iface_connect_ind,
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&isdn_x25iface_disconn_ind
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* error message helper function */
67475be4d85a274d0961593db41cf85689db1d583cJoe Perchesstatic void illegal_state_warn(unsigned state, unsigned char firstbyte)
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
69475be4d85a274d0961593db41cf85689db1d583cJoe Perches	printk(KERN_WARNING "isdn_x25iface: firstbyte %x illegal in"
70475be4d85a274d0961593db41cf85689db1d583cJoe Perches	       "current state %d\n", firstbyte, state);
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* check protocol data field for consistency */
74475be4d85a274d0961593db41cf85689db1d583cJoe Perchesstatic int pdata_is_bad(ix25_pdata_t *pda) {
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
76475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (pda  &&  pda->magic == ISDN_X25IFACE_MAGIC) return 0;
77475be4d85a274d0961593db41cf85689db1d583cJoe Perches	printk(KERN_WARNING
78475be4d85a274d0961593db41cf85689db1d583cJoe Perches	       "isdn_x25iface_xxx: illegal pointer to proto data\n");
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* create a new x25 interface protocol instance
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
84475be4d85a274d0961593db41cf85689db1d583cJoe Perchesstruct concap_proto *isdn_x25iface_proto_new(void)
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
86475be4d85a274d0961593db41cf85689db1d583cJoe Perches	ix25_pdata_t *tmp = kmalloc(sizeof(ix25_pdata_t), GFP_KERNEL);
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IX25DEBUG("isdn_x25iface_proto_new\n");
88475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (tmp) {
89475be4d85a274d0961593db41cf85689db1d583cJoe Perches		tmp->magic = ISDN_X25IFACE_MAGIC;
90475be4d85a274d0961593db41cf85689db1d583cJoe Perches		tmp->state = WAN_UNCONFIGURED;
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* private data space used to hold the concap_proto data.
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   Only to be accessed via the returned pointer */
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock_init(&tmp->priv.lock);
94475be4d85a274d0961593db41cf85689db1d583cJoe Perches		tmp->priv.dops       = NULL;
95475be4d85a274d0961593db41cf85689db1d583cJoe Perches		tmp->priv.net_dev    = NULL;
96475be4d85a274d0961593db41cf85689db1d583cJoe Perches		tmp->priv.pops       = &ix25_pops;
97475be4d85a274d0961593db41cf85689db1d583cJoe Perches		tmp->priv.flags      = 0;
98475be4d85a274d0961593db41cf85689db1d583cJoe Perches		tmp->priv.proto_data = tmp;
99475be4d85a274d0961593db41cf85689db1d583cJoe Perches		return (&(tmp->priv));
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
104475be4d85a274d0961593db41cf85689db1d583cJoe Perches/* close the x25iface encapsulation protocol
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
106475be4d85a274d0961593db41cf85689db1d583cJoe Perchesstatic int isdn_x25iface_proto_close(struct concap_proto *cprot) {
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ix25_pdata_t *tmp;
109475be4d85a274d0961593db41cf85689db1d583cJoe Perches	int ret = 0;
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ulong flags;
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
112475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (!cprot) {
113475be4d85a274d0961593db41cf85689db1d583cJoe Perches		printk(KERN_ERR "isdn_x25iface_proto_close: "
114475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       "invalid concap_proto pointer\n");
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
117475be4d85a274d0961593db41cf85689db1d583cJoe Perches	IX25DEBUG("isdn_x25iface_proto_close %s \n", MY_DEVNAME(cprot->net_dev));
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&cprot->lock, flags);
119475be4d85a274d0961593db41cf85689db1d583cJoe Perches	cprot->dops    = NULL;
120475be4d85a274d0961593db41cf85689db1d583cJoe Perches	cprot->net_dev = NULL;
121475be4d85a274d0961593db41cf85689db1d583cJoe Perches	tmp = cprot->proto_data;
122475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (pdata_is_bad(tmp)) {
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -1;
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
125475be4d85a274d0961593db41cf85689db1d583cJoe Perches		tmp->state = WAN_UNCONFIGURED;
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&cprot->lock, flags);
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Delete the x25iface encapsulation protocol instance
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
133475be4d85a274d0961593db41cf85689db1d583cJoe Perchesstatic void isdn_x25iface_proto_del(struct concap_proto *cprot) {
134475be4d85a274d0961593db41cf85689db1d583cJoe Perches
135475be4d85a274d0961593db41cf85689db1d583cJoe Perches	ix25_pdata_t *tmp;
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
137475be4d85a274d0961593db41cf85689db1d583cJoe Perches	IX25DEBUG("isdn_x25iface_proto_del \n");
138475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (!cprot) {
139475be4d85a274d0961593db41cf85689db1d583cJoe Perches		printk(KERN_ERR "isdn_x25iface_proto_del: "
140475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       "concap_proto pointer is NULL\n");
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
143475be4d85a274d0961593db41cf85689db1d583cJoe Perches	tmp = cprot->proto_data;
144475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (tmp == NULL) {
145475be4d85a274d0961593db41cf85689db1d583cJoe Perches		printk(KERN_ERR "isdn_x25iface_proto_del: inconsistent "
146475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       "proto_data pointer (maybe already deleted?)\n");
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* close if the protocol is still open */
150475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (cprot->dops) isdn_x25iface_proto_close(cprot);
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* freeing the storage should be sufficient now. But some additional
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   settings might help to catch wild pointer bugs */
153475be4d85a274d0961593db41cf85689db1d583cJoe Perches	tmp->magic = 0;
154475be4d85a274d0961593db41cf85689db1d583cJoe Perches	cprot->proto_data = NULL;
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
156475be4d85a274d0961593db41cf85689db1d583cJoe Perches	kfree(tmp);
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return;
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* (re-)initialize the data structures for x25iface encapsulation
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1623e206b0a66fcaf39dbef92640ce6a63d51fc5c53Adrian Bunkstatic int isdn_x25iface_proto_restart(struct concap_proto *cprot,
163475be4d85a274d0961593db41cf85689db1d583cJoe Perches				       struct net_device *ndev,
164475be4d85a274d0961593db41cf85689db1d583cJoe Perches				       struct concap_device_ops *dops)
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
166475be4d85a274d0961593db41cf85689db1d583cJoe Perches	ix25_pdata_t *pda = cprot->proto_data;
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ulong flags;
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
169475be4d85a274d0961593db41cf85689db1d583cJoe Perches	IX25DEBUG("isdn_x25iface_proto_restart %s \n", MY_DEVNAME(ndev));
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
171475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (pdata_is_bad(pda)) return -1;
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
173475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (!(dops && dops->data_req && dops->connect_req
174475be4d85a274d0961593db41cf85689db1d583cJoe Perches	      && dops->disconn_req)) {
175475be4d85a274d0961593db41cf85689db1d583cJoe Perches		printk(KERN_WARNING "isdn_x25iface_restart: required dops"
176475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       " missing\n");
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		isdn_x25iface_proto_close(cprot);
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&cprot->lock, flags);
181475be4d85a274d0961593db41cf85689db1d583cJoe Perches	cprot->net_dev = ndev;
182475be4d85a274d0961593db41cf85689db1d583cJoe Perches	cprot->pops = &ix25_pops;
183475be4d85a274d0961593db41cf85689db1d583cJoe Perches	cprot->dops = dops;
184475be4d85a274d0961593db41cf85689db1d583cJoe Perches	pda->state = WAN_DISCONNECTED;
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&cprot->lock, flags);
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
189475be4d85a274d0961593db41cf85689db1d583cJoe Perches/* deliver a dl_data frame received from i4l HL driver to the network layer
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1913e206b0a66fcaf39dbef92640ce6a63d51fc5c53Adrian Bunkstatic int isdn_x25iface_receive(struct concap_proto *cprot, struct sk_buff *skb)
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
193475be4d85a274d0961593db41cf85689db1d583cJoe Perches	IX25DEBUG("isdn_x25iface_receive %s \n", MY_DEVNAME(cprot->net_dev));
194475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (((ix25_pdata_t *)(cprot->proto_data))
195475be4d85a274d0961593db41cf85689db1d583cJoe Perches	    ->state == WAN_CONNECTED) {
196475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (skb_push(skb, 1)) {
1974150bbf3388eba2c9d2cb7a345134e363cc6e34fandrew hendry			skb->data[0] = X25_IFACE_DATA;
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			skb->protocol = x25_type_trans(skb, cprot->net_dev);
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			netif_rx(skb);
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
203475be4d85a274d0961593db41cf85689db1d583cJoe Perches	printk(KERN_WARNING "isdn_x25iface_receive %s: not connected, skb dropped\n", MY_DEVNAME(cprot->net_dev));
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_kfree_skb(skb);
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
208475be4d85a274d0961593db41cf85689db1d583cJoe Perches/* a connection set up is indicated by lower layer
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2103e206b0a66fcaf39dbef92640ce6a63d51fc5c53Adrian Bunkstatic int isdn_x25iface_connect_ind(struct concap_proto *cprot)
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
212475be4d85a274d0961593db41cf85689db1d583cJoe Perches	struct sk_buff *skb;
213475be4d85a274d0961593db41cf85689db1d583cJoe Perches	enum wan_states *state_p
214475be4d85a274d0961593db41cf85689db1d583cJoe Perches		= &(((ix25_pdata_t *)(cprot->proto_data))->state);
215475be4d85a274d0961593db41cf85689db1d583cJoe Perches	IX25DEBUG("isdn_x25iface_connect_ind %s \n"
216475be4d85a274d0961593db41cf85689db1d583cJoe Perches		  , MY_DEVNAME(cprot->net_dev));
217475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (*state_p == WAN_UNCONFIGURED) {
218475be4d85a274d0961593db41cf85689db1d583cJoe Perches		printk(KERN_WARNING
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "isdn_x25iface_connect_ind while unconfigured %s\n"
220475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       , MY_DEVNAME(cprot->net_dev));
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*state_p = WAN_CONNECTED;
224d81931d9a2ec3e2e2cd8238b72f20c5fe44ccc7bEric Sesterhenn
225d81931d9a2ec3e2e2cd8238b72f20c5fe44ccc7bEric Sesterhenn	skb = dev_alloc_skb(1);
226475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (skb) {
2274150bbf3388eba2c9d2cb7a345134e363cc6e34fandrew hendry		*(skb_put(skb, 1)) = X25_IFACE_CONNECT;
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb->protocol = x25_type_trans(skb, cprot->net_dev);
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netif_rx(skb);
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "isdn_x25iface_connect_ind: "
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       " out of memory -- disconnecting\n");
234475be4d85a274d0961593db41cf85689db1d583cJoe Perches		cprot->dops->disconn_req(cprot);
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
238475be4d85a274d0961593db41cf85689db1d583cJoe Perches
239475be4d85a274d0961593db41cf85689db1d583cJoe Perches/* a disconnect is indicated by lower layer
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2413e206b0a66fcaf39dbef92640ce6a63d51fc5c53Adrian Bunkstatic int isdn_x25iface_disconn_ind(struct concap_proto *cprot)
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
244475be4d85a274d0961593db41cf85689db1d583cJoe Perches	enum wan_states *state_p
245475be4d85a274d0961593db41cf85689db1d583cJoe Perches		= &(((ix25_pdata_t *)(cprot->proto_data))->state);
246475be4d85a274d0961593db41cf85689db1d583cJoe Perches	IX25DEBUG("isdn_x25iface_disconn_ind %s \n", MY_DEVNAME(cprot->net_dev));
247475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (*state_p == WAN_UNCONFIGURED) {
248475be4d85a274d0961593db41cf85689db1d583cJoe Perches		printk(KERN_WARNING
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "isdn_x25iface_disconn_ind while unconfigured\n");
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
252475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (!cprot->net_dev) return -1;
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*state_p = WAN_DISCONNECTED;
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb = dev_alloc_skb(1);
255475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (skb) {
2564150bbf3388eba2c9d2cb7a345134e363cc6e34fandrew hendry		*(skb_put(skb, 1)) = X25_IFACE_DISCONNECT;
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb->protocol = x25_type_trans(skb, cprot->net_dev);
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netif_rx(skb);
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "isdn_x25iface_disconn_ind:"
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       " out of memory\n");
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* process a frame handed over to us from linux network layer. First byte
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   semantics as defined in Documentation/networking/x25-iface.txt
269475be4d85a274d0961593db41cf85689db1d583cJoe Perches*/
2703e206b0a66fcaf39dbef92640ce6a63d51fc5c53Adrian Bunkstatic int isdn_x25iface_xmit(struct concap_proto *cprot, struct sk_buff *skb)
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char firstbyte = skb->data[0];
273475be4d85a274d0961593db41cf85689db1d583cJoe Perches	enum wan_states *state = &((ix25_pdata_t *)cprot->proto_data)->state;
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = 0;
2754150bbf3388eba2c9d2cb7a345134e363cc6e34fandrew hendry	IX25DEBUG("isdn_x25iface_xmit: %s first=%x state=%d\n",
276475be4d85a274d0961593db41cf85689db1d583cJoe Perches		  MY_DEVNAME(cprot->net_dev), firstbyte, *state);
277475be4d85a274d0961593db41cf85689db1d583cJoe Perches	switch (firstbyte) {
2784150bbf3388eba2c9d2cb7a345134e363cc6e34fandrew hendry	case X25_IFACE_DATA:
279475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (*state == WAN_CONNECTED) {
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			skb_pull(skb, 1);
281475be4d85a274d0961593db41cf85689db1d583cJoe Perches			cprot->net_dev->trans_start = jiffies;
282475be4d85a274d0961593db41cf85689db1d583cJoe Perches			ret = (cprot->dops->data_req(cprot, skb));
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* prepare for future retransmissions */
284475be4d85a274d0961593db41cf85689db1d583cJoe Perches			if (ret) skb_push(skb, 1);
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return ret;
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
287475be4d85a274d0961593db41cf85689db1d583cJoe Perches		illegal_state_warn(*state, firstbyte);
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2894150bbf3388eba2c9d2cb7a345134e363cc6e34fandrew hendry	case X25_IFACE_CONNECT:
290475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (*state == WAN_DISCONNECTED) {
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*state = WAN_CONNECTING;
292475be4d85a274d0961593db41cf85689db1d583cJoe Perches			ret = cprot->dops->connect_req(cprot);
293475be4d85a274d0961593db41cf85689db1d583cJoe Perches			if (ret) {
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* reset state and notify upper layer about
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * immidiatly failed attempts */
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				isdn_x25iface_disconn_ind(cprot);
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
299475be4d85a274d0961593db41cf85689db1d583cJoe Perches			illegal_state_warn(*state, firstbyte);
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3024150bbf3388eba2c9d2cb7a345134e363cc6e34fandrew hendry	case X25_IFACE_DISCONNECT:
303475be4d85a274d0961593db41cf85689db1d583cJoe Perches		switch (*state) {
304475be4d85a274d0961593db41cf85689db1d583cJoe Perches		case WAN_DISCONNECTED:
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Should not happen. However, give upper layer a
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   chance to recover from inconstistency  but don't
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   trust the lower layer sending the disconn_confirm
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   when already disconnected */
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_WARNING "isdn_x25iface_xmit: disconnect "
310475be4d85a274d0961593db41cf85689db1d583cJoe Perches			       " requested while disconnected\n");
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			isdn_x25iface_disconn_ind(cprot);
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break; /* prevent infinite loops */
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case WAN_CONNECTING:
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case WAN_CONNECTED:
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*state = WAN_DISCONNECTED;
316475be4d85a274d0961593db41cf85689db1d583cJoe Perches			cprot->dops->disconn_req(cprot);
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
319475be4d85a274d0961593db41cf85689db1d583cJoe Perches			illegal_state_warn(*state, firstbyte);
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3224150bbf3388eba2c9d2cb7a345134e363cc6e34fandrew hendry	case X25_IFACE_PARAMS:
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "isdn_x25iface_xmit: setting of lapb"
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       " options not yet supported\n");
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "isdn_x25iface_xmit: frame with illegal"
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       " first byte %x ignored:\n", firstbyte);
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_kfree_skb(skb);
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
333