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