root/net/ax25/ax25_out.c

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

DEFINITIONS

This source file includes following definitions.
  1. ax25_output
  2. ax25_send_iframe
  3. ax25_kick
  4. ax25_transmit_buffer
  5. ax25_nr_error_recovery
  6. ax25_establish_data_link
  7. ax25_transmit_enquiry
  8. ax25_enquiry_response
  9. ax25_timeout_response
  10. ax25_check_iframes_acked
  11. ax25_check_need_response

   1 /*
   2  *      AX.25 release 030
   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  *      AX.25 028a      Jonathan(G4KLX) New state machine based on SDL diagrams.
  23  *      AX.25 029       Alan(GW4PTS)    Switched to KA9Q constant names.
  24  *                      Jonathan(G4KLX) Only poll when window is full.
  25  *      AX.25 030       Jonathan(G4KLX) Added fragmentation to ax25_output.
  26  *                                      Added support for extended AX.25.
  27  */
  28 
  29 #include <linux/config.h>
  30 #ifdef CONFIG_AX25
  31 #include <linux/errno.h>
  32 #include <linux/types.h>
  33 #include <linux/socket.h>
  34 #include <linux/in.h>
  35 #include <linux/kernel.h>
  36 #include <linux/sched.h>
  37 #include <linux/timer.h>
  38 #include <linux/string.h>
  39 #include <linux/sockios.h>
  40 #include <linux/net.h>
  41 #include <net/ax25.h>
  42 #include <linux/inet.h>
  43 #include <linux/netdevice.h>
  44 #include <linux/skbuff.h>
  45 #include <net/sock.h>
  46 #include <asm/segment.h>
  47 #include <asm/system.h>
  48 #include <linux/fcntl.h>
  49 #include <linux/mm.h>
  50 #include <linux/interrupt.h>
  51 
  52 /*
  53  * All outgoing AX.25 I frames pass via this routine. Therefore this is
  54  * where the fragmentation of frames takes place.
  55  */
  56 void ax25_output(ax25_cb *ax25, struct sk_buff *skb)
     /* [previous][next][first][last][top][bottom][index][help] */
  57 {
  58         struct sk_buff *skbn;
  59         unsigned char *p;
  60         int err, frontlen, mtu, len, fragno, first = 1;
  61         
  62         mtu = ax25->device->mtu;
  63         
  64         if ((skb->len - 1) > mtu) {
  65                 mtu -= 2;               /* Allow for fragment control info */
  66                 
  67                 fragno = skb->len / mtu;
  68                 if (skb->len % mtu == 0) fragno--;
  69 
  70                 frontlen = skb_headroom(skb);   /* Address space + CTRL */
  71 
  72                 while (skb->len > 0) {
  73                         if (skb->sk != NULL) {
  74                                 if ((skbn = sock_alloc_send_skb(skb->sk, mtu + 2 + frontlen, 0, 0, &err)) == NULL)
  75                                         return;
  76                         } else {
  77                                 if ((skbn = alloc_skb(mtu + 2 + frontlen, GFP_ATOMIC)) == NULL)
  78                                         return;
  79                         }
  80 
  81                         skbn->sk   = skb->sk;
  82                         skbn->free = 1;
  83                         skbn->arp  = 1;
  84 
  85                         skb_reserve(skbn, frontlen + 2);
  86 
  87                         len = (mtu > skb->len) ? skb->len : mtu;
  88                         
  89                         memcpy(skb_put(skbn, len), skb->data, len);
  90                         skb_pull(skb, len);
  91 
  92                         p = skb_push(skbn, 2);
  93 
  94                         *p++ = AX25_P_SEGMENT;
  95 
  96                         *p = fragno--;
  97                         if (first) {
  98                                 *p |= SEG_FIRST;
  99                                 first = 0;
 100                         }
 101 
 102                         skb_queue_tail(&ax25->write_queue, skbn); /* Throw it on the queue */
 103                 }
 104                 
 105                 skb->free = 1;
 106                 kfree_skb(skb, FREE_WRITE);
 107         } else {
 108                 skb_queue_tail(&ax25->write_queue, skb);          /* Throw it on the queue */
 109         }
 110 
 111         if (ax25->state == AX25_STATE_3 || ax25->state == AX25_STATE_4)
 112                 ax25_kick(ax25);
 113 }
 114 
 115 /* 
 116  *  This procedure is passed a buffer descriptor for an iframe. It builds
 117  *  the rest of the control part of the frame and then writes it out.
 118  */
 119 static void ax25_send_iframe(ax25_cb *ax25, struct sk_buff *skb, int poll_bit)
     /* [previous][next][first][last][top][bottom][index][help] */
 120 {
 121         unsigned char *frame;
 122 
 123         if (skb == NULL)
 124                 return;
 125 
 126         if (ax25->modulus == MODULUS) {
 127                 frame = skb_push(skb, 1);
 128 
 129                 *frame = I;
 130                 *frame |= (poll_bit) ? PF : 0;
 131                 *frame |= (ax25->vr << 5);
 132                 *frame |= (ax25->vs << 1);
 133         } else {
 134                 frame = skb_push(skb, 2);
 135 
 136                 frame[0] = I;
 137                 frame[0] |= (ax25->vs << 1);
 138                 frame[1] = (poll_bit) ? EPF : 0;
 139                 frame[1] |= (ax25->vr << 1);
 140         }
 141 
 142         ax25_transmit_buffer(ax25, skb, C_COMMAND);     
 143 }
 144 
 145 void ax25_kick(ax25_cb *ax25)
     /* [previous][next][first][last][top][bottom][index][help] */
 146 {
 147         struct sk_buff *skb, *skbn;
 148         int last = 1;
 149         unsigned short start, end, next;
 150 
 151         del_timer(&ax25->timer);
 152 
 153         start = (skb_peek(&ax25->ack_queue) == NULL) ? ax25->va : ax25->vs;
 154         end   = (ax25->va + ax25->window) % ax25->modulus;
 155 
 156         if (!(ax25->condition & PEER_RX_BUSY_CONDITION) &&
 157             start != end                                   &&
 158             skb_peek(&ax25->write_queue) != NULL) {
 159 
 160                 ax25->vs = start;
 161 
 162                 /*
 163                  * Transmit data until either we're out of data to send or
 164                  * the window is full. Send a poll on the final I frame if
 165                  * the window is filled.
 166                  */
 167 
 168                 /*
 169                  * Dequeue the frame and copy it.
 170                  */
 171                 skb  = skb_dequeue(&ax25->write_queue);
 172 
 173                 do {
 174                         if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) {
 175                                 skb_queue_head(&ax25->write_queue, skb);
 176                                 return;
 177                         }
 178 
 179                         next = (ax25->vs + 1) % ax25->modulus;
 180 #ifdef notdef
 181                         last = (next == end) || skb_peek(&ax25->write_queue) == NULL;
 182 #else
 183                         last = (next == end);
 184 #endif
 185                         /*
 186                          * Transmit the frame copy.
 187                          */
 188                         ax25_send_iframe(ax25, skbn, (last) ? POLLON : POLLOFF);
 189 
 190                         ax25->vs = next;
 191 
 192                         /*
 193                          * Requeue the original data frame.
 194                          */
 195                         skb_queue_tail(&ax25->ack_queue, skb);
 196 #ifdef notdef
 197                 } while (!last);
 198 #else
 199                 } while (!last && (skb = skb_dequeue(&ax25->write_queue)) != NULL);
 200 #endif
 201                 ax25->condition &= ~ACK_PENDING_CONDITION;
 202 
 203                 if (ax25->t1timer == 0) {
 204                         ax25->t3timer = 0;
 205                         ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
 206                 }
 207         }
 208 
 209         ax25_set_timer(ax25);
 210 }
 211 
 212 void ax25_transmit_buffer(ax25_cb *ax25, struct sk_buff *skb, int type)
     /* [previous][next][first][last][top][bottom][index][help] */
 213 {
 214         unsigned char *ptr;
 215 
 216         if (ax25->device == NULL) {
 217                 if (ax25->sk != NULL) {
 218                         ax25->sk->state = TCP_CLOSE;
 219                         ax25->sk->err   = ENETUNREACH;
 220                         if (!ax25->sk->dead)
 221                                 ax25->sk->state_change(ax25->sk);
 222                         ax25->sk->dead  = 1;
 223                 }
 224                 return;
 225         }
 226 
 227         if (skb_headroom(skb) < size_ax25_addr(ax25->digipeat)) {
 228                 printk("ax25_transmit_buffer: not enough room for digi-peaters\n");
 229                 skb->free = 1;
 230                 kfree_skb(skb, FREE_WRITE);
 231                 return;
 232         }
 233 
 234         ptr = skb_push(skb, size_ax25_addr(ax25->digipeat));
 235         build_ax25_addr(ptr, &ax25->source_addr, &ax25->dest_addr, ax25->digipeat, type, ax25->modulus);
 236 
 237         skb->arp = 1;
 238 
 239         ax25_queue_xmit(skb, ax25->device, SOPRI_NORMAL);
 240 }
 241 
 242 /*
 243  * The following routines are taken from page 170 of the 7th ARRL Computer
 244  * Networking Conference paper, as is the whole state machine.
 245  */
 246 
 247 void ax25_nr_error_recovery(ax25_cb *ax25)
     /* [previous][next][first][last][top][bottom][index][help] */
 248 {
 249         ax25_establish_data_link(ax25);
 250 }
 251 
 252 void ax25_establish_data_link(ax25_cb *ax25)
     /* [previous][next][first][last][top][bottom][index][help] */
 253 {
 254         ax25->condition = 0x00;
 255         ax25->n2count   = 0;
 256 
 257         if (ax25->modulus == MODULUS) {
 258                 ax25_send_control(ax25, SABM, POLLON, C_COMMAND);
 259         } else {
 260                 ax25_send_control(ax25, SABME, POLLON, C_COMMAND);
 261         }
 262         
 263         ax25->t3timer = 0;
 264         ax25->t2timer = 0;
 265         ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
 266 }
 267 
 268 void ax25_transmit_enquiry(ax25_cb *ax25)
     /* [previous][next][first][last][top][bottom][index][help] */
 269 {
 270         if (ax25->condition & OWN_RX_BUSY_CONDITION)
 271                 ax25_send_control(ax25, RNR, POLLON, C_COMMAND);
 272         else
 273                 ax25_send_control(ax25, RR, POLLON, C_COMMAND);
 274 
 275         ax25->condition &= ~ACK_PENDING_CONDITION;
 276 
 277         ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
 278 }
 279         
 280 void ax25_enquiry_response(ax25_cb *ax25)
     /* [previous][next][first][last][top][bottom][index][help] */
 281 {
 282         if (ax25->condition & OWN_RX_BUSY_CONDITION)
 283                 ax25_send_control(ax25, RNR, POLLON, C_RESPONSE);
 284         else
 285                 ax25_send_control(ax25, RR, POLLON, C_RESPONSE);
 286 
 287         ax25->condition &= ~ACK_PENDING_CONDITION;
 288 }
 289 
 290 void ax25_timeout_response(ax25_cb *ax25)
     /* [previous][next][first][last][top][bottom][index][help] */
 291 {
 292         if (ax25->condition & OWN_RX_BUSY_CONDITION)
 293                 ax25_send_control(ax25, RNR, POLLOFF, C_RESPONSE);
 294         else
 295                 ax25_send_control(ax25, RR, POLLOFF, C_RESPONSE);
 296 
 297         ax25->condition &= ~ACK_PENDING_CONDITION;
 298 }
 299 
 300 void ax25_check_iframes_acked(ax25_cb *ax25, unsigned short nr)
     /* [previous][next][first][last][top][bottom][index][help] */
 301 {
 302         if (ax25->vs == nr) {
 303                 ax25_frames_acked(ax25, nr);
 304                 ax25_calculate_rtt(ax25);
 305                 ax25->t1timer = 0;
 306                 ax25->t3timer = ax25->t3;
 307         } else {
 308                 if (ax25->va != nr) {
 309                         ax25_frames_acked(ax25, nr);
 310                         ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
 311                 }
 312         }
 313 }
 314 
 315 void ax25_check_need_response(ax25_cb *ax25, int type, int pf)
     /* [previous][next][first][last][top][bottom][index][help] */
 316 {
 317         if (type == C_COMMAND && pf)
 318                 ax25_enquiry_response(ax25);
 319 }
 320 
 321 #endif

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