linux/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/jiffies.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 LIST_HEAD(lapb_list);
  43static DEFINE_RWLOCK(lapb_list_lock);
  44
  45/*
  46 *      Free an allocated lapb control block.
  47 */
  48static void lapb_free_cb(struct lapb_cb *lapb)
  49{
  50        kfree(lapb);
  51}
  52
  53static __inline__ void lapb_hold(struct lapb_cb *lapb)
  54{
  55        atomic_inc(&lapb->refcnt);
  56}
  57
  58static __inline__ void lapb_put(struct lapb_cb *lapb)
  59{
  60        if (atomic_dec_and_test(&lapb->refcnt))
  61                lapb_free_cb(lapb);
  62}
  63
  64/*
  65 *      Socket removal during an interrupt is now safe.
  66 */
  67static void __lapb_remove_cb(struct lapb_cb *lapb)
  68{
  69        if (lapb->node.next) {
  70                list_del(&lapb->node);
  71                lapb_put(lapb);
  72        }
  73}
  74
  75/*
  76 *      Add a socket to the bound sockets list.
  77 */
  78static void __lapb_insert_cb(struct lapb_cb *lapb)
  79{
  80        list_add(&lapb->node, &lapb_list);
  81        lapb_hold(lapb);
  82}
  83
  84static struct lapb_cb *__lapb_devtostruct(struct net_device *dev)
  85{
  86        struct list_head *entry;
  87        struct lapb_cb *lapb, *use = NULL;
  88
  89        list_for_each(entry, &lapb_list) {
  90                lapb = list_entry(entry, struct lapb_cb, node);
  91                if (lapb->dev == dev) {
  92                        use = lapb;
  93                        break;
  94                }
  95        }
  96
  97        if (use)
  98                lapb_hold(use);
  99
 100        return use;
 101}
 102
 103static struct lapb_cb *lapb_devtostruct(struct net_device *dev)
 104{
 105        struct lapb_cb *rc;
 106
 107        read_lock_bh(&lapb_list_lock);
 108        rc = __lapb_devtostruct(dev);
 109        read_unlock_bh(&lapb_list_lock);
 110
 111        return rc;
 112}
 113/*
 114 *      Create an empty LAPB control block.
 115 */
 116static struct lapb_cb *lapb_create_cb(void)
 117{
 118        struct lapb_cb *lapb = kzalloc(sizeof(*lapb), GFP_ATOMIC);
 119
 120
 121        if (!lapb)
 122                goto out;
 123
 124        skb_queue_head_init(&lapb->write_queue);
 125        skb_queue_head_init(&lapb->ack_queue);
 126
 127        init_timer(&lapb->t1timer);
 128        init_timer(&lapb->t2timer);
 129
 130        lapb->t1      = LAPB_DEFAULT_T1;
 131        lapb->t2      = LAPB_DEFAULT_T2;
 132        lapb->n2      = LAPB_DEFAULT_N2;
 133        lapb->mode    = LAPB_DEFAULT_MODE;
 134        lapb->window  = LAPB_DEFAULT_WINDOW;
 135        lapb->state   = LAPB_STATE_0;
 136        atomic_set(&lapb->refcnt, 1);
 137out:
 138        return lapb;
 139}
 140
 141int lapb_register(struct net_device *dev, struct lapb_register_struct *callbacks)
 142{
 143        struct lapb_cb *lapb;
 144        int rc = LAPB_BADTOKEN;
 145
 146        write_lock_bh(&lapb_list_lock);
 147
 148        lapb = __lapb_devtostruct(dev);
 149        if (lapb) {
 150                lapb_put(lapb);
 151                goto out;
 152        }
 153
 154        lapb = lapb_create_cb();
 155        rc = LAPB_NOMEM;
 156        if (!lapb)
 157                goto out;
 158
 159        lapb->dev       = dev;
 160        lapb->callbacks = *callbacks;
 161
 162        __lapb_insert_cb(lapb);
 163
 164        lapb_start_t1timer(lapb);
 165
 166        rc = LAPB_OK;
 167out:
 168        write_unlock_bh(&lapb_list_lock);
 169        return rc;
 170}
 171
 172int lapb_unregister(struct net_device *dev)
 173{
 174        struct lapb_cb *lapb;
 175        int rc = LAPB_BADTOKEN;
 176
 177        write_lock_bh(&lapb_list_lock);
 178        lapb = __lapb_devtostruct(dev);
 179        if (!lapb)
 180                goto out;
 181
 182        lapb_stop_t1timer(lapb);
 183        lapb_stop_t2timer(lapb);
 184
 185        lapb_clear_queues(lapb);
 186
 187        __lapb_remove_cb(lapb);
 188
 189        lapb_put(lapb);
 190        rc = LAPB_OK;
 191out:
 192        write_unlock_bh(&lapb_list_lock);
 193        return rc;
 194}
 195
 196int lapb_getparms(struct net_device *dev, struct lapb_parms_struct *parms)
 197{
 198        int rc = LAPB_BADTOKEN;
 199        struct lapb_cb *lapb = lapb_devtostruct(dev);
 200
 201        if (!lapb)
 202                goto out;
 203
 204        parms->t1      = lapb->t1 / HZ;
 205        parms->t2      = lapb->t2 / HZ;
 206        parms->n2      = lapb->n2;
 207        parms->n2count = lapb->n2count;
 208        parms->state   = lapb->state;
 209        parms->window  = lapb->window;
 210        parms->mode    = lapb->mode;
 211
 212        if (!timer_pending(&lapb->t1timer))
 213                parms->t1timer = 0;
 214        else
 215                parms->t1timer = (lapb->t1timer.expires - jiffies) / HZ;
 216
 217        if (!timer_pending(&lapb->t2timer))
 218                parms->t2timer = 0;
 219        else
 220                parms->t2timer = (lapb->t2timer.expires - jiffies) / HZ;
 221
 222        lapb_put(lapb);
 223        rc = LAPB_OK;
 224out:
 225        return rc;
 226}
 227
 228int lapb_setparms(struct net_device *dev, struct lapb_parms_struct *parms)
 229{
 230        int rc = LAPB_BADTOKEN;
 231        struct lapb_cb *lapb = lapb_devtostruct(dev);
 232
 233        if (!lapb)
 234                goto out;
 235
 236        rc = LAPB_INVALUE;
 237        if (parms->t1 < 1 || parms->t2 < 1 || parms->n2 < 1)
 238                goto out_put;
 239
 240        if (lapb->state == LAPB_STATE_0) {
 241                if (parms->mode & LAPB_EXTENDED) {
 242                        if (parms->window < 1 || parms->window > 127)
 243                                goto out_put;
 244                } else {
 245                        if (parms->window < 1 || parms->window > 7)
 246                                goto out_put;
 247                }
 248                lapb->mode    = parms->mode;
 249                lapb->window  = parms->window;
 250        }
 251
 252        lapb->t1    = parms->t1 * HZ;
 253        lapb->t2    = parms->t2 * HZ;
 254        lapb->n2    = parms->n2;
 255
 256        rc = LAPB_OK;
 257out_put:
 258        lapb_put(lapb);
 259out:
 260        return rc;
 261}
 262
 263int lapb_connect_request(struct net_device *dev)
 264{
 265        struct lapb_cb *lapb = lapb_devtostruct(dev);
 266        int rc = LAPB_BADTOKEN;
 267
 268        if (!lapb)
 269                goto out;
 270
 271        rc = LAPB_OK;
 272        if (lapb->state == LAPB_STATE_1)
 273                goto out_put;
 274
 275        rc = LAPB_CONNECTED;
 276        if (lapb->state == LAPB_STATE_3 || lapb->state == LAPB_STATE_4)
 277                goto out_put;
 278
 279        lapb_establish_data_link(lapb);
 280
 281#if LAPB_DEBUG > 0
 282        printk(KERN_DEBUG "lapb: (%p) S0 -> S1\n", lapb->dev);
 283#endif
 284        lapb->state = LAPB_STATE_1;
 285
 286        rc = LAPB_OK;
 287out_put:
 288        lapb_put(lapb);
 289out:
 290        return rc;
 291}
 292
 293int lapb_disconnect_request(struct net_device *dev)
 294{
 295        struct lapb_cb *lapb = lapb_devtostruct(dev);
 296        int rc = LAPB_BADTOKEN;
 297
 298        if (!lapb)
 299                goto out;
 300
 301        switch (lapb->state) {
 302                case LAPB_STATE_0:
 303                        rc = LAPB_NOTCONNECTED;
 304                        goto out_put;
 305
 306                case LAPB_STATE_1:
 307#if LAPB_DEBUG > 1
 308                        printk(KERN_DEBUG "lapb: (%p) S1 TX DISC(1)\n", lapb->dev);
 309#endif
 310#if LAPB_DEBUG > 0
 311                        printk(KERN_DEBUG "lapb: (%p) S1 -> S0\n", lapb->dev);
 312#endif
 313                        lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND);
 314                        lapb->state = LAPB_STATE_0;
 315                        lapb_start_t1timer(lapb);
 316                        rc = LAPB_NOTCONNECTED;
 317                        goto out_put;
 318
 319                case LAPB_STATE_2:
 320                        rc = LAPB_OK;
 321                        goto out_put;
 322        }
 323
 324        lapb_clear_queues(lapb);
 325        lapb->n2count = 0;
 326        lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND);
 327        lapb_start_t1timer(lapb);
 328        lapb_stop_t2timer(lapb);
 329        lapb->state = LAPB_STATE_2;
 330
 331#if LAPB_DEBUG > 1
 332        printk(KERN_DEBUG "lapb: (%p) S3 DISC(1)\n", lapb->dev);
 333#endif
 334#if LAPB_DEBUG > 0
 335        printk(KERN_DEBUG "lapb: (%p) S3 -> S2\n", lapb->dev);
 336#endif
 337
 338        rc = LAPB_OK;
 339out_put:
 340        lapb_put(lapb);
 341out:
 342        return rc;
 343}
 344
 345int lapb_data_request(struct net_device *dev, struct sk_buff *skb)
 346{
 347        struct lapb_cb *lapb = lapb_devtostruct(dev);
 348        int rc = LAPB_BADTOKEN;
 349
 350        if (!lapb)
 351                goto out;
 352
 353        rc = LAPB_NOTCONNECTED;
 354        if (lapb->state != LAPB_STATE_3 && lapb->state != LAPB_STATE_4)
 355                goto out_put;
 356
 357        skb_queue_tail(&lapb->write_queue, skb);
 358        lapb_kick(lapb);
 359        rc = LAPB_OK;
 360out_put:
 361        lapb_put(lapb);
 362out:
 363        return rc;
 364}
 365
 366int lapb_data_received(struct net_device *dev, struct sk_buff *skb)
 367{
 368        struct lapb_cb *lapb = lapb_devtostruct(dev);
 369        int rc = LAPB_BADTOKEN;
 370
 371        if (lapb) {
 372                lapb_data_input(lapb, skb);
 373                lapb_put(lapb);
 374                rc = LAPB_OK;
 375        }
 376
 377        return rc;
 378}
 379
 380void lapb_connect_confirmation(struct lapb_cb *lapb, int reason)
 381{
 382        if (lapb->callbacks.connect_confirmation)
 383                lapb->callbacks.connect_confirmation(lapb->dev, reason);
 384}
 385
 386void lapb_connect_indication(struct lapb_cb *lapb, int reason)
 387{
 388        if (lapb->callbacks.connect_indication)
 389                lapb->callbacks.connect_indication(lapb->dev, reason);
 390}
 391
 392void lapb_disconnect_confirmation(struct lapb_cb *lapb, int reason)
 393{
 394        if (lapb->callbacks.disconnect_confirmation)
 395                lapb->callbacks.disconnect_confirmation(lapb->dev, reason);
 396}
 397
 398void lapb_disconnect_indication(struct lapb_cb *lapb, int reason)
 399{
 400        if (lapb->callbacks.disconnect_indication)
 401                lapb->callbacks.disconnect_indication(lapb->dev, reason);
 402}
 403
 404int lapb_data_indication(struct lapb_cb *lapb, struct sk_buff *skb)
 405{
 406        if (lapb->callbacks.data_indication)
 407                return lapb->callbacks.data_indication(lapb->dev, skb);
 408
 409        kfree_skb(skb);
 410        return NET_RX_CN_HIGH; /* For now; must be != NET_RX_DROP */
 411}
 412
 413int lapb_data_transmit(struct lapb_cb *lapb, struct sk_buff *skb)
 414{
 415        int used = 0;
 416
 417        if (lapb->callbacks.data_transmit) {
 418                lapb->callbacks.data_transmit(lapb->dev, skb);
 419                used = 1;
 420        }
 421
 422        return used;
 423}
 424
 425EXPORT_SYMBOL(lapb_register);
 426EXPORT_SYMBOL(lapb_unregister);
 427EXPORT_SYMBOL(lapb_getparms);
 428EXPORT_SYMBOL(lapb_setparms);
 429EXPORT_SYMBOL(lapb_connect_request);
 430EXPORT_SYMBOL(lapb_disconnect_request);
 431EXPORT_SYMBOL(lapb_data_request);
 432EXPORT_SYMBOL(lapb_data_received);
 433
 434static int __init lapb_init(void)
 435{
 436        return 0;
 437}
 438
 439static void __exit lapb_exit(void)
 440{
 441        WARN_ON(!list_empty(&lapb_list));
 442}
 443
 444MODULE_AUTHOR("Jonathan Naylor <g4klx@g4klx.demon.co.uk>");
 445MODULE_DESCRIPTION("The X.25 Link Access Procedure B link layer protocol");
 446MODULE_LICENSE("GPL");
 447
 448module_init(lapb_init);
 449module_exit(lapb_exit);
 450
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.