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