root/net/netrom/nr_subr.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nr_clear_queues
  2. nr_frames_acked
  3. nr_requeue_frames
  4. nr_validate_nr
  5. nr_in_rx_window
  6. nr_write_internal
  7. nr_transmit_dm
  8. nr_calculate_t1
  9. nr_calculate_rtt

   1 /*
   2  *      NET/ROM release 003
   3  *
   4  *      This is ALPHA test software. This code may break your machine, randomly fail to work with new 
   5  *      releases, misbehave and/or generally screw up. It might even work. 
   6  *
   7  *      This code REQUIRES 1.2.1 or higher/ NET3.029
   8  *
   9  *      This module:
  10  *              This module is free software; you can redistribute it and/or
  11  *              modify it under the terms of the GNU General Public License
  12  *              as published by the Free Software Foundation; either version
  13  *              2 of the License, or (at your option) any later version.
  14  *
  15  *      History
  16  *      NET/ROM 001     Jonathan(G4KLX) Cloned from ax25_subr.c
  17  *      NET/ROM 003     Jonathan(G4KLX) Added G8BPQ NET/ROM extensions.
  18  */
  19  
  20 #include <linux/config.h>
  21 #ifdef CONFIG_NETROM
  22 #include <linux/errno.h>
  23 #include <linux/types.h>
  24 #include <linux/socket.h>
  25 #include <linux/in.h>
  26 #include <linux/kernel.h>
  27 #include <linux/sched.h>
  28 #include <linux/timer.h>
  29 #include <linux/string.h>
  30 #include <linux/sockios.h>
  31 #include <linux/net.h>
  32 #include <net/ax25.h>
  33 #include <linux/inet.h>
  34 #include <linux/netdevice.h>
  35 #include <linux/skbuff.h>
  36 #include <net/sock.h>
  37 #include <asm/segment.h>
  38 #include <asm/system.h>
  39 #include <linux/fcntl.h>
  40 #include <linux/mm.h>
  41 #include <linux/interrupt.h>
  42 #include <net/netrom.h>
  43 
  44 /*
  45  *      This routine purges all of the queues of frames.
  46  */
  47 void nr_clear_queues(struct sock *sk)
     /* [previous][next][first][last][top][bottom][index][help] */
  48 {
  49         struct sk_buff *skb;
  50 
  51         while ((skb = skb_dequeue(&sk->write_queue)) != NULL) {
  52                 skb->sk   = sk;
  53                 skb->free = 1;
  54                 kfree_skb(skb, FREE_WRITE);
  55         }
  56 
  57         while ((skb = skb_dequeue(&sk->nr->ack_queue)) != NULL) {
  58                 skb->sk   = sk;
  59                 skb->free = 1;
  60                 kfree_skb(skb, FREE_WRITE);
  61         }
  62 
  63         while ((skb = skb_dequeue(&sk->nr->reseq_queue)) != NULL) {
  64                 kfree_skb(skb, FREE_READ);
  65         }
  66 
  67         while ((skb = skb_dequeue(&sk->nr->frag_queue)) != NULL) {
  68                 kfree_skb(skb, FREE_READ);
  69         }
  70 }
  71 
  72 /*
  73  * This routine purges the input queue of those frames that have been
  74  * acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the
  75  * SDL diagram.
  76  */
  77 void nr_frames_acked(struct sock *sk, unsigned short nr)
     /* [previous][next][first][last][top][bottom][index][help] */
  78 {
  79         struct sk_buff *skb;
  80 
  81         /*
  82          * Remove all the ack-ed frames from the ack queue.
  83          */
  84         if (sk->nr->va != nr) {
  85                 while (skb_peek(&sk->nr->ack_queue) != NULL && sk->nr->va != nr) {
  86                         skb = skb_dequeue(&sk->nr->ack_queue);
  87                         skb->sk   = sk;
  88                         skb->free = 1;
  89                         kfree_skb(skb, FREE_WRITE);
  90                         sk->nr->va = (sk->nr->va + 1) % NR_MODULUS;
  91                 }
  92         }
  93 }
  94 
  95 /*
  96  * Requeue all the un-ack-ed frames on the output queue to be picked
  97  * up by nr_kick called from the timer. This arrangement handles the
  98  * possibility of an empty output queue.
  99  */
 100 void nr_requeue_frames(struct sock *sk)
     /* [previous][next][first][last][top][bottom][index][help] */
 101 {
 102         struct sk_buff *skb, *skb_prev = NULL;
 103 
 104         while ((skb = skb_dequeue(&sk->nr->ack_queue)) != NULL) {
 105                 if (skb_prev == NULL)
 106                         skb_queue_head(&sk->write_queue, skb);
 107                 else
 108                         skb_append(skb_prev, skb);
 109                 skb_prev = skb;
 110         }
 111 }
 112 
 113 /*
 114  *      Validate that the value of nr is between va and vs. Return true or
 115  *      false for testing.
 116  */
 117 int nr_validate_nr(struct sock *sk, unsigned short nr)
     /* [previous][next][first][last][top][bottom][index][help] */
 118 {
 119         unsigned short vc = sk->nr->va;
 120 
 121         while (vc != sk->nr->vs) {
 122                 if (nr == vc) return 1;
 123                 vc = (vc + 1) % NR_MODULUS;
 124         }
 125         
 126         if (nr == sk->nr->vs) return 1;
 127 
 128         return 0;
 129 }
 130 
 131 /*
 132  *      Check that ns is within the receive window.
 133  */
 134 int nr_in_rx_window(struct sock *sk, unsigned short ns)
     /* [previous][next][first][last][top][bottom][index][help] */
 135 {
 136         unsigned short vc = sk->nr->vr;
 137         unsigned short vt = (sk->nr->vl + sk->window) % NR_MODULUS;
 138 
 139         while (vc != vt) {
 140                 if (ns == vc) return 1;
 141                 vc = (vc + 1) % NR_MODULUS;
 142         }
 143 
 144         return 0;
 145 }
 146 
 147 /* 
 148  *  This routine is called when the HDLC layer internally generates a
 149  *  control frame.
 150  */
 151 void nr_write_internal(struct sock *sk, int frametype)
     /* [previous][next][first][last][top][bottom][index][help] */
 152 {
 153         struct sk_buff *skb;
 154         unsigned char  *dptr;
 155         int len, timeout;
 156 
 157         len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + NR_NETWORK_LEN + NR_TRANSPORT_LEN;
 158         
 159         switch (frametype & 0x0F) {
 160                 case NR_CONNREQ:
 161                         len += 17;
 162                         break;
 163                 case NR_CONNACK:
 164                         len += (sk->nr->bpqext) ? 2 : 1;
 165                         break;
 166                 case NR_DISCREQ:
 167                 case NR_DISCACK:
 168                 case NR_INFOACK:
 169                         break;
 170                 default:
 171                         printk("nr_write_internal: invalid frame type %d\n", frametype);
 172                         return;
 173         }
 174         
 175         if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
 176                 return;
 177 
 178         /*
 179          *      Space for AX.25 and NET/ROM network header
 180          */
 181         skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + NR_NETWORK_LEN);
 182         
 183         dptr = skb_put(skb, skb_tailroom(skb));
 184 
 185         switch (frametype & 0x0F) {
 186 
 187                 case NR_CONNREQ:
 188                         timeout  = (sk->nr->rtt / PR_SLOWHZ) * 2;
 189                         *dptr++  = sk->nr->my_index;
 190                         *dptr++  = sk->nr->my_id;
 191                         *dptr++  = 0;
 192                         *dptr++  = 0;
 193                         *dptr++  = frametype;
 194                         *dptr++  = sk->window;
 195                         memcpy(dptr, &sk->nr->user_addr, AX25_ADDR_LEN);
 196                         dptr[6] &= ~LAPB_C;
 197                         dptr[6] &= ~LAPB_E;
 198                         dptr[6] |= SSSID_SPARE;
 199                         dptr    += AX25_ADDR_LEN;
 200                         memcpy(dptr, &sk->nr->source_addr, AX25_ADDR_LEN);
 201                         dptr[6] &= ~LAPB_C;
 202                         dptr[6] &= ~LAPB_E;
 203                         dptr[6] |= SSSID_SPARE;
 204                         dptr    += AX25_ADDR_LEN;
 205                         *dptr++  = timeout % 256;
 206                         *dptr++  = timeout / 256;
 207                         break;
 208 
 209                 case NR_CONNACK:
 210                         *dptr++ = sk->nr->your_index;
 211                         *dptr++ = sk->nr->your_id;
 212                         *dptr++ = sk->nr->my_index;
 213                         *dptr++ = sk->nr->my_id;
 214                         *dptr++ = frametype;
 215                         *dptr++ = sk->window;
 216                         if (sk->nr->bpqext) *dptr++ = nr_default.ttl;
 217                         break;
 218 
 219                 case NR_DISCREQ:
 220                 case NR_DISCACK:
 221                         *dptr++ = sk->nr->your_index;
 222                         *dptr++ = sk->nr->your_id;
 223                         *dptr++ = 0;
 224                         *dptr++ = 0;
 225                         *dptr++ = frametype;
 226                         break;
 227 
 228                 case NR_INFOACK:
 229                         *dptr++ = sk->nr->your_index;
 230                         *dptr++ = sk->nr->your_id;
 231                         *dptr++ = 0;
 232                         *dptr++ = sk->nr->vr;
 233                         *dptr++ = frametype;
 234                         break;
 235         }
 236 
 237         skb->free = 1;
 238 
 239         nr_transmit_buffer(sk, skb);
 240 }
 241 
 242 /*
 243  * This routine is called when a Connect Acknowledge with the Choke Flag
 244  * set is needed to refuse a connection.
 245  */
 246 void nr_transmit_dm(struct sk_buff *skb)
     /* [previous][next][first][last][top][bottom][index][help] */
 247 {
 248         struct sk_buff *skbn;
 249         unsigned char *dptr;
 250         int len;
 251 
 252         len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + NR_NETWORK_LEN + NR_TRANSPORT_LEN + 1;
 253 
 254         if ((skbn = alloc_skb(len, GFP_ATOMIC)) == NULL)
 255                 return;
 256 
 257         skb_reserve(skbn, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN);
 258 
 259         dptr = skb_put(skbn, NR_NETWORK_LEN + NR_TRANSPORT_LEN);
 260 
 261         memcpy(dptr, skb->data + 7, AX25_ADDR_LEN);
 262         dptr[6] &= ~LAPB_C;
 263         dptr[6] &= ~LAPB_E;
 264         dptr[6] |= SSSID_SPARE;
 265         dptr += AX25_ADDR_LEN;
 266         
 267         memcpy(dptr, skb->data + 0, AX25_ADDR_LEN);
 268         dptr[6] &= ~LAPB_C;
 269         dptr[6] |= LAPB_E;
 270         dptr[6] |= SSSID_SPARE;
 271         dptr += AX25_ADDR_LEN;
 272 
 273         *dptr++ = nr_default.ttl;
 274 
 275         *dptr++ = skb->data[15];
 276         *dptr++ = skb->data[16];
 277         *dptr++ = 0;
 278         *dptr++ = 0;
 279         *dptr++ = NR_CONNACK | NR_CHOKE_FLAG;
 280         *dptr++ = 0;
 281 
 282         skbn->free = 1;
 283         skbn->sk   = NULL;
 284 
 285         if (!nr_route_frame(skbn, NULL))
 286                 kfree_skb(skbn, FREE_WRITE);
 287 }
 288 
 289 /*
 290  *      Exponential backoff for NET/ROM
 291  */
 292 unsigned short nr_calculate_t1(struct sock *sk)
     /* [previous][next][first][last][top][bottom][index][help] */
 293 {
 294         int n, t;
 295         
 296         for (t = 2, n = 0; n < sk->nr->n2count; n++)
 297                 t *= 2;
 298 
 299         if (t > 8) t = 8;
 300 
 301         return t * sk->nr->rtt;
 302 }
 303 
 304 /*
 305  *      Calculate the Round Trip Time
 306  */
 307 void nr_calculate_rtt(struct sock *sk)
     /* [previous][next][first][last][top][bottom][index][help] */
 308 {
 309         if (sk->nr->t1timer > 0 && sk->nr->n2count == 0)
 310                 sk->nr->rtt = (9 * sk->nr->rtt + sk->nr->t1 - sk->nr->t1timer) / 10;
 311 
 312 #ifdef  NR_T1CLAMPLO
 313         /* Don't go below one tenth of a second */
 314         if (sk->nr->rtt < (NR_T1CLAMPLO))
 315                 sk->nr->rtt = (NR_T1CLAMPLO);
 316 #else   /* Failsafe - some people might have sub 1/10th RTTs :-) **/
 317         if (sk->nr->rtt == 0)
 318                 sk->nr->rtt = PR_SLOWHZ;
 319 #endif
 320 #ifdef  NR_T1CLAMPHI
 321         /* OR above clamped seconds **/
 322         if (sk->nr->rtt > (NR_T1CLAMPHI))
 323                 sk->nr->rtt = (NR_T1CLAMPHI);
 324 #endif
 325 }
 326 
 327 #endif

/* [previous][next][first][last][top][bottom][index][help] */