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 <linux/netfilter.h>
  29#include <net/rose.h>
  30
  31static void rose_ftimer_expiry(unsigned long);
  32static void rose_t0timer_expiry(unsigned long);
  33
  34static void rose_transmit_restart_confirmation(struct rose_neigh *neigh);
  35static void rose_transmit_restart_request(struct rose_neigh *neigh);
  36
  37void rose_start_ftimer(struct rose_neigh *neigh)
  38{
  39        del_timer(&neigh->ftimer);
  40
  41        neigh->ftimer.data     = (unsigned long)neigh;
  42        neigh->ftimer.function = &rose_ftimer_expiry;
  43        neigh->ftimer.expires  =
  44                jiffies + msecs_to_jiffies(sysctl_rose_link_fail_timeout);
  45
  46        add_timer(&neigh->ftimer);
  47}
  48
  49static void rose_start_t0timer(struct rose_neigh *neigh)
  50{
  51        del_timer(&neigh->t0timer);
  52
  53        neigh->t0timer.data     = (unsigned long)neigh;
  54        neigh->t0timer.function = &rose_t0timer_expiry;
  55        neigh->t0timer.expires  =
  56                jiffies + msecs_to_jiffies(sysctl_rose_restart_request_timeout);
  57
  58        add_timer(&neigh->t0timer);
  59}
  60
  61void rose_stop_ftimer(struct rose_neigh *neigh)
  62{
  63        del_timer(&neigh->ftimer);
  64}
  65
  66void rose_stop_t0timer(struct rose_neigh *neigh)
  67{
  68        del_timer(&neigh->t0timer);
  69}
  70
  71int rose_ftimer_running(struct rose_neigh *neigh)
  72{
  73        return timer_pending(&neigh->ftimer);
  74}
  75
  76static int rose_t0timer_running(struct rose_neigh *neigh)
  77{
  78        return timer_pending(&neigh->t0timer);
  79}
  80
  81static void rose_ftimer_expiry(unsigned long param)
  82{
  83}
  84
  85static void rose_t0timer_expiry(unsigned long param)
  86{
  87        struct rose_neigh *neigh = (struct rose_neigh *)param;
  88
  89        rose_transmit_restart_request(neigh);
  90
  91        neigh->dce_mode = 0;
  92
  93        rose_start_t0timer(neigh);
  94}
  95
  96/*
  97 *      Interface to ax25_send_frame. Changes my level 2 callsign depending
  98 *      on whether we have a global ROSE callsign or use the default port
  99 *      callsign.
 100 */
 101static int rose_send_frame(struct sk_buff *skb, struct rose_neigh *neigh)
 102{
 103        ax25_address *rose_call;
 104        ax25_cb *ax25s;
 105
 106        if (ax25cmp(&rose_callsign, &null_ax25_address) == 0)
 107                rose_call = (ax25_address *)neigh->dev->dev_addr;
 108        else
 109                rose_call = &rose_callsign;
 110
 111        ax25s = neigh->ax25;
 112        neigh->ax25 = ax25_send_frame(skb, 260, rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);
 113        if (ax25s)
 114                ax25_cb_put(ax25s);
 115
 116        return neigh->ax25 != NULL;
 117}
 118
 119/*
 120 *      Interface to ax25_link_up. Changes my level 2 callsign depending
 121 *      on whether we have a global ROSE callsign or use the default port
 122 *      callsign.
 123 */
 124static int rose_link_up(struct rose_neigh *neigh)
 125{
 126        ax25_address *rose_call;
 127        ax25_cb *ax25s;
 128
 129        if (ax25cmp(&rose_callsign, &null_ax25_address) == 0)
 130                rose_call = (ax25_address *)neigh->dev->dev_addr;
 131        else
 132                rose_call = &rose_callsign;
 133
 134        ax25s = neigh->ax25;
 135        neigh->ax25 = ax25_find_cb(rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);
 136        if (ax25s)
 137                ax25_cb_put(ax25s);
 138
 139        return neigh->ax25 != NULL;
 140}
 141
 142/*
 143 *      This handles all restart and diagnostic frames.
 144 */
 145void rose_link_rx_restart(struct sk_buff *skb, struct rose_neigh *neigh, unsigned short frametype)
 146{
 147        struct sk_buff *skbn;
 148
 149        switch (frametype) {
 150        case ROSE_RESTART_REQUEST:
 151                rose_stop_t0timer(neigh);
 152                neigh->restarted = 1;
 153                neigh->dce_mode  = (skb->data[3] == ROSE_DTE_ORIGINATED);
 154                rose_transmit_restart_confirmation(neigh);
 155                break;
 156
 157        case ROSE_RESTART_CONFIRMATION:
 158                rose_stop_t0timer(neigh);
 159                neigh->restarted = 1;
 160                break;
 161
 162        case ROSE_DIAGNOSTIC:
 163                printk(KERN_WARNING "ROSE: received diagnostic #%d - %02X %02X %02X\n", skb->data[3], skb->data[4], skb->data[5], skb->data[6]);
 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
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.