root/net/netrom/nr_in.c

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

DEFINITIONS

This source file includes following definitions.
  1. nr_queue_rx_frame
  2. nr_state1_machine
  3. nr_state2_machine
  4. nr_state3_machine
  5. nr_process_rx_frame

   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  *      Most of this code is based on the SDL diagrams published in the 7th
  16  *      ARRL Computer Networking Conference papers. The diagrams have mistakes
  17  *      in them, but are mostly correct. Before you modify the code could you
  18  *      read the SDL diagrams as the code is not obvious and probably very
  19  *      easy to break;
  20  *
  21  *      History
  22  *      NET/ROM 001     Jonathan(G4KLX) Cloned from ax25_in.c
  23  *      NET/ROM 003     Jonathan(G4KLX) Added NET/ROM fragment reception.
  24  */
  25 
  26 #include <linux/config.h>
  27 #ifdef CONFIG_NETROM
  28 #include <linux/errno.h>
  29 #include <linux/types.h>
  30 #include <linux/socket.h>
  31 #include <linux/in.h>
  32 #include <linux/kernel.h>
  33 #include <linux/sched.h>
  34 #include <linux/timer.h>
  35 #include <linux/string.h>
  36 #include <linux/sockios.h>
  37 #include <linux/net.h>
  38 #include <net/ax25.h>
  39 #include <linux/inet.h>
  40 #include <linux/netdevice.h>
  41 #include <linux/skbuff.h>
  42 #include <net/sock.h>
  43 #include <net/ip.h>                     /* For ip_rcv */
  44 #include <asm/segment.h>
  45 #include <asm/system.h>
  46 #include <linux/fcntl.h>
  47 #include <linux/mm.h>
  48 #include <linux/interrupt.h>
  49 #include <net/netrom.h>
  50 
  51 static int nr_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
     /* [previous][next][first][last][top][bottom][index][help] */
  52 {
  53         struct sk_buff *skbo, *skbn = skb;
  54 
  55         if (more) {
  56                 sk->nr->fraglen += skb->len;
  57                 skb_queue_tail(&sk->nr->frag_queue, skb);
  58                 return 0;
  59         }
  60         
  61         if (!more && sk->nr->fraglen > 0) {     /* End of fragment */
  62                 sk->nr->fraglen += skb->len;
  63                 skb_queue_tail(&sk->nr->frag_queue, skb);
  64 
  65                 if ((skbn = alloc_skb(sk->nr->fraglen, GFP_ATOMIC)) == NULL)
  66                         return 1;
  67 
  68                 skbn->free = 1;
  69                 skbn->arp  = 1;
  70                 skbn->sk   = sk;
  71                 sk->rmem_alloc += skb->truesize;
  72                         
  73                 while ((skbo = skb_dequeue(&sk->nr->frag_queue)) != NULL) {
  74                         memcpy(skb_put(skbn, skbo->len), skbo->data, skbo->len);
  75 
  76                         kfree_skb(skbo, FREE_READ);
  77                 }
  78 
  79                 sk->nr->fraglen = 0;            
  80         }
  81 
  82         return sock_queue_rcv_skb(sk, skbn);
  83 }
  84 
  85 /*
  86  * State machine for state 1, Awaiting Connection State.
  87  * The handling of the timer(s) is in file nr_timer.c.
  88  * Handling of state 0 and connection release is in netrom.c.
  89  */
  90 static int nr_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype)
     /* [previous][next][first][last][top][bottom][index][help] */
  91 {
  92         switch (frametype) {
  93 
  94                 case NR_CONNACK:
  95                         nr_calculate_rtt(sk);
  96                         sk->window         = skb->data[5];
  97                         sk->nr->your_index = skb->data[2];
  98                         sk->nr->your_id    = skb->data[3];
  99                         sk->nr->t1timer    = 0;
 100                         sk->nr->t2timer    = 0;
 101                         sk->nr->t4timer    = 0;
 102                         sk->nr->vs         = 0;
 103                         sk->nr->va         = 0;
 104                         sk->nr->vr         = 0;
 105                         sk->nr->vl         = 0;
 106                         sk->nr->state      = NR_STATE_3;
 107                         sk->state          = TCP_ESTABLISHED;
 108                         sk->nr->n2count    = 0;
 109                         /* For WAIT_SABM connections we will produce an accept ready socket here */
 110                         if (!sk->dead)
 111                                 sk->state_change(sk);
 112                         break;
 113 
 114                 case NR_CONNACK | NR_CHOKE_FLAG:
 115                         nr_clear_queues(sk);
 116                         sk->nr->state = NR_STATE_0;
 117                         sk->state     = TCP_CLOSE;
 118                         sk->err       = ECONNREFUSED;
 119                         if (!sk->dead)
 120                                 sk->state_change(sk);
 121                         sk->dead      = 1;
 122                         break;
 123 
 124                 default:
 125                         break;
 126         }
 127 
 128         return 0;
 129 }
 130 
 131 /*
 132  * State machine for state 2, Awaiting Release State.
 133  * The handling of the timer(s) is in file nr_timer.c
 134  * Handling of state 0 and connection release is in netrom.c.
 135  */
 136 static int nr_state2_machine(struct sock *sk, struct sk_buff *skb, int frametype)
     /* [previous][next][first][last][top][bottom][index][help] */
 137 {
 138         switch (frametype) {
 139 
 140                 case NR_DISCREQ:
 141                         nr_write_internal(sk, NR_DISCACK);
 142                         break;
 143 
 144                 case NR_DISCACK:
 145                         sk->nr->state = NR_STATE_0;
 146                         sk->state     = TCP_CLOSE;
 147                         sk->err       = 0;
 148                         if (!sk->dead)
 149                                 sk->state_change(sk);
 150                         sk->dead      = 1;
 151                         break;
 152 
 153                 default:
 154                         break;
 155         }
 156 
 157         return 0;
 158 }
 159 
 160 /*
 161  * State machine for state 3, Connected State.
 162  * The handling of the timer(s) is in file nr_timer.c
 163  * Handling of state 0 and connection release is in netrom.c.
 164  */
 165 static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype)
     /* [previous][next][first][last][top][bottom][index][help] */
 166 {
 167         struct sk_buff_head temp_queue;
 168         struct sk_buff *skbn;
 169         unsigned short save_vr;
 170         unsigned short nr, ns;
 171         int queued = 0;
 172 
 173         nr = skb->data[3];
 174         ns = skb->data[2];
 175 
 176         switch (frametype) {
 177 
 178                 case NR_CONNREQ:
 179                         nr_write_internal(sk, NR_CONNACK);
 180                         sk->nr->condition = 0x00;
 181                         sk->nr->t1timer   = 0;
 182                         sk->nr->t2timer   = 0;
 183                         sk->nr->t4timer   = 0;
 184                         sk->nr->vs        = 0;
 185                         sk->nr->va        = 0;
 186                         sk->nr->vr        = 0;
 187                         sk->nr->vl        = 0;
 188                         break;
 189 
 190                 case NR_DISCREQ:
 191                         nr_clear_queues(sk);
 192                         nr_write_internal(sk, NR_DISCACK);
 193                         sk->nr->state = NR_STATE_0;
 194                         sk->state     = TCP_CLOSE;
 195                         sk->err       = 0;
 196                         if (!sk->dead)
 197                                 sk->state_change(sk);
 198                         sk->dead      = 1;
 199                         break;
 200 
 201                 case NR_DISCACK:
 202                         nr_clear_queues(sk);
 203                         sk->nr->state = NR_STATE_0;
 204                         sk->state     = TCP_CLOSE;
 205                         sk->err       = ECONNRESET;
 206                         if (!sk->dead)
 207                                 sk->state_change(sk);
 208                         sk->dead      = 1;
 209                         break;
 210 
 211                 case NR_INFOACK:
 212                 case NR_INFOACK | NR_CHOKE_FLAG:
 213                         if (frametype & NR_CHOKE_FLAG) {
 214                                 sk->nr->condition |= PEER_RX_BUSY_CONDITION;
 215                                 sk->nr->t4timer = nr_default.busy_delay;
 216                         } else {
 217                                 sk->nr->condition &= ~PEER_RX_BUSY_CONDITION;
 218                                 sk->nr->t4timer = 0;
 219                         }
 220                         if (!nr_validate_nr(sk, nr)) {
 221                                 nr_nr_error_recovery(sk);
 222                                 sk->nr->state = NR_STATE_1;
 223                                 break;
 224                         }
 225                         if (sk->nr->condition & PEER_RX_BUSY_CONDITION) {
 226                                 nr_frames_acked(sk, nr);
 227                         } else {
 228                                 nr_check_iframes_acked(sk, nr);
 229                         }
 230                         break;
 231                         
 232                 case NR_INFOACK | NR_NAK_FLAG:
 233                 case NR_INFOACK | NR_NAK_FLAG | NR_CHOKE_FLAG:
 234                         if (frametype & NR_CHOKE_FLAG) {
 235                                 sk->nr->condition |= PEER_RX_BUSY_CONDITION;
 236                                 sk->nr->t4timer = nr_default.busy_delay;
 237                         } else {
 238                                 sk->nr->condition &= ~PEER_RX_BUSY_CONDITION;
 239                                 sk->nr->t4timer = 0;
 240                         }
 241                         if (nr_validate_nr(sk, nr)) {
 242                                 nr_frames_acked(sk, nr);
 243                                 nr_send_nak_frame(sk);
 244                         } else {
 245                                 nr_nr_error_recovery(sk);
 246                                 sk->nr->state = NR_STATE_1;
 247                         }
 248                         break;
 249                         
 250                 case NR_INFO:
 251                 case NR_INFO | NR_CHOKE_FLAG:
 252                 case NR_INFO | NR_MORE_FLAG:
 253                 case NR_INFO | NR_CHOKE_FLAG | NR_MORE_FLAG:
 254                         if (frametype & NR_CHOKE_FLAG) {
 255                                 sk->nr->condition |= PEER_RX_BUSY_CONDITION;
 256                                 sk->nr->t4timer = nr_default.busy_delay;
 257                         } else {
 258                                 sk->nr->condition &= ~PEER_RX_BUSY_CONDITION;
 259                                 sk->nr->t4timer = 0;
 260                         }
 261                         if (!nr_validate_nr(sk, nr)) {
 262                                 nr_nr_error_recovery(sk);
 263                                 sk->nr->state = NR_STATE_1;
 264                                 break;
 265                         }
 266                         if (sk->nr->condition & PEER_RX_BUSY_CONDITION) {
 267                                 nr_frames_acked(sk, nr);
 268                         } else {
 269                                 nr_check_iframes_acked(sk, nr);
 270                         }
 271                         queued = 1;
 272                         skb_queue_head(&sk->nr->reseq_queue, skb);
 273                         if (sk->nr->condition & OWN_RX_BUSY_CONDITION)
 274                                 break;
 275                         skb_queue_head_init(&temp_queue);
 276                         do {
 277                                 save_vr = sk->nr->vr;
 278                                 while ((skbn = skb_dequeue(&sk->nr->reseq_queue)) != NULL) {
 279                                         ns = skbn->data[2];
 280                                         if (ns == sk->nr->vr) {
 281                                                 if (nr_queue_rx_frame(sk, skbn, frametype & NR_MORE_FLAG) == 0) {
 282                                                         sk->nr->vr = (sk->nr->vr + 1) % NR_MODULUS;
 283                                                 } else {
 284                                                         sk->nr->condition |= OWN_RX_BUSY_CONDITION;
 285                                                         skb_queue_tail(&temp_queue, skbn);
 286                                                 }
 287                                         } else if (nr_in_rx_window(sk, ns)) {
 288                                                 skb_queue_tail(&temp_queue, skbn);
 289                                         } else {
 290                                                 skbn->free = 1;
 291                                                 kfree_skb(skbn, FREE_READ);
 292                                         }
 293                                 }
 294                                 while ((skbn = skb_dequeue(&temp_queue)) != NULL) {
 295                                         skb_queue_tail(&sk->nr->reseq_queue, skbn);
 296                                 }
 297                         } while (save_vr != sk->nr->vr);
 298                         /*
 299                          * Window is full, ack it immediately.
 300                          */
 301                         if (((sk->nr->vl + sk->window) % NR_MODULUS) == sk->nr->vr) {
 302                                 nr_enquiry_response(sk);
 303                         } else {
 304                                 if (!(sk->nr->condition & ACK_PENDING_CONDITION)) {
 305                                         sk->nr->t2timer = sk->nr->t2;
 306                                         sk->nr->condition |= ACK_PENDING_CONDITION;
 307                                 }
 308                         }
 309                         break;
 310 
 311                 default:
 312                         break;
 313         }
 314 
 315         return queued;
 316 }
 317 
 318 /* Higher level upcall for a LAPB frame */
 319 int nr_process_rx_frame(struct sock *sk, struct sk_buff *skb)
     /* [previous][next][first][last][top][bottom][index][help] */
 320 {
 321         int queued = 0, frametype;
 322 
 323         if (sk->nr->state != NR_STATE_1 && sk->nr->state != NR_STATE_2 &&
 324             sk->nr->state != NR_STATE_3) {
 325                 printk("nr_process_rx_frame: frame received - state: %d\n", sk->nr->state);
 326                 return queued;
 327         }
 328 
 329         del_timer(&sk->timer);
 330 
 331         frametype = skb->data[4];
 332 
 333         switch (sk->nr->state)
 334         {
 335                 case NR_STATE_1:
 336                         queued = nr_state1_machine(sk, skb, frametype);
 337                         break;
 338                 case NR_STATE_2:
 339                         queued = nr_state2_machine(sk, skb, frametype);
 340                         break;
 341                 case NR_STATE_3:
 342                         queued = nr_state3_machine(sk, skb, frametype);
 343                         break;
 344         }
 345 
 346         nr_set_timer(sk);
 347 
 348         return queued;
 349 }
 350 
 351 #endif

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