root/net/netrom/nr_out.c

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

DEFINITIONS

This source file includes following definitions.
  1. nr_output
  2. nr_send_iframe
  3. nr_send_nak_frame
  4. nr_kick
  5. nr_transmit_buffer
  6. nr_nr_error_recovery
  7. nr_establish_data_link
  8. nr_enquiry_response
  9. nr_check_iframes_acked

   1 /*
   2  *      NET/ROM release 002
   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_out.c
  17  */
  18 
  19 #include <linux/config.h>
  20 #ifdef CONFIG_NETROM
  21 #include <linux/errno.h>
  22 #include <linux/types.h>
  23 #include <linux/socket.h>
  24 #include <linux/in.h>
  25 #include <linux/kernel.h>
  26 #include <linux/sched.h>
  27 #include <linux/timer.h>
  28 #include <linux/string.h>
  29 #include <linux/sockios.h>
  30 #include <linux/net.h>
  31 #include <net/ax25.h>
  32 #include <linux/inet.h>
  33 #include <linux/netdevice.h>
  34 #include <linux/skbuff.h>
  35 #include <net/sock.h>
  36 #include <asm/segment.h>
  37 #include <asm/system.h>
  38 #include <linux/fcntl.h>
  39 #include <linux/mm.h>
  40 #include <linux/interrupt.h>
  41 #include <net/netrom.h>
  42 
  43 int nr_output(struct sock *sk, struct sk_buff *skb)
     /* [previous][next][first][last][top][bottom][index][help] */
  44 {
  45         skb_queue_tail(&sk->write_queue, skb);  /* Throw it on the queue */
  46 
  47         if (sk->nr->state == NR_STATE_3)
  48                 nr_kick(sk);
  49 
  50         return 0;
  51 }
  52 
  53 /* 
  54  *  This procedure is passed a buffer descriptor for an iframe. It builds
  55  *  the rest of the control part of the frame and then writes it out.
  56  */
  57 static void nr_send_iframe(struct sock *sk, struct sk_buff *skb)
     /* [previous][next][first][last][top][bottom][index][help] */
  58 {
  59         unsigned char *dptr;
  60 
  61         if (skb == NULL)
  62                 return;
  63 
  64         dptr = skb->data + 34;
  65         
  66         *dptr++ = sk->nr->vs;
  67         *dptr++ = sk->nr->vr;
  68 
  69         nr_transmit_buffer(sk, skb);    
  70 }
  71 
  72 void nr_send_nak_frame(struct sock *sk)
     /* [previous][next][first][last][top][bottom][index][help] */
  73 {
  74         struct sk_buff *skb, *skbn;
  75         
  76         if ((skb = skb_peek(&sk->nr->ack_queue)) == NULL)
  77                 return;
  78                 
  79         if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL)
  80                 return;
  81 
  82         nr_send_iframe(sk, skbn);
  83 
  84         sk->nr->condition &= ~ACK_PENDING_CONDITION;
  85         sk->nr->vl      = sk->nr->vr;
  86         sk->nr->t1timer = 0;
  87 }
  88 
  89 void nr_kick(struct sock *sk)
     /* [previous][next][first][last][top][bottom][index][help] */
  90 {
  91         struct sk_buff *skb, *skbn;
  92         int last = 1;
  93         unsigned short start, end, next;
  94 
  95         del_timer(&sk->timer);
  96 
  97         start = (skb_peek(&sk->nr->ack_queue) == NULL) ? sk->nr->va : sk->nr->vs;
  98         end   = (sk->nr->va + sk->window) % NR_MODULUS;
  99 
 100         if (!(sk->nr->condition & PEER_RX_BUSY_CONDITION) &&
 101             start != end                                   &&
 102             skb_peek(&sk->write_queue) != NULL) {
 103 
 104                 sk->nr->vs = start;
 105 
 106                 /*
 107                  * Transmit data until either we're out of data to send or
 108                  * the window is full.
 109                  */
 110                 do {
 111                         /*
 112                          * Dequeue the frame and copy it.
 113                          */
 114                         skb  = skb_dequeue(&sk->write_queue);
 115 
 116                         if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) {
 117                                 skb_queue_head(&sk->write_queue, skb);
 118                                 return;
 119                         }
 120 
 121                         next = (sk->nr->vs + 1) % NR_MODULUS;
 122                         last = (next == end);
 123 
 124                         /*
 125                          * Transmit the frame copy.
 126                          */
 127                         nr_send_iframe(sk, skbn);
 128 
 129                         sk->nr->vs = next;
 130 
 131                         /*
 132                          * Requeue the original data frame.
 133                          */
 134                         skb_queue_tail(&sk->nr->ack_queue, skb);
 135 
 136                 } while (!last && skb_peek(&sk->write_queue) != NULL);
 137 
 138                 sk->nr->vl = sk->nr->vr;
 139                 sk->nr->condition &= ~ACK_PENDING_CONDITION;
 140 
 141                 if (sk->nr->t1timer == 0) {
 142                         sk->nr->t1timer = sk->nr->t1 = nr_calculate_t1(sk);
 143                 }
 144         }
 145 
 146         nr_set_timer(sk);
 147 }
 148 
 149 void nr_transmit_buffer(struct sock *sk, struct sk_buff *skb)
     /* [previous][next][first][last][top][bottom][index][help] */
 150 {
 151         unsigned char *dptr;
 152 
 153         dptr = skb->data + 16;
 154 
 155         *dptr++ = AX25_P_NETROM;
 156         
 157         memcpy(dptr, &sk->nr->source_addr, sizeof(ax25_address));
 158         dptr[6] &= ~LAPB_C;
 159         dptr[6] &= ~LAPB_E;
 160         dptr[6] |= SSID_SPARE;
 161         dptr += 7;
 162 
 163         memcpy(dptr, &sk->nr->dest_addr,   sizeof(ax25_address));
 164         dptr[6] &= ~LAPB_C;
 165         dptr[6] |= LAPB_E;
 166         dptr[6] |= SSID_SPARE;
 167         dptr += 7;
 168 
 169         *dptr++ = nr_default.ttl;
 170 
 171         skb->arp = 1;
 172 
 173         if (!nr_route_frame(skb, NULL)) {
 174                 kfree_skb(skb, FREE_WRITE);
 175 
 176                 sk->state = TCP_CLOSE;
 177                 sk->err   = ENETUNREACH;
 178                 if (!sk->dead)
 179                         sk->state_change(sk);
 180                 sk->dead  = 1;
 181         }
 182 }
 183 
 184 /*
 185  * The following routines are taken from page 170 of the 7th ARRL Computer
 186  * Networking Conference paper, as is the whole state machine.
 187  */
 188 
 189 void nr_nr_error_recovery(struct sock *sk)
     /* [previous][next][first][last][top][bottom][index][help] */
 190 {
 191         nr_establish_data_link(sk);
 192 }
 193 
 194 void nr_establish_data_link(struct sock *sk)
     /* [previous][next][first][last][top][bottom][index][help] */
 195 {
 196         sk->nr->condition = 0x00;
 197         sk->nr->n2count   = 0;
 198 
 199         nr_write_internal(sk, NR_CONNREQ);
 200 
 201         sk->nr->t2timer = 0;
 202         sk->nr->t1timer = sk->nr->t1 = nr_calculate_t1(sk);
 203 }
 204 
 205 /*
 206  * Never send a NAK when we are CHOKEd.
 207  */
 208 void nr_enquiry_response(struct sock *sk)
     /* [previous][next][first][last][top][bottom][index][help] */
 209 {
 210         int frametype = NR_INFOACK;
 211         
 212         if (sk->nr->condition & OWN_RX_BUSY_CONDITION) {
 213                 frametype += NR_CHOKE_FLAG;
 214         } else {
 215                 if (skb_peek(&sk->nr->reseq_queue) != NULL) {
 216                         frametype += NR_NAK_FLAG;
 217                 }
 218         }
 219         
 220         nr_write_internal(sk, frametype);
 221 
 222         sk->nr->vl = sk->nr->vr;
 223         sk->nr->condition &= ~ACK_PENDING_CONDITION;
 224 }
 225 
 226 void nr_check_iframes_acked(struct sock *sk, unsigned short nr)
     /* [previous][next][first][last][top][bottom][index][help] */
 227 {
 228         if (sk->nr->vs == nr) {
 229                 nr_frames_acked(sk, nr);
 230                 nr_requeue_frames(sk);
 231                 nr_calculate_rtt(sk);
 232                 sk->nr->t1timer = 0;
 233                 sk->nr->n2count = 0;
 234         } else {
 235                 if (sk->nr->va != nr) {
 236                         nr_frames_acked(sk, nr);
 237                         nr_requeue_frames(sk);
 238                         sk->nr->t1timer = sk->nr->t1 = nr_calculate_t1(sk);
 239                 }
 240         }
 241 }
 242 
 243 #endif

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