linux/net/rose/rose_link.c
<<
>>
Prefs
   1/*
   2 * This program is free software; you can redistribute it and/or modify
   3 * it under the terms of the GNU General Public License as published by
   4 * the Free Software Foundation; either version 2 of the License, or
   5 * (at your option) any later version.
   6 *
   7 * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
   8 */
   9#include <linux/errno.h>
  10#include <linux/types.h>
  11#include <linux/socket.h>
  12#include <linux/in.h>
  13#include <linux/kernel.h>
  14#include <linux/jiffies.h>
  15#include <linux/timer.h>
  16#include <linux/string.h>
  17#include <linux/sockios.h>
  18#include <linux/net.h>
  19#include <linux/slab.h>
  20#include <net/ax25.h>
  21#include <linux/inet.h>
  22#include <linux/netdevice.h>
  23#include <linux/skbuff.h>
  24#include <net/sock.h>
  25#include <linux/fcntl.h>
  26#include <linux/mm.h>
  27#include <linux/interrupt.h>
  28#include <net/rose.h>
  29
  30static void rose_ftimer_expiry(unsigned long);
  31static void rose_t0timer_expiry(unsigned long);
  32
  33static void rose_transmit_restart_confirmation(struct rose_neigh *neigh);
  34static void rose_transmit_restart_request(struct rose_neigh *neigh);
  35
  36void rose_start_ftimer(struct rose_neigh *neigh)
  37{
  38        del_timer(&neigh->ftimer);
  39
  40        neigh->ftimer.data     = (unsigned long)neigh;
  41        neigh->ftimer.function = &rose_ftimer_expiry;
  42        neigh->ftimer.expires  =
  43                jiffies + msecs_to_jiffies(sysctl_rose_link_fail_timeout);
  44
  45        add_timer(&neigh->ftimer);
  46}
  47
  48static void rose_start_t0timer(struct rose_neigh *neigh)
  49{
  50        del_timer(&neigh->t0timer);
  51
  52        neigh->t0timer.data     = (unsigned long)neigh;
  53        neigh->t0timer.function = &rose_t0timer_expiry;
  54        neigh->t0timer.expires  =
  55                jiffies + msecs_to_jiffies(sysctl_rose_restart_request_timeout);
  56
  57        add_timer(&neigh->t0timer);
  58}
  59
  60void rose_stop_ftimer(struct rose_neigh *neigh)
  61{
  62        del_timer(&neigh->ftimer);
  63}
  64
  65void rose_stop_t0timer(struct rose_neigh *neigh)
  66{
  67        del_timer(&neigh->t0timer);
  68}
  69
  70int rose_ftimer_running(struct rose_neigh *neigh)
  71{
  72        return timer_pending(&neigh->ftimer);
  73}
  74
  75static int rose_t0timer_running(struct rose_neigh *neigh)
  76{
  77        return timer_pending(&neigh->t0timer);
  78}
  79
  80static void rose_ftimer_expiry(unsigned long param)
  81{
  82}
  83
  84static void rose_t0timer_expiry(unsigned long param)
  85{
  86        struct rose_neigh *neigh = (struct rose_neigh *)param;
  87
  88        rose_transmit_restart_request(neigh);
  89
  90        neigh->dce_mode = 0;
  91
  92        rose_start_t0timer(neigh);
  93}
  94
  95/*
  96 *      Interface to ax25_send_frame. Changes my level 2 callsign depending
  97 *      on whether we have a global ROSE callsign or use the default port
  98 *      callsign.
  99 */
 100static int rose_send_frame(struct sk_buff *skb, struct rose_neigh *neigh)
 101{
 102        ax25_address *rose_call;
 103        ax25_cb *ax25s;
 104
 105        if (ax25cmp(&rose_callsign, &null_ax25_address) == 0)
 106                rose_call = (ax25_address *)neigh->dev->dev_addr;
 107        else
 108                rose_call = &rose_callsign;
 109
 110        ax25s = neigh->ax25;
 111        neigh->ax25 = ax25_send_frame(skb, 260, rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);
 112        if (ax25s)
 113                ax25_cb_put(ax25s);
 114
 115        return neigh->ax25 != NULL;
 116}
 117
 118/*
 119 *      Interface to ax25_link_up. Changes my level 2 callsign depending
 120 *      on whether we have a global ROSE callsign or use the default port
 121 *      callsign.
 122 */
 123static int rose_link_up(struct rose_neigh *neigh)
 124{
 125        ax25_address *rose_call;
 126        ax25_cb *ax25s;
 127
 128        if (ax25cmp(&rose_callsign, &null_ax25_address) == 0)
 129                rose_call = (ax25_address *)neigh->dev->dev_addr;
 130        else
 131                rose_call = &rose_callsign;
 132
 133        ax25s = neigh->ax25;
 134        neigh->ax25 = ax25_find_cb(rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);
 135        if (ax25s)
 136                ax25_cb_put(ax25s);
 137
 138        return neigh->ax25 != NULL;
 139}
 140
 141/*
 142 *      This handles all restart and diagnostic frames.
 143 */
 144void rose_link_rx_restart(struct sk_buff *skb, struct rose_neigh *neigh, unsigned short frametype)
 145{
 146        struct sk_buff *skbn;
 147
 148        switch (frametype) {
 149        case ROSE_RESTART_REQUEST:
 150                rose_stop_t0timer(neigh);
 151                neigh->restarted = 1;
 152                neigh->dce_mode  = (skb->data[3] == ROSE_DTE_ORIGINATED);
 153                rose_transmit_restart_confirmation(neigh);
 154                break;
 155
 156        case ROSE_RESTART_CONFIRMATION:
 157                rose_stop_t0timer(neigh);
 158                neigh->restarted = 1;
 159                break;
 160
 161        case ROSE_DIAGNOSTIC:
 162                pr_warn("ROSE: received diagnostic #%d - %3ph\n", skb->data[3],
 163                        skb->data + 4);
 164                break;
 165
 166        default:
 167                printk(KERN_WARNING "ROSE: received unknown %02X with LCI 000\n", frametype);
 168                break;
 169        }
 170
 171        if (neigh->restarted) {
 172                while ((skbn = skb_dequeue(&neigh->queue)) != NULL)
 173                        if (!rose_send_frame(skbn, neigh))
 174                                kfree_skb(skbn);
 175        }
 176}
 177
 178/*
 179 *      This routine is called when a Restart Request is needed
 180 */
 181static void rose_transmit_restart_request(struct rose_neigh *neigh)
 182{
 183        struct sk_buff *skb;
 184        unsigned char *dptr;
 185        int len;
 186
 187        len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN + 3;
 188
 189        if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
 190                return;
 191
 192        skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN);
 193
 194        dptr = skb_put(skb, ROSE_MIN_LEN + 3);
 195
 196        *dptr++ = AX25_P_ROSE;
 197        *dptr++ = ROSE_GFI;
 198        *dptr++ = 0x00;
 199        *dptr++ = ROSE_RESTART_REQUEST;
 200        *dptr++ = ROSE_DTE_ORIGINATED;
 201        *dptr++ = 0;
 202
 203        if (!rose_send_frame(skb, neigh))
 204                kfree_skb(skb);
 205}
 206
 207/*
 208 * This routine is called when a Restart Confirmation is needed
 209 */
 210static void rose_transmit_restart_confirmation(struct rose_neigh *neigh)
 211{
 212        struct sk_buff *skb;
 213        unsigned char *dptr;
 214        int len;
 215
 216        len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN + 1;
 217
 218        if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
 219                return;
 220
 221        skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN);
 222
 223        dptr = skb_put(skb, ROSE_MIN_LEN + 1);
 224
 225        *dptr++ = AX25_P_ROSE;
 226        *dptr++ = ROSE_GFI;
 227        *dptr++ = 0x00;
 228        *dptr++ = ROSE_RESTART_CONFIRMATION;
 229
 230        if (!rose_send_frame(skb, neigh))
 231                kfree_skb(skb);
 232}
 233
 234/*
 235 * This routine is called when a Clear Request is needed outside of the context
 236 * of a connected socket.
 237 */
 238void rose_transmit_clear_request(struct rose_neigh *neigh, unsigned int lci, unsigned char cause, unsigned char diagnostic)
 239{
 240        struct sk_buff *skb;
 241        unsigned char *dptr;
 242        int len;
 243
 244        len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN + 3;
 245
 246        if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
 247                return;
 248
 249        skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN);
 250
 251        dptr = skb_put(skb, ROSE_MIN_LEN + 3);
 252
 253        *dptr++ = AX25_P_ROSE;
 254        *dptr++ = ((lci >> 8) & 0x0F) | ROSE_GFI;
 255        *dptr++ = ((lci >> 0) & 0xFF);
 256        *dptr++ = ROSE_CLEAR_REQUEST;
 257        *dptr++ = cause;
 258        *dptr++ = diagnostic;
 259
 260        if (!rose_send_frame(skb, neigh))
 261                kfree_skb(skb);
 262}
 263
 264void rose_transmit_link(struct sk_buff *skb, struct rose_neigh *neigh)
 265{
 266        unsigned char *dptr;
 267
 268        if (neigh->loopback) {
 269                rose_loopback_queue(skb, neigh);
 270                return;
 271        }
 272
 273        if (!rose_link_up(neigh))
 274                neigh->restarted = 0;
 275
 276        dptr = skb_push(skb, 1);
 277        *dptr++ = AX25_P_ROSE;
 278
 279        if (neigh->restarted) {
 280                if (!rose_send_frame(skb, neigh))
 281                        kfree_skb(skb);
 282        } else {
 283                skb_queue_tail(&neigh->queue, skb);
 284
 285                if (!rose_t0timer_running(neigh)) {
 286                        rose_transmit_restart_request(neigh);
 287                        neigh->dce_mode = 0;
 288                        rose_start_t0timer(neigh);
 289                }
 290        }
 291}
 292