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 += skbn->truesize;
  72                 skbn->h.raw = skbn->data;
  73 
  74                 skbo = skb_dequeue(&sk->nr->frag_queue);
  75                 memcpy(skb_put(skbn, skbo->len), skbo->data, skbo->len);
  76                 kfree_skb(skbo, FREE_READ);
  77 
  78                 while ((skbo = skb_dequeue(&sk->nr->frag_queue)) != NULL) {
  79                         skb_pull(skbo, NR_NETWORK_LEN + NR_TRANSPORT_LEN);
  80                         memcpy(skb_put(skbn, skbo->len), skbo->data, skbo->len);
  81                         kfree_skb(skbo, FREE_READ);
  82                 }
  83 
  84                 sk->nr->fraglen = 0;            
  85         }
  86 
  87         return sock_queue_rcv_skb(sk, skbn);
  88 }
  89 
  90 /*
  91  * State machine for state 1, Awaiting Connection State.
  92  * The handling of the timer(s) is in file nr_timer.c.
  93  * Handling of state 0 and connection release is in netrom.c.
  94  */
  95 static int nr_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype)
     /* [previous][next][first][last][top][bottom][index][help] */
  96 {
  97         switch (frametype) {
  98 
  99                 case NR_CONNACK:
 100                         nr_calculate_rtt(sk);
 101                         sk->window         = skb->data[20];
 102                         sk->nr->your_index = skb->data[17];
 103                         sk->nr->your_id    = skb->data[18];
 104                         sk->nr->t1timer    = 0;
 105                         sk->nr->t2timer    = 0;
 106                         sk->nr->t4timer    = 0;
 107                         sk->nr->vs         = 0;
 108                         sk->nr->va         = 0;
 109                         sk->nr->vr         = 0;
 110                         sk->nr->vl         = 0;
 111                         sk->nr->state      = NR_STATE_3;
 112                         sk->state          = TCP_ESTABLISHED;
 113                         sk->nr->n2count    = 0;
 114                         /* For WAIT_SABM connections we will produce an accept ready socket here */
 115                         if (!sk->dead)
 116                                 sk->state_change(sk);
 117                         break;
 118 
 119                 case NR_CONNACK | NR_CHOKE_FLAG:
 120                         nr_clear_queues(sk);
 121                         sk->nr->state = NR_STATE_0;
 122                         sk->state     = TCP_CLOSE;
 123                         sk->err       = ECONNREFUSED;
 124                         if (!sk->dead)
 125                                 sk->state_change(sk);
 126                         sk->dead      = 1;
 127                         break;
 128 
 129                 default:
 130                         break;
 131         }
 132 
 133         return 0;
 134 }
 135 
 136 /*
 137  * State machine for state 2, Awaiting Release State.
 138  * The handling of the timer(s) is in file nr_timer.c
 139  * Handling of state 0 and connection release is in netrom.c.
 140  */
 141 static int nr_state2_machine(struct sock *sk, struct sk_buff *skb, int frametype)
     /* [previous][next][first][last][top][bottom][index][help] */
 142 {
 143         switch (frametype) {
 144 
 145                 case NR_DISCREQ:
 146                         nr_write_internal(sk, NR_DISCACK);
 147                         break;
 148 
 149                 case NR_DISCACK:
 150                         sk->nr->state = NR_STATE_0;
 151                         sk->state     = TCP_CLOSE;
 152                         sk->err       = 0;
 153                         if (!sk->dead)
 154                                 sk->state_change(sk);
 155                         sk->dead      = 1;
 156                         break;
 157 
 158                 default:
 159                         break;
 160         }
 161 
 162         return 0;
 163 }
 164 
 165 /*
 166  * State machine for state 3, Connected State.
 167  * The handling of the timer(s) is in file nr_timer.c
 168  * Handling of state 0 and connection release is in netrom.c.
 169  */
 170 static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype)
     /* [previous][next][first][last][top][bottom][index][help] */
 171 {
 172         struct sk_buff_head temp_queue;
 173         struct sk_buff *skbn;
 174         unsigned short save_vr;
 175         unsigned short nr, ns;
 176         int queued = 0;
 177 
 178         nr = skb->data[18];
 179         ns = skb->data[17];
 180 
 181         switch (frametype) {
 182 
 183                 case NR_CONNREQ:
 184                         nr_write_internal(sk, NR_CONNACK);
 185                         sk->nr->condition = 0x00;
 186                         sk->nr->t1timer   = 0;
 187                         sk->nr->t2timer   = 0;
 188                         sk->nr->t4timer   = 0;
 189                         sk->nr->vs        = 0;
 190                         sk->nr->va        = 0;
 191                         sk->nr->vr        = 0;
 192                         sk->nr->vl        = 0;
 193                         break;
 194 
 195                 case NR_DISCREQ:
 196                         nr_clear_queues(sk);
 197                         nr_write_internal(sk, NR_DISCACK);
 198                         sk->nr->state = NR_STATE_0;
 199                         sk->state     = TCP_CLOSE;
 200                         sk->err       = 0;
 201                         if (!sk->dead)
 202                                 sk->state_change(sk);
 203                         sk->dead      = 1;
 204                         break;
 205 
 206                 case NR_DISCACK:
 207                         nr_clear_queues(sk);
 208                         sk->nr->state = NR_STATE_0;
 209                         sk->state     = TCP_CLOSE;
 210                         sk->err       = ECONNRESET;
 211                         if (!sk->dead)
 212                                 sk->state_change(sk);
 213                         sk->dead      = 1;
 214                         break;
 215 
 216                 case NR_INFOACK:
 217                 case NR_INFOACK | NR_CHOKE_FLAG:
 218                         if (frametype & NR_CHOKE_FLAG) {
 219                                 sk->nr->condition |= PEER_RX_BUSY_CONDITION;
 220                                 sk->nr->t4timer = nr_default.busy_delay;
 221                         } else {
 222                                 sk->nr->condition &= ~PEER_RX_BUSY_CONDITION;
 223                                 sk->nr->t4timer = 0;
 224                         }
 225                         if (!nr_validate_nr(sk, nr)) {
 226                                 nr_nr_error_recovery(sk);
 227                                 sk->nr->state = NR_STATE_1;
 228                                 break;
 229                         }
 230                         if (sk->nr->condition & PEER_RX_BUSY_CONDITION) {
 231                                 nr_frames_acked(sk, nr);
 232                         } else {
 233                                 nr_check_iframes_acked(sk, nr);
 234                         }
 235                         break;
 236                         
 237                 case NR_INFOACK | NR_NAK_FLAG:
 238                 case NR_INFOACK | NR_NAK_FLAG | NR_CHOKE_FLAG:
 239                         if (frametype & NR_CHOKE_FLAG) {
 240                                 sk->nr->condition |= PEER_RX_BUSY_CONDITION;
 241                                 sk->nr->t4timer = nr_default.busy_delay;
 242                         } else {
 243                                 sk->nr->condition &= ~PEER_RX_BUSY_CONDITION;
 244                                 sk->nr->t4timer = 0;
 245                         }
 246                         if (nr_validate_nr(sk, nr)) {
 247                                 nr_frames_acked(sk, nr);
 248                                 nr_send_nak_frame(sk);
 249                         } else {
 250                                 nr_nr_error_recovery(sk);
 251                                 sk->nr->state = NR_STATE_1;
 252                         }
 253                         break;
 254                         
 255                 case NR_INFO:
 256                 case NR_INFO | NR_CHOKE_FLAG:
 257                 case NR_INFO | NR_MORE_FLAG:
 258                 case NR_INFO | NR_CHOKE_FLAG | NR_MORE_FLAG:
 259                         if (frametype & NR_CHOKE_FLAG) {
 260                                 sk->nr->condition |= PEER_RX_BUSY_CONDITION;
 261                                 sk->nr->t4timer = nr_default.busy_delay;
 262                         } else {
 263                                 sk->nr->condition &= ~PEER_RX_BUSY_CONDITION;
 264                                 sk->nr->t4timer = 0;
 265                         }
 266                         if (!nr_validate_nr(sk, nr)) {
 267                                 nr_nr_error_recovery(sk);
 268                                 sk->nr->state = NR_STATE_1;
 269                                 break;
 270                         }
 271                         if (sk->nr->condition & PEER_RX_BUSY_CONDITION) {
 272                                 nr_frames_acked(sk, nr);
 273                         } else {
 274                                 nr_check_iframes_acked(sk, nr);
 275                         }
 276                         queued = 1;
 277                         skb_queue_head(&sk->nr->reseq_queue, skb);
 278                         if (sk->nr->condition & OWN_RX_BUSY_CONDITION)
 279                                 break;
 280                         skb_queue_head_init(&temp_queue);
 281                         do {
 282                                 save_vr = sk->nr->vr;
 283                                 while ((skbn = skb_dequeue(&sk->nr->reseq_queue)) != NULL) {
 284                                         ns = skbn->data[17];
 285                                         if (ns == sk->nr->vr) {
 286                                                 if (nr_queue_rx_frame(sk, skbn, frametype & NR_MORE_FLAG) == 0) {
 287                                                         sk->nr->vr = (sk->nr->vr + 1) % NR_MODULUS;
 288                                                 } else {
 289                                                         sk->nr->condition |= OWN_RX_BUSY_CONDITION;
 290                                                         skb_queue_tail(&temp_queue, skbn);
 291                                                 }
 292                                         } else if (nr_in_rx_window(sk, ns)) {
 293                                                 skb_queue_tail(&temp_queue, skbn);
 294                                         } else {
 295                                                 skbn->free = 1;
 296                                                 kfree_skb(skbn, FREE_READ);
 297                                         }
 298                                 }
 299                                 while ((skbn = skb_dequeue(&temp_queue)) != NULL) {
 300                                         skb_queue_tail(&sk->nr->reseq_queue, skbn);
 301                                 }
 302                         } while (save_vr != sk->nr->vr);
 303                         /*
 304                          * Window is full, ack it immediately.
 305                          */
 306                         if (((sk->nr->vl + sk->window) % NR_MODULUS) == sk->nr->vr) {
 307                                 nr_enquiry_response(sk);
 308                         } else {
 309                                 if (!(sk->nr->condition & ACK_PENDING_CONDITION)) {
 310                                         sk->nr->t2timer = sk->nr->t2;
 311                                         sk->nr->condition |= ACK_PENDING_CONDITION;
 312                                 }
 313                         }
 314                         break;
 315 
 316                 default:
 317                         break;
 318         }
 319 
 320         return queued;
 321 }
 322 
 323 /* Higher level upcall for a LAPB frame */
 324 int nr_process_rx_frame(struct sock *sk, struct sk_buff *skb)
     /* [previous][next][first][last][top][bottom][index][help] */
 325 {
 326         int queued = 0, frametype;
 327 
 328         if (sk->nr->state != NR_STATE_1 && sk->nr->state != NR_STATE_2 &&
 329             sk->nr->state != NR_STATE_3) {
 330                 printk("nr_process_rx_frame: frame received - state: %d\n", sk->nr->state);
 331                 return queued;
 332         }
 333 
 334         del_timer(&sk->timer);
 335 
 336         frametype = skb->data[19];
 337 
 338         switch (sk->nr->state)
 339         {
 340                 case NR_STATE_1:
 341                         queued = nr_state1_machine(sk, skb, frametype);
 342                         break;
 343                 case NR_STATE_2:
 344                         queued = nr_state2_machine(sk, skb, frametype);
 345                         break;
 346                 case NR_STATE_3:
 347                         queued = nr_state3_machine(sk, skb, frametype);
 348                         break;
 349         }
 350 
 351         nr_set_timer(sk);
 352 
 353         return queued;
 354 }
 355 
 356 #endif

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