1 /* $Id: isdn_x25iface.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
 
   3  * Linux ISDN subsystem, X.25 related functions
 
   5  * This software may be used and distributed according to the terms
 
   6  * of the GNU General Public License, incorporated herein by reference.
 
   8  * stuff needed to support the Linux X.25 PLP code on top of devices that
 
   9  * can provide a lab_b service using the concap_proto mechanism.
 
  10  * This module supports a network interface which provides lapb_sematics
 
  11  * -- as defined in Documentation/networking/x25-iface.txt -- to
 
  12  * the upper layer and assumes that the lower layer provides a reliable
 
  13  * data link service by means of the concap_device_ops callbacks.
 
  15  * Only protocol specific stuff goes here. Device specific stuff
 
  16  * goes to another -- device related -- concap_proto support source file.
 
  20 /* #include <linux/isdn.h> */
 
  21 #include <linux/netdevice.h>
 
  22 #include <linux/concap.h>
 
  23 #include <linux/wanrouter.h>
 
  24 #include <net/x25device.h>
 
  25 #include "isdn_x25iface.h"
 
  27 /* for debugging messages not to cause an oops when device pointer is NULL*/
 
  28 #define MY_DEVNAME(dev)  ( (dev) ? (dev)->name : "DEVICE UNSPECIFIED" )
 
  31 typedef struct isdn_x25iface_proto_data {
 
  33         enum wan_states state;
 
  34         /* Private stuff, not to be accessed via proto_data. We provide the
 
  35            other storage for the concap_proto instance here as well,
 
  36            enabling us to allocate both with just one kmalloc(): */ 
 
  37         struct concap_proto priv;
 
  42 /* is now in header file (extern): struct concap_proto * isdn_x25iface_proto_new(void); */
 
  43 static void isdn_x25iface_proto_del( struct concap_proto * );
 
  44 static int isdn_x25iface_proto_close( struct concap_proto * );
 
  45 static int isdn_x25iface_proto_restart( struct concap_proto *,
 
  47                                         struct concap_device_ops *);
 
  48 static int isdn_x25iface_xmit( struct concap_proto *, struct sk_buff * );
 
  49 static int isdn_x25iface_receive( struct concap_proto *, struct sk_buff * );
 
  50 static int isdn_x25iface_connect_ind( struct concap_proto * );
 
  51 static int isdn_x25iface_disconn_ind( struct concap_proto * );
 
  54 static struct concap_proto_ops ix25_pops = {
 
  55         &isdn_x25iface_proto_new,
 
  56         &isdn_x25iface_proto_del,
 
  57         &isdn_x25iface_proto_restart,
 
  58         &isdn_x25iface_proto_close,
 
  60         &isdn_x25iface_receive,
 
  61         &isdn_x25iface_connect_ind,
 
  62         &isdn_x25iface_disconn_ind
 
  65 /* error message helper function */
 
  66 static void illegal_state_warn( unsigned state, unsigned char firstbyte) 
 
  68         printk( KERN_WARNING "isdn_x25iface: firstbyte %x illegal in"
 
  69                 "current state %d\n",firstbyte, state );
 
  72 /* check protocol data field for consistency */
 
  73 static int pdata_is_bad( ix25_pdata_t * pda ){
 
  75         if( pda  &&  pda -> magic == ISDN_X25IFACE_MAGIC ) return 0;
 
  77                 "isdn_x25iface_xxx: illegal pointer to proto data\n" );
 
  81 /* create a new x25 interface protocol instance
 
  83 struct concap_proto * isdn_x25iface_proto_new(void)
 
  85         ix25_pdata_t * tmp = kmalloc(sizeof(ix25_pdata_t),GFP_KERNEL);
 
  86         IX25DEBUG("isdn_x25iface_proto_new\n");
 
  88                 tmp -> magic = ISDN_X25IFACE_MAGIC;
 
  89                 tmp -> state = WAN_UNCONFIGURED;
 
  90                 /* private data space used to hold the concap_proto data.
 
  91                    Only to be accessed via the returned pointer */
 
  92                 spin_lock_init(&tmp->priv.lock);
 
  93                 tmp -> priv.dops       = NULL;
 
  94                 tmp -> priv.net_dev    = NULL;
 
  95                 tmp -> priv.pops       = &ix25_pops;
 
  96                 tmp -> priv.flags      = 0;
 
  97                 tmp -> priv.proto_data = tmp;
 
  98                 return( &(tmp -> priv) );
 
 103 /* close the x25iface encapsulation protocol 
 
 105 static int isdn_x25iface_proto_close(struct concap_proto *cprot){
 
 112                 printk( KERN_ERR "isdn_x25iface_proto_close: "
 
 113                         "invalid concap_proto pointer\n" );
 
 116         IX25DEBUG( "isdn_x25iface_proto_close %s \n", MY_DEVNAME(cprot -> net_dev) );
 
 117         spin_lock_irqsave(&cprot->lock, flags);
 
 118         cprot -> dops    = NULL;
 
 119         cprot -> net_dev = NULL;
 
 120         tmp = cprot -> proto_data;
 
 121         if( pdata_is_bad( tmp ) ){
 
 124                 tmp -> state = WAN_UNCONFIGURED;
 
 126         spin_unlock_irqrestore(&cprot->lock, flags);
 
 130 /* Delete the x25iface encapsulation protocol instance
 
 132 static void isdn_x25iface_proto_del(struct concap_proto *cprot){
 
 136         IX25DEBUG( "isdn_x25iface_proto_del \n" );
 
 138                 printk( KERN_ERR "isdn_x25iface_proto_del: "
 
 139                         "concap_proto pointer is NULL\n" );
 
 142         tmp = cprot -> proto_data;
 
 144                 printk( KERN_ERR "isdn_x25iface_proto_del: inconsistent "
 
 145                         "proto_data pointer (maybe already deleted?)\n"); 
 
 148         /* close if the protocol is still open */
 
 149         if( cprot -> dops ) isdn_x25iface_proto_close(cprot);
 
 150         /* freeing the storage should be sufficient now. But some additional
 
 151            settings might help to catch wild pointer bugs */
 
 153         cprot -> proto_data = NULL;
 
 159 /* (re-)initialize the data structures for x25iface encapsulation
 
 161 static int isdn_x25iface_proto_restart(struct concap_proto *cprot,
 
 162                                         struct net_device *ndev,
 
 163                                         struct concap_device_ops *dops)
 
 165         ix25_pdata_t * pda = cprot -> proto_data ;
 
 168         IX25DEBUG( "isdn_x25iface_proto_restart %s \n", MY_DEVNAME(ndev) );
 
 170         if ( pdata_is_bad( pda ) ) return -1;
 
 172         if( !( dops  && dops -> data_req && dops -> connect_req 
 
 173                && dops -> disconn_req )  ){
 
 174                 printk( KERN_WARNING "isdn_x25iface_restart: required dops"
 
 176                 isdn_x25iface_proto_close(cprot);
 
 179         spin_lock_irqsave(&cprot->lock, flags);
 
 180         cprot -> net_dev = ndev;
 
 181         cprot -> pops = &ix25_pops;
 
 182         cprot -> dops = dops;
 
 183         pda -> state = WAN_DISCONNECTED;
 
 184         spin_unlock_irqrestore(&cprot->lock, flags);
 
 188 /* deliver a dl_data frame received from i4l HL driver to the network layer 
 
 190 static int isdn_x25iface_receive(struct concap_proto *cprot, struct sk_buff *skb)
 
 192         IX25DEBUG( "isdn_x25iface_receive %s \n", MY_DEVNAME(cprot->net_dev) );
 
 193         if ( ( (ix25_pdata_t*) (cprot->proto_data) ) 
 
 194              -> state == WAN_CONNECTED ){
 
 195                 if( skb_push(skb, 1)){
 
 197                         skb->protocol = x25_type_trans(skb, cprot->net_dev);
 
 202         printk(KERN_WARNING "isdn_x25iface_receive %s: not connected, skb dropped\n", MY_DEVNAME(cprot->net_dev) );
 
 207 /* a connection set up is indicated by lower layer 
 
 209 static int isdn_x25iface_connect_ind(struct concap_proto *cprot)
 
 211         struct sk_buff * skb = dev_alloc_skb(1);
 
 212         enum wan_states *state_p 
 
 213           = &( ( (ix25_pdata_t*) (cprot->proto_data) ) -> state);
 
 214         IX25DEBUG( "isdn_x25iface_connect_ind %s \n"
 
 215                    , MY_DEVNAME(cprot->net_dev) );
 
 216         if( *state_p == WAN_UNCONFIGURED ){ 
 
 218                        "isdn_x25iface_connect_ind while unconfigured %s\n"
 
 219                        , MY_DEVNAME(cprot->net_dev) );
 
 222         *state_p = WAN_CONNECTED;
 
 224                 *( skb_put(skb, 1) ) = 0x01;
 
 225                 skb->protocol = x25_type_trans(skb, cprot->net_dev);
 
 229                 printk(KERN_WARNING "isdn_x25iface_connect_ind: "
 
 230                        " out of memory -- disconnecting\n");
 
 231                 cprot -> dops -> disconn_req(cprot);
 
 236 /* a disconnect is indicated by lower layer 
 
 238 static int isdn_x25iface_disconn_ind(struct concap_proto *cprot)
 
 241         enum wan_states *state_p 
 
 242           = &( ( (ix25_pdata_t*) (cprot->proto_data) ) -> state);
 
 243         IX25DEBUG( "isdn_x25iface_disconn_ind %s \n", MY_DEVNAME(cprot -> net_dev) );
 
 244         if( *state_p == WAN_UNCONFIGURED ){ 
 
 246                        "isdn_x25iface_disconn_ind while unconfigured\n");
 
 249         if(! cprot -> net_dev) return -1;
 
 250         *state_p = WAN_DISCONNECTED;
 
 251         skb = dev_alloc_skb(1);
 
 253                 *( skb_put(skb, 1) ) = 0x02;
 
 254                 skb->protocol = x25_type_trans(skb, cprot->net_dev);
 
 258                 printk(KERN_WARNING "isdn_x25iface_disconn_ind:"
 
 264 /* process a frame handed over to us from linux network layer. First byte
 
 265    semantics as defined in Documentation/networking/x25-iface.txt
 
 267 static int isdn_x25iface_xmit(struct concap_proto *cprot, struct sk_buff *skb)
 
 269         unsigned char firstbyte = skb->data[0];
 
 270         enum wan_states *state = &((ix25_pdata_t*)cprot->proto_data)->state;
 
 272         IX25DEBUG( "isdn_x25iface_xmit: %s first=%x state=%d \n", MY_DEVNAME(cprot -> net_dev), firstbyte, *state );
 
 273         switch ( firstbyte ){
 
 274         case 0x00: /* dl_data request */
 
 275                 if( *state == WAN_CONNECTED ){
 
 277                         cprot -> net_dev -> trans_start = jiffies;
 
 278                         ret = ( cprot -> dops -> data_req(cprot, skb) );
 
 279                         /* prepare for future retransmissions */
 
 280                         if( ret ) skb_push(skb,1);
 
 283                 illegal_state_warn( *state, firstbyte ); 
 
 285         case 0x01: /* dl_connect request */
 
 286                 if( *state == WAN_DISCONNECTED ){
 
 287                         *state = WAN_CONNECTING;
 
 288                         ret = cprot -> dops -> connect_req(cprot);
 
 290                                 /* reset state and notify upper layer about
 
 291                                  * immidiatly failed attempts */
 
 292                                 isdn_x25iface_disconn_ind(cprot);
 
 295                         illegal_state_warn( *state, firstbyte );
 
 298         case 0x02: /* dl_disconnect request */
 
 300                 case WAN_DISCONNECTED: 
 
 301                         /* Should not happen. However, give upper layer a
 
 302                            chance to recover from inconstistency  but don't
 
 303                            trust the lower layer sending the disconn_confirm
 
 304                            when already disconnected */
 
 305                         printk(KERN_WARNING "isdn_x25iface_xmit: disconnect "
 
 306                                " requested while disconnected\n" );
 
 307                         isdn_x25iface_disconn_ind(cprot);
 
 308                         break; /* prevent infinite loops */
 
 311                         *state = WAN_DISCONNECTED;
 
 312                         cprot -> dops -> disconn_req(cprot);
 
 315                         illegal_state_warn( *state, firstbyte );
 
 318         case 0x03: /* changing lapb parameters requested */
 
 319                 printk(KERN_WARNING "isdn_x25iface_xmit: setting of lapb"
 
 320                        " options not yet supported\n");
 
 323                 printk(KERN_WARNING "isdn_x25iface_xmit: frame with illegal"
 
 324                        " first byte %x ignored:\n", firstbyte);