linux/net/lapb/lapb_iface.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *      LAPB release 002
   4 *
   5 *      This code REQUIRES 2.1.15 or higher/ NET3.038
   6 *
   7 *      History
   8 *      LAPB 001        Jonathan Naylor Started Coding
   9 *      LAPB 002        Jonathan Naylor New timer architecture.
  10 *      2000-10-29      Henner Eisen    lapb_data_indication() return status.
  11 */
  12
  13#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  14
  15#include <linux/module.h>
  16#include <linux/errno.h>
  17#include <linux/types.h>
  18#include <linux/socket.h>
  19#include <linux/in.h>
  20#include <linux/kernel.h>
  21#include <linux/jiffies.h>
  22#include <linux/timer.h>
  23#include <linux/string.h>
  24#include <linux/sockios.h>
  25#include <linux/net.h>
  26#include <linux/inet.h>
  27#include <linux/if_arp.h>
  28#include <linux/skbuff.h>
  29#include <linux/slab.h>
  30#include <net/sock.h>
  31#include <linux/uaccess.h>
  32#include <linux/fcntl.h>
  33#include <linux/mm.h>
  34#include <linux/interrupt.h>
  35#include <linux/stat.h>
  36#include <linux/init.h>
  37#include <net/lapb.h>
  38
  39static LIST_HEAD(lapb_list);
  40static DEFINE_RWLOCK(lapb_list_lock);
  41
  42/*
  43 *      Free an allocated lapb control block.
  44 */
  45static void lapb_free_cb(struct lapb_cb *lapb)
  46{
  47        kfree(lapb);
  48}
  49
  50static __inline__ void lapb_hold(struct lapb_cb *lapb)
  51{
  52        refcount_inc(&lapb->refcnt);
  53}
  54
  55static __inline__ void lapb_put(struct lapb_cb *lapb)
  56{
  57        if (refcount_dec_and_test(&lapb->refcnt))
  58                lapb_free_cb(lapb);
  59}
  60
  61/*
  62 *      Socket removal during an interrupt is now safe.
  63 */
  64static void __lapb_remove_cb(struct lapb_cb *lapb)
  65{
  66        if (lapb->node.next) {
  67                list_del(&lapb->node);
  68                lapb_put(lapb);
  69        }
  70}
  71
  72/*
  73 *      Add a socket to the bound sockets list.
  74 */
  75static void __lapb_insert_cb(struct lapb_cb *lapb)
  76{
  77        list_add(&lapb->node, &lapb_list);
  78        lapb_hold(lapb);
  79}
  80
  81static struct lapb_cb *__lapb_devtostruct(struct net_device *dev)
  82{
  83        struct list_head *entry;
  84        struct lapb_cb *lapb, *use = NULL;
  85
  86        list_for_each(entry, &lapb_list) {
  87                lapb = list_entry(entry, struct lapb_cb, node);
  88                if (lapb->dev == dev) {
  89                        use = lapb;
  90                        break;
  91                }
  92        }
  93
  94        if (use)
  95                lapb_hold(use);
  96
  97        return use;
  98}
  99
 100static struct lapb_cb *lapb_devtostruct(struct net_device *dev)
 101{
 102        struct lapb_cb *rc;
 103
 104        read_lock_bh(&lapb_list_lock);
 105        rc = __lapb_devtostruct(dev);
 106        read_unlock_bh(&lapb_list_lock);
 107
 108        return rc;
 109}
 110/*
 111 *      Create an empty LAPB control block.
 112 */
 113static struct lapb_cb *lapb_create_cb(void)
 114{
 115        struct lapb_cb *lapb = kzalloc(sizeof(*lapb), GFP_ATOMIC);
 116
 117        if (!lapb)
 118                goto out;
 119
 120        skb_queue_head_init(&lapb->write_queue);
 121        skb_queue_head_init(&lapb->ack_queue);
 122
 123        timer_setup(&lapb->t1timer, NULL, 0);
 124        timer_setup(&lapb->t2timer, NULL, 0);
 125
 126        lapb->t1      = LAPB_DEFAULT_T1;
 127        lapb->t2      = LAPB_DEFAULT_T2;
 128        lapb->n2      = LAPB_DEFAULT_N2;
 129        lapb->mode    = LAPB_DEFAULT_MODE;
 130        lapb->window  = LAPB_DEFAULT_WINDOW;
 131        lapb->state   = LAPB_STATE_0;
 132        refcount_set(&lapb->refcnt, 1);
 133out:
 134        return lapb;
 135}
 136
 137int lapb_register(struct net_device *dev,
 138                  const struct lapb_register_struct *callbacks)
 139{
 140        struct lapb_cb *lapb;
 141        int rc = LAPB_BADTOKEN;
 142
 143        write_lock_bh(&lapb_list_lock);
 144
 145        lapb = __lapb_devtostruct(dev);
 146        if (lapb) {
 147                lapb_put(lapb);
 148                goto out;
 149        }
 150
 151        lapb = lapb_create_cb();
 152        rc = LAPB_NOMEM;
 153        if (!lapb)
 154                goto out;
 155
 156        lapb->dev       = dev;
 157        lapb->callbacks = callbacks;
 158
 159        __lapb_insert_cb(lapb);
 160
 161        lapb_start_t1timer(lapb);
 162
 163        rc = LAPB_OK;
 164out:
 165        write_unlock_bh(&lapb_list_lock);
 166        return rc;
 167}
 168EXPORT_SYMBOL(lapb_register);
 169
 170int lapb_unregister(struct net_device *dev)
 171{
 172        struct lapb_cb *lapb;
 173        int rc = LAPB_BADTOKEN;
 174
 175        write_lock_bh(&lapb_list_lock);
 176        lapb = __lapb_devtostruct(dev);
 177        if (!lapb)
 178                goto out;
 179        lapb_put(lapb);
 180
 181        lapb_stop_t1timer(lapb);
 182        lapb_stop_t2timer(lapb);
 183
 184        lapb_clear_queues(lapb);
 185
 186        __lapb_remove_cb(lapb);
 187
 188        lapb_put(lapb);
 189        rc = LAPB_OK;
 190out:
 191        write_unlock_bh(&lapb_list_lock);
 192        return rc;
 193}
 194EXPORT_SYMBOL(lapb_unregister);
 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}
 227EXPORT_SYMBOL(lapb_getparms);
 228
 229int lapb_setparms(struct net_device *dev, struct lapb_parms_struct *parms)
 230{
 231        int rc = LAPB_BADTOKEN;
 232        struct lapb_cb *lapb = lapb_devtostruct(dev);
 233
 234        if (!lapb)
 235                goto out;
 236
 237        rc = LAPB_INVALUE;
 238        if (parms->t1 < 1 || parms->t2 < 1 || parms->n2 < 1)
 239                goto out_put;
 240
 241        if (lapb->state == LAPB_STATE_0) {
 242                if (parms->mode & LAPB_EXTENDED) {
 243                        if (parms->window < 1 || parms->window > 127)
 244                                goto out_put;
 245                } else {
 246                        if (parms->window < 1 || parms->window > 7)
 247                                goto out_put;
 248                }
 249                lapb->mode    = parms->mode;
 250                lapb->window  = parms->window;
 251        }
 252
 253        lapb->t1    = parms->t1 * HZ;
 254        lapb->t2    = parms->t2 * HZ;
 255        lapb->n2    = parms->n2;
 256
 257        rc = LAPB_OK;
 258out_put:
 259        lapb_put(lapb);
 260out:
 261        return rc;
 262}
 263EXPORT_SYMBOL(lapb_setparms);
 264
 265int lapb_connect_request(struct net_device *dev)
 266{
 267        struct lapb_cb *lapb = lapb_devtostruct(dev);
 268        int rc = LAPB_BADTOKEN;
 269
 270        if (!lapb)
 271                goto out;
 272
 273        rc = LAPB_OK;
 274        if (lapb->state == LAPB_STATE_1)
 275                goto out_put;
 276
 277        rc = LAPB_CONNECTED;
 278        if (lapb->state == LAPB_STATE_3 || lapb->state == LAPB_STATE_4)
 279                goto out_put;
 280
 281        lapb_establish_data_link(lapb);
 282
 283        lapb_dbg(0, "(%p) S0 -> S1\n", lapb->dev);
 284        lapb->state = LAPB_STATE_1;
 285
 286        rc = LAPB_OK;
 287out_put:
 288        lapb_put(lapb);
 289out:
 290        return rc;
 291}
 292EXPORT_SYMBOL(lapb_connect_request);
 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}
 337EXPORT_SYMBOL(lapb_disconnect_request);
 338
 339int lapb_data_request(struct net_device *dev, struct sk_buff *skb)
 340{
 341        struct lapb_cb *lapb = lapb_devtostruct(dev);
 342        int rc = LAPB_BADTOKEN;
 343
 344        if (!lapb)
 345                goto out;
 346
 347        rc = LAPB_NOTCONNECTED;
 348        if (lapb->state != LAPB_STATE_3 && lapb->state != LAPB_STATE_4)
 349                goto out_put;
 350
 351        skb_queue_tail(&lapb->write_queue, skb);
 352        lapb_kick(lapb);
 353        rc = LAPB_OK;
 354out_put:
 355        lapb_put(lapb);
 356out:
 357        return rc;
 358}
 359EXPORT_SYMBOL(lapb_data_request);
 360
 361int lapb_data_received(struct net_device *dev, struct sk_buff *skb)
 362{
 363        struct lapb_cb *lapb = lapb_devtostruct(dev);
 364        int rc = LAPB_BADTOKEN;
 365
 366        if (lapb) {
 367                lapb_data_input(lapb, skb);
 368                lapb_put(lapb);
 369                rc = LAPB_OK;
 370        }
 371
 372        return rc;
 373}
 374EXPORT_SYMBOL(lapb_data_received);
 375
 376void lapb_connect_confirmation(struct lapb_cb *lapb, int reason)
 377{
 378        if (lapb->callbacks->connect_confirmation)
 379                lapb->callbacks->connect_confirmation(lapb->dev, reason);
 380}
 381
 382void lapb_connect_indication(struct lapb_cb *lapb, int reason)
 383{
 384        if (lapb->callbacks->connect_indication)
 385                lapb->callbacks->connect_indication(lapb->dev, reason);
 386}
 387
 388void lapb_disconnect_confirmation(struct lapb_cb *lapb, int reason)
 389{
 390        if (lapb->callbacks->disconnect_confirmation)
 391                lapb->callbacks->disconnect_confirmation(lapb->dev, reason);
 392}
 393
 394void lapb_disconnect_indication(struct lapb_cb *lapb, int reason)
 395{
 396        if (lapb->callbacks->disconnect_indication)
 397                lapb->callbacks->disconnect_indication(lapb->dev, reason);
 398}
 399
 400int lapb_data_indication(struct lapb_cb *lapb, struct sk_buff *skb)
 401{
 402        if (lapb->callbacks->data_indication)
 403                return lapb->callbacks->data_indication(lapb->dev, skb);
 404
 405        kfree_skb(skb);
 406        return NET_RX_SUCCESS; /* For now; must be != NET_RX_DROP */
 407}
 408
 409int lapb_data_transmit(struct lapb_cb *lapb, struct sk_buff *skb)
 410{
 411        int used = 0;
 412
 413        if (lapb->callbacks->data_transmit) {
 414                lapb->callbacks->data_transmit(lapb->dev, skb);
 415                used = 1;
 416        }
 417
 418        return used;
 419}
 420
 421static int __init lapb_init(void)
 422{
 423        return 0;
 424}
 425
 426static void __exit lapb_exit(void)
 427{
 428        WARN_ON(!list_empty(&lapb_list));
 429}
 430
 431MODULE_AUTHOR("Jonathan Naylor <g4klx@g4klx.demon.co.uk>");
 432MODULE_DESCRIPTION("The X.25 Link Access Procedure B link layer protocol");
 433MODULE_LICENSE("GPL");
 434
 435module_init(lapb_init);
 436module_exit(lapb_exit);
 437