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_check_iframes_acked
  10. ax25_check_need_response

   1 /*
   2  *      AX.25 release 029
   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  */
  26 
  27 #include <linux/config.h>
  28 #ifdef CONFIG_AX25
  29 #include <linux/errno.h>
  30 #include <linux/types.h>
  31 #include <linux/socket.h>
  32 #include <linux/in.h>
  33 #include <linux/kernel.h>
  34 #include <linux/sched.h>
  35 #include <linux/timer.h>
  36 #include <linux/string.h>
  37 #include <linux/sockios.h>
  38 #include <linux/net.h>
  39 #include <net/ax25.h>
  40 #include <linux/inet.h>
  41 #include <linux/netdevice.h>
  42 #include <linux/skbuff.h>
  43 #include <net/sock.h>
  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 
  50 int ax25_output(ax25_cb *ax25, struct sk_buff *skb)
     /* [previous][next][first][last][top][bottom][index][help] */
  51 {
  52         skb_queue_tail(&ax25->write_queue, skb);        /* Throw it on the queue */
  53 
  54         if (ax25->state == AX25_STATE_3 || ax25->state == AX25_STATE_4)
  55                 ax25_kick(ax25);
  56 
  57         return 0;
  58 }
  59 
  60 /* 
  61  *  This procedure is passed a buffer descriptor for an iframe. It builds
  62  *  the rest of the control part of the frame and then writes it out.
  63  */
  64 static void ax25_send_iframe(ax25_cb *ax25, struct sk_buff *skb, int poll_bit)
     /* [previous][next][first][last][top][bottom][index][help] */
  65 {
  66         unsigned char *frame;
  67 
  68         if (skb == NULL)
  69                 return;
  70         
  71         frame = skb_push(skb, 1);       /* KISS + header */
  72 
  73         *frame = I;
  74         *frame |= poll_bit;
  75         *frame |= (ax25->vr << 5);
  76         *frame |= (ax25->vs << 1);
  77 
  78         ax25_transmit_buffer(ax25, skb, C_COMMAND);     
  79 }
  80 
  81 void ax25_kick(ax25_cb *ax25)
     /* [previous][next][first][last][top][bottom][index][help] */
  82 {
  83         struct sk_buff *skb, *skbn;
  84         int last = 1;
  85         unsigned short start, end, next;
  86 
  87         del_timer(&ax25->timer);
  88 
  89         start = (skb_peek(&ax25->ack_queue) == NULL) ? ax25->va : ax25->vs;
  90         end   = (ax25->va + ax25->window) % MODULUS;
  91 
  92         if (!(ax25->condition & PEER_RX_BUSY_CONDITION) &&
  93             start != end                                   &&
  94             skb_peek(&ax25->write_queue) != NULL) {
  95 
  96                 ax25->vs = start;
  97 
  98                 /*
  99                  * Transmit data until either we're out of data to send or
 100                  * the window is full. Send a poll on the final I frame if
 101                  * the window is filled.
 102                  */
 103                 do {
 104                         /*
 105                          * Dequeue the frame and copy it.
 106                          */
 107                         skb  = skb_dequeue(&ax25->write_queue);
 108 
 109                         if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) {
 110                                 skb_queue_head(&ax25->write_queue, skb);
 111                                 return;
 112                         }
 113 
 114                         next = (ax25->vs + 1) % MODULUS;
 115 #ifdef notdef
 116                         last = (next == end) || skb_peek(&ax25->write_queue) == NULL;
 117 #else
 118                         last = (next == end);
 119 #endif
 120                         /*
 121                          * Transmit the frame copy.
 122                          */
 123                         ax25_send_iframe(ax25, skbn, (last) ? PF : 0);
 124 
 125                         ax25->vs = next;
 126 
 127                         /*
 128                          * Requeue the original data frame.
 129                          */
 130                         skb_queue_tail(&ax25->ack_queue, skb);
 131 #ifdef notdef
 132                 } while (!last);
 133 #else
 134                 } while (!last && skb_peek(&ax25->write_queue) != NULL);
 135 #endif
 136                 ax25->condition &= ~ACK_PENDING_CONDITION;
 137 
 138                 if (ax25->t1timer == 0) {
 139                         ax25->t3timer = 0;
 140                         ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
 141                 }
 142         }
 143 
 144         ax25_set_timer(ax25);
 145 }
 146 
 147 void ax25_transmit_buffer(ax25_cb *ax25, struct sk_buff *skb, int type)
     /* [previous][next][first][last][top][bottom][index][help] */
 148 {
 149         unsigned char *ptr;
 150 
 151         if (ax25->device == NULL) {
 152                 if (ax25->sk != NULL) {
 153                         ax25->sk->state = TCP_CLOSE;
 154                         ax25->sk->err   = ENETUNREACH;
 155                         if (!ax25->sk->dead)
 156                                 ax25->sk->state_change(ax25->sk);
 157                         ax25->sk->dead  = 1;
 158                 }
 159                 return;
 160         }
 161 
 162         if (skb_headroom(skb) < size_ax25_addr(ax25->digipeat)) {
 163                 printk("ax25_transmit_buffer: not enough room for digi-peaters\n");
 164                 skb->free = 1;
 165                 kfree_skb(skb, FREE_WRITE);
 166                 return;
 167         }
 168 
 169         ptr = skb_push(skb, size_ax25_addr(ax25->digipeat));
 170         build_ax25_addr(ptr, &ax25->source_addr, &ax25->dest_addr, ax25->digipeat, type);
 171 
 172         skb->arp = 1;
 173 
 174         ax25_queue_xmit(skb, ax25->device, SOPRI_NORMAL);
 175 }
 176 
 177 /*
 178  * The following routines are taken from page 170 of the 7th ARRL Computer
 179  * Networking Conference paper, as is the whole state machine.
 180  */
 181 
 182 void ax25_nr_error_recovery(ax25_cb *ax25)
     /* [previous][next][first][last][top][bottom][index][help] */
 183 {
 184         ax25_establish_data_link(ax25);
 185 }
 186 
 187 void ax25_establish_data_link(ax25_cb *ax25)
     /* [previous][next][first][last][top][bottom][index][help] */
 188 {
 189         ax25->condition = 0x00;
 190         ax25->n2count   = 0;
 191 
 192         ax25_send_control(ax25, SABM | PF, C_COMMAND);
 193 
 194         ax25->t3timer = 0;
 195         ax25->t2timer = 0;
 196         ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
 197 }
 198 
 199 void ax25_transmit_enquiry(ax25_cb *ax25)
     /* [previous][next][first][last][top][bottom][index][help] */
 200 {
 201         if (ax25->condition & OWN_RX_BUSY_CONDITION)
 202                 ax25_send_control(ax25, RNR | PF, C_COMMAND);
 203         else
 204                 ax25_send_control(ax25, RR | PF, C_COMMAND);
 205 
 206         ax25->condition &= ~ACK_PENDING_CONDITION;
 207 
 208         ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
 209 }
 210         
 211 void ax25_enquiry_response(ax25_cb *ax25)
     /* [previous][next][first][last][top][bottom][index][help] */
 212 {
 213         if (ax25->condition & OWN_RX_BUSY_CONDITION)
 214                 ax25_send_control(ax25, RNR | PF, C_RESPONSE);
 215         else
 216                 ax25_send_control(ax25, RR | PF, C_RESPONSE);
 217 
 218         ax25->condition &= ~ACK_PENDING_CONDITION;
 219 }
 220 
 221 void ax25_check_iframes_acked(ax25_cb *ax25, unsigned short nr)
     /* [previous][next][first][last][top][bottom][index][help] */
 222 {
 223         if (ax25->vs == nr) {
 224                 ax25_frames_acked(ax25, nr);
 225                 ax25_calculate_rtt(ax25);
 226                 ax25->t1timer = 0;
 227                 ax25->t3timer = ax25->t3;
 228         } else {
 229                 if (ax25->va != nr) {
 230                         ax25_frames_acked(ax25, nr);
 231                         ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
 232                 }
 233         }
 234 }
 235 
 236 void ax25_check_need_response(ax25_cb *ax25, int type, int pf)
     /* [previous][next][first][last][top][bottom][index][help] */
 237 {
 238         if (type == C_COMMAND && pf)
 239                 ax25_enquiry_response(ax25);
 240 }
 241 
 242 #endif

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