linux-old/net/lapb/lapb_iface.c
<<
>>
Prefs
   1/*
   2 *      LAPB release 002
   3 *
   4 *      This code REQUIRES 2.1.15 or higher/ NET3.038
   5 *
   6 *      This module:
   7 *              This module is free software; you can redistribute it and/or
   8 *              modify it under the terms of the GNU General Public License
   9 *              as published by the Free Software Foundation; either version
  10 *              2 of the License, or (at your option) any later version.
  11 *
  12 *      History
  13 *      LAPB 001        Jonathan Naylor Started Coding
  14 *      LAPB 002        Jonathan Naylor New timer architecture.
  15 *      2000-10-29      Henner Eisen    lapb_data_indication() return status.
  16 */
  17 
  18#include <linux/module.h>
  19#include <linux/errno.h>
  20#include <linux/types.h>
  21#include <linux/socket.h>
  22#include <linux/in.h>
  23#include <linux/kernel.h>
  24#include <linux/sched.h>
  25#include <linux/timer.h>
  26#include <linux/string.h>
  27#include <linux/sockios.h>
  28#include <linux/net.h>
  29#include <linux/inet.h>
  30#include <linux/if_arp.h>
  31#include <linux/skbuff.h>
  32#include <net/sock.h>
  33#include <asm/uaccess.h>
  34#include <asm/system.h>
  35#include <linux/fcntl.h>
  36#include <linux/mm.h>
  37#include <linux/interrupt.h>
  38#include <linux/stat.h>
  39#include <linux/init.h>
  40#include <net/lapb.h>
  41
  42static lapb_cb *volatile lapb_list /* = NULL initially */;
  43
  44/*
  45 *      Free an allocated lapb control block. This is done to centralise
  46 *      the MOD count code.
  47 */
  48static void lapb_free_cb(lapb_cb *lapb)
  49{
  50        kfree(lapb);
  51
  52        MOD_DEC_USE_COUNT;
  53}
  54
  55/*
  56 *      Socket removal during an interrupt is now safe.
  57 */
  58static void lapb_remove_cb(lapb_cb *lapb)
  59{
  60        lapb_cb *s;
  61        unsigned long flags;
  62
  63        save_flags(flags); cli();
  64
  65        if ((s = lapb_list) == lapb) {
  66                lapb_list = s->next;
  67                restore_flags(flags);
  68                return;
  69        }
  70
  71        while (s != NULL && s->next != NULL) {
  72                if (s->next == lapb) {
  73                        s->next = lapb->next;
  74                        restore_flags(flags);
  75                        return;
  76                }
  77
  78                s = s->next;
  79        }
  80
  81        restore_flags(flags);
  82}
  83
  84/*
  85 *      Add a socket to the bound sockets list.
  86 */
  87static void lapb_insert_cb(lapb_cb *lapb)
  88{
  89        unsigned long flags;
  90
  91        save_flags(flags); cli();
  92
  93        lapb->next = lapb_list;
  94        lapb_list  = lapb;
  95
  96        restore_flags(flags);
  97}
  98
  99/*
 100 *      Convert the integer token used by the device driver into a pointer
 101 *      to a LAPB control structure.
 102 */
 103static lapb_cb *lapb_tokentostruct(void *token)
 104{
 105        lapb_cb *lapb;
 106
 107        for (lapb = lapb_list; lapb != NULL; lapb = lapb->next)
 108                if (lapb->token == token)
 109                        return lapb;
 110
 111        return NULL;
 112}
 113
 114/*
 115 *      Create an empty LAPB control block.
 116 */
 117static lapb_cb *lapb_create_cb(void)
 118{
 119        lapb_cb *lapb;
 120
 121        if ((lapb = kmalloc(sizeof(*lapb), GFP_ATOMIC)) == NULL)
 122                return NULL;
 123
 124        MOD_INC_USE_COUNT;
 125
 126        memset(lapb, 0x00, sizeof(*lapb));
 127
 128        skb_queue_head_init(&lapb->write_queue);
 129        skb_queue_head_init(&lapb->ack_queue);
 130
 131        init_timer(&lapb->t1timer);
 132        init_timer(&lapb->t2timer);
 133
 134        lapb->t1      = LAPB_DEFAULT_T1;
 135        lapb->t2      = LAPB_DEFAULT_T2;
 136        lapb->n2      = LAPB_DEFAULT_N2;
 137        lapb->mode    = LAPB_DEFAULT_MODE;
 138        lapb->window  = LAPB_DEFAULT_WINDOW;
 139        lapb->state   = LAPB_STATE_0;
 140
 141        return lapb;
 142}
 143
 144int lapb_register(void *token, struct lapb_register_struct *callbacks)
 145{
 146        lapb_cb *lapb;
 147
 148        if (lapb_tokentostruct(token) != NULL)
 149                return LAPB_BADTOKEN;
 150
 151        if ((lapb = lapb_create_cb()) == NULL)
 152                return LAPB_NOMEM;
 153
 154        lapb->token     = token;
 155        lapb->callbacks = *callbacks;
 156
 157        lapb_insert_cb(lapb);
 158
 159        lapb_start_t1timer(lapb);
 160
 161        return LAPB_OK;
 162}
 163
 164int lapb_unregister(void *token)
 165{
 166        lapb_cb *lapb;
 167
 168        if ((lapb = lapb_tokentostruct(token)) == NULL)
 169                return LAPB_BADTOKEN;
 170
 171        lapb_stop_t1timer(lapb);
 172        lapb_stop_t2timer(lapb);
 173
 174        lapb_clear_queues(lapb);
 175
 176        lapb_remove_cb(lapb);
 177
 178        lapb_free_cb(lapb);
 179
 180        return LAPB_OK;
 181}
 182
 183int lapb_getparms(void *token, struct lapb_parms_struct *parms)
 184{
 185        lapb_cb *lapb;
 186
 187        if ((lapb = lapb_tokentostruct(token)) == NULL)
 188                return LAPB_BADTOKEN;
 189
 190        parms->t1      = lapb->t1 / HZ;
 191        parms->t2      = lapb->t2 / HZ;
 192        parms->n2      = lapb->n2;
 193        parms->n2count = lapb->n2count;
 194        parms->state   = lapb->state;
 195        parms->window  = lapb->window;
 196        parms->mode    = lapb->mode;
 197
 198        if (!timer_pending(&lapb->t1timer))
 199                parms->t1timer = 0;
 200        else
 201                parms->t1timer = (lapb->t1timer.expires - jiffies) / HZ;
 202
 203        if (!timer_pending(&lapb->t2timer))
 204                parms->t2timer = 0;
 205        else
 206                parms->t2timer = (lapb->t2timer.expires - jiffies) / HZ;
 207
 208        return LAPB_OK;
 209}
 210
 211int lapb_setparms(void *token, struct lapb_parms_struct *parms)
 212{
 213        lapb_cb *lapb;
 214
 215        if ((lapb = lapb_tokentostruct(token)) == NULL)
 216                return LAPB_BADTOKEN;
 217
 218        if (parms->t1 < 1)
 219                return LAPB_INVALUE;
 220
 221        if (parms->t2 < 1)
 222                return LAPB_INVALUE;
 223
 224        if (parms->n2 < 1)
 225                return LAPB_INVALUE;
 226
 227        if (lapb->state == LAPB_STATE_0) {
 228                if (parms->mode & LAPB_EXTENDED) {
 229                        if (parms->window < 1 || parms->window > 127)
 230                                return LAPB_INVALUE;
 231                } else {
 232                        if (parms->window < 1 || parms->window > 7)
 233                                return LAPB_INVALUE;
 234                }
 235
 236                lapb->mode    = parms->mode;
 237                lapb->window  = parms->window;
 238        }
 239
 240        lapb->t1    = parms->t1 * HZ;
 241        lapb->t2    = parms->t2 * HZ;
 242        lapb->n2    = parms->n2;
 243
 244        return LAPB_OK;
 245}
 246
 247int lapb_connect_request(void *token)
 248{
 249        lapb_cb *lapb;
 250
 251        if ((lapb = lapb_tokentostruct(token)) == NULL)
 252                return LAPB_BADTOKEN;
 253
 254        switch (lapb->state) {
 255                case LAPB_STATE_1:
 256                        return LAPB_OK;
 257                case LAPB_STATE_3:
 258                case LAPB_STATE_4:
 259                        return LAPB_CONNECTED;
 260        }
 261
 262        lapb_establish_data_link(lapb);
 263
 264#if LAPB_DEBUG > 0
 265        printk(KERN_DEBUG "lapb: (%p) S0 -> S1\n", lapb->token);
 266#endif
 267
 268        lapb->state = LAPB_STATE_1;
 269
 270        return LAPB_OK;
 271}
 272
 273int lapb_disconnect_request(void *token)
 274{
 275        lapb_cb *lapb;
 276
 277        if ((lapb = lapb_tokentostruct(token)) == NULL)
 278                return LAPB_BADTOKEN;
 279
 280        switch (lapb->state) {
 281                case LAPB_STATE_0:
 282                        return LAPB_NOTCONNECTED;
 283
 284                case LAPB_STATE_1:
 285#if LAPB_DEBUG > 1
 286                        printk(KERN_DEBUG "lapb: (%p) S1 TX DISC(1)\n", lapb->token);
 287#endif
 288#if LAPB_DEBUG > 0
 289                        printk(KERN_DEBUG "lapb: (%p) S1 -> S0\n", lapb->token);
 290#endif
 291                        lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND);
 292                        lapb->state = LAPB_STATE_0;
 293                        lapb_start_t1timer(lapb);
 294                        return LAPB_NOTCONNECTED;
 295
 296                case LAPB_STATE_2:
 297                        return LAPB_OK;
 298        }
 299
 300        lapb_clear_queues(lapb);
 301        lapb->n2count = 0;
 302        lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND);
 303        lapb_start_t1timer(lapb);
 304        lapb_stop_t2timer(lapb);
 305        lapb->state = LAPB_STATE_2;
 306
 307#if LAPB_DEBUG > 1
 308        printk(KERN_DEBUG "lapb: (%p) S3 DISC(1)\n", lapb->token);
 309#endif
 310#if LAPB_DEBUG > 0
 311        printk(KERN_DEBUG "lapb: (%p) S3 -> S2\n", lapb->token);
 312#endif
 313
 314        return LAPB_OK;
 315}
 316
 317int lapb_data_request(void *token, struct sk_buff *skb)
 318{
 319        lapb_cb *lapb;
 320
 321        if ((lapb = lapb_tokentostruct(token)) == NULL)
 322                return LAPB_BADTOKEN;
 323
 324        if (lapb->state != LAPB_STATE_3 && lapb->state != LAPB_STATE_4)
 325                return LAPB_NOTCONNECTED;
 326
 327        skb_queue_tail(&lapb->write_queue, skb);
 328
 329        lapb_kick(lapb);
 330
 331        return LAPB_OK;
 332}
 333
 334int lapb_data_received(void *token, struct sk_buff *skb)
 335{
 336        lapb_cb *lapb;
 337
 338        if ((lapb = lapb_tokentostruct(token)) == NULL)
 339                return LAPB_BADTOKEN;
 340
 341        lapb_data_input(lapb, skb);
 342
 343        return LAPB_OK;
 344}
 345
 346void lapb_connect_confirmation(lapb_cb *lapb, int reason)
 347{
 348        if (lapb->callbacks.connect_confirmation != NULL)
 349                (lapb->callbacks.connect_confirmation)(lapb->token, reason);
 350}
 351
 352void lapb_connect_indication(lapb_cb *lapb, int reason)
 353{
 354        if (lapb->callbacks.connect_indication != NULL)
 355                (lapb->callbacks.connect_indication)(lapb->token, reason);
 356}
 357
 358void lapb_disconnect_confirmation(lapb_cb *lapb, int reason)
 359{
 360        if (lapb->callbacks.disconnect_confirmation != NULL)
 361                (lapb->callbacks.disconnect_confirmation)(lapb->token, reason);
 362}
 363
 364void lapb_disconnect_indication(lapb_cb *lapb, int reason)
 365{
 366        if (lapb->callbacks.disconnect_indication != NULL)
 367                (lapb->callbacks.disconnect_indication)(lapb->token, reason);
 368}
 369
 370int lapb_data_indication(lapb_cb *lapb, struct sk_buff *skb)
 371{
 372        if (lapb->callbacks.data_indication != NULL) {
 373                return (lapb->callbacks.data_indication)(lapb->token, skb);
 374        }
 375        kfree_skb(skb);
 376        return NET_RX_CN_HIGH; /* For now; must be != NET_RX_DROP */ 
 377}
 378
 379int lapb_data_transmit(lapb_cb *lapb, struct sk_buff *skb)
 380{
 381        int used = 0;
 382
 383        if (lapb->callbacks.data_transmit != NULL) {
 384                (lapb->callbacks.data_transmit)(lapb->token, skb);
 385                used = 1;
 386        }
 387
 388        return used;
 389}
 390
 391EXPORT_SYMBOL(lapb_register);
 392EXPORT_SYMBOL(lapb_unregister);
 393EXPORT_SYMBOL(lapb_getparms);
 394EXPORT_SYMBOL(lapb_setparms);
 395EXPORT_SYMBOL(lapb_connect_request);
 396EXPORT_SYMBOL(lapb_disconnect_request);
 397EXPORT_SYMBOL(lapb_data_request);
 398EXPORT_SYMBOL(lapb_data_received);
 399
 400static char banner[] __initdata = KERN_INFO "NET4: LAPB for Linux. Version 0.01 for NET4.0\n";
 401
 402static int __init lapb_init(void)
 403{
 404        printk(banner);
 405        return 0;
 406}
 407
 408MODULE_AUTHOR("Jonathan Naylor <g4klx@g4klx.demon.co.uk>");
 409MODULE_DESCRIPTION("The X.25 Link Access Procedure B link layer protocol");
 410MODULE_LICENSE("GPL");
 411
 412module_init(lapb_init);
 413
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.