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