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