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 <net/ax25.h>
  20#include <linux/inet.h>
  21#include <linux/netdevice.h>
  22#include <linux/skbuff.h>
  23#include <net/sock.h>
  24#include <asm/system.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
 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        neigh->ax25 = ax25_send_frame(skb, 260, rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);
 111
 112        return (neigh->ax25 != NULL);
 113}
 114
 115/*
 116 *      Interface to ax25_link_up. Changes my level 2 callsign depending
 117 *      on whether we have a global ROSE callsign or use the default port
 118 *      callsign.
 119 */
 120static int rose_link_up(struct rose_neigh *neigh)
 121{
 122        ax25_address *rose_call;
 123
 124        if (ax25cmp(&rose_callsign, &null_ax25_address) == 0)
 125                rose_call = (ax25_address *)neigh->dev->dev_addr;
 126        else
 127                rose_call = &rose_callsign;
 128
 129        neigh->ax25 = ax25_find_cb(rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);
 130
 131        return (neigh->ax25 != NULL);
 132}
 133
 134/*
 135 *      This handles all restart and diagnostic frames.
 136 */
 137void rose_link_rx_restart(struct sk_buff *skb, struct rose_neigh *neigh, unsigned short frametype)
 138{
 139        struct sk_buff *skbn;
 140
 141        switch (frametype) {
 142        case ROSE_RESTART_REQUEST:
 143                rose_stop_t0timer(neigh);
 144                neigh->restarted = 1;
 145                neigh->dce_mode  = (skb->data[3] == ROSE_DTE_ORIGINATED);
 146                rose_transmit_restart_confirmation(neigh);
 147                break;
 148
 149        case ROSE_RESTART_CONFIRMATION:
 150                rose_stop_t0timer(neigh);
 151                neigh->restarted = 1;
 152                break;
 153
 154        case ROSE_DIAGNOSTIC:
 155                printk(KERN_WARNING "ROSE: received diagnostic #%d - %02X %02X %02X\n", skb->data[3], skb->data[4], skb->data[5], skb->data[6]);
 156                break;
 157
 158        default:
 159                printk(KERN_WARNING "ROSE: received unknown %02X with LCI 000\n", frametype);
 160                break;
 161        }
 162
 163        if (neigh->restarted) {
 164                while ((skbn = skb_dequeue(&neigh->queue)) != NULL)
 165                        if (!rose_send_frame(skbn, neigh))
 166                                kfree_skb(skbn);
 167        }
 168}
 169
 170/*
 171 *      This routine is called when a Restart Request is needed
 172 */
 173static void rose_transmit_restart_request(struct rose_neigh *neigh)
 174{
 175        struct sk_buff *skb;
 176        unsigned char *dptr;
 177        int len;
 178
 179        len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN + 3;
 180
 181        if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
 182                return;
 183
 184        skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN);
 185
 186        dptr = skb_put(skb, ROSE_MIN_LEN + 3);
 187
 188        *dptr++ = AX25_P_ROSE;
 189        *dptr++ = ROSE_GFI;
 190        *dptr++ = 0x00;
 191        *dptr++ = ROSE_RESTART_REQUEST;
 192        *dptr++ = ROSE_DTE_ORIGINATED;
 193        *dptr++ = 0;
 194
 195        if (!rose_send_frame(skb, neigh))
 196                kfree_skb(skb);
 197}
 198
 199/*
 200 * This routine is called when a Restart Confirmation is needed
 201 */
 202static void rose_transmit_restart_confirmation(struct rose_neigh *neigh)
 203{
 204        struct sk_buff *skb;
 205        unsigned char *dptr;
 206        int len;
 207
 208        len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN + 1;
 209
 210        if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
 211                return;
 212
 213        skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN);
 214
 215        dptr = skb_put(skb, ROSE_MIN_LEN + 1);
 216
 217        *dptr++ = AX25_P_ROSE;
 218        *dptr++ = ROSE_GFI;
 219        *dptr++ = 0x00;
 220        *dptr++ = ROSE_RESTART_CONFIRMATION;
 221
 222        if (!rose_send_frame(skb, neigh))
 223                kfree_skb(skb);
 224}
 225
 226/*
 227 * This routine is called when a Clear Request is needed outside of the context
 228 * of a connected socket.
 229 */
 230void rose_transmit_clear_request(struct rose_neigh *neigh, unsigned int lci, unsigned char cause, unsigned char diagnostic)
 231{
 232        struct sk_buff *skb;
 233        unsigned char *dptr;
 234        int len;
 235
 236        len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN + 3;
 237
 238        if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
 239                return;
 240
 241        skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN);
 242
 243        dptr = skb_put(skb, ROSE_MIN_LEN + 3);
 244
 245        *dptr++ = AX25_P_ROSE;
 246        *dptr++ = ((lci >> 8) & 0x0F) | ROSE_GFI;
 247        *dptr++ = ((lci >> 0) & 0xFF);
 248        *dptr++ = ROSE_CLEAR_REQUEST;
 249        *dptr++ = cause;
 250        *dptr++ = diagnostic;
 251
 252        if (!rose_send_frame(skb, neigh))
 253                kfree_skb(skb);
 254}
 255
 256void rose_transmit_link(struct sk_buff *skb, struct rose_neigh *neigh)
 257{
 258        unsigned char *dptr;
 259
 260#if 0
 261        if (call_fw_firewall(PF_ROSE, skb->dev, skb->data, NULL, &skb) != FW_ACCEPT) {
 262                kfree_skb(skb);
 263                return;
 264        }
 265#endif
 266
 267        if (neigh->loopback) {
 268                rose_loopback_queue(skb, neigh);
 269                return;
 270        }
 271
 272        if (!rose_link_up(neigh))
 273                neigh->restarted = 0;
 274
 275        dptr = skb_push(skb, 1);
 276        *dptr++ = AX25_P_ROSE;
 277
 278        if (neigh->restarted) {
 279                if (!rose_send_frame(skb, neigh))
 280                        kfree_skb(skb);
 281        } else {
 282                skb_queue_tail(&neigh->queue, skb);
 283
 284                if (!rose_t0timer_running(neigh)) {
 285                        rose_transmit_restart_request(neigh);
 286                        neigh->dce_mode = 0;
 287                        rose_start_t0timer(neigh);
 288                }
 289        }
 290}
 291