OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [net/] [netrom/] [nr_in.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.