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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [net/] [netrom/] [nr_in.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *      NET/ROM release 007
3
 *
4
 *      This code REQUIRES 2.1.15 or higher/ NET3.038
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
 *      NET/ROM 006     Jonathan(G4KLX) Hdrincl removal changes.
24
 *      NET/ROM 007     Jonathan(G4KLX) New timer architecture.
25
 */
26
 
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/uaccess.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
        nr_start_idletimer(sk);
57
 
58
        if (more) {
59
                sk->protinfo.nr->fraglen += skb->len;
60
                skb_queue_tail(&sk->protinfo.nr->frag_queue, skb);
61
                return 0;
62
        }
63
 
64
        if (!more && sk->protinfo.nr->fraglen > 0) {     /* End of fragment */
65
                sk->protinfo.nr->fraglen += skb->len;
66
                skb_queue_tail(&sk->protinfo.nr->frag_queue, skb);
67
 
68
                if ((skbn = alloc_skb(sk->protinfo.nr->fraglen, GFP_ATOMIC)) == NULL)
69
                        return 1;
70
 
71
                skbn->h.raw = skbn->data;
72
 
73
                while ((skbo = skb_dequeue(&sk->protinfo.nr->frag_queue)) != NULL) {
74
                        memcpy(skb_put(skbn, skbo->len), skbo->data, skbo->len);
75
                        kfree_skb(skbo);
76
                }
77
 
78
                sk->protinfo.nr->fraglen = 0;
79
        }
80
 
81
        return sock_queue_rcv_skb(sk, skbn);
82
}
83
 
84
/*
85
 * State machine for state 1, Awaiting Connection State.
86
 * The handling of the timer(s) is in file nr_timer.c.
87
 * Handling of state 0 and connection release is in netrom.c.
88
 */
89
static int nr_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype)
90
{
91
        switch (frametype) {
92
 
93
                case NR_CONNACK:
94
                        nr_stop_t1timer(sk);
95
                        nr_start_idletimer(sk);
96
                        sk->protinfo.nr->your_index = skb->data[17];
97
                        sk->protinfo.nr->your_id    = skb->data[18];
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
                        if (!sk->dead)
107
                                sk->state_change(sk);
108
                        break;
109
 
110
                case NR_CONNACK | NR_CHOKE_FLAG:
111
                        nr_disconnect(sk, ECONNREFUSED);
112
                        break;
113
 
114
                default:
115
                        break;
116
        }
117
 
118
        return 0;
119
}
120
 
121
/*
122
 * State machine for state 2, Awaiting Release State.
123
 * The handling of the timer(s) is in file nr_timer.c
124
 * Handling of state 0 and connection release is in netrom.c.
125
 */
126
static int nr_state2_machine(struct sock *sk, struct sk_buff *skb, int frametype)
127
{
128
        switch (frametype) {
129
 
130
                case NR_CONNACK | NR_CHOKE_FLAG:
131
                        nr_disconnect(sk, ECONNRESET);
132
                        break;
133
 
134
                case NR_DISCREQ:
135
                        nr_write_internal(sk, NR_DISCACK);
136
 
137
                case NR_DISCACK:
138
                        nr_disconnect(sk, 0);
139
                        break;
140
 
141
                default:
142
                        break;
143
        }
144
 
145
        return 0;
146
}
147
 
148
/*
149
 * State machine for state 3, Connected State.
150
 * The handling of the timer(s) is in file nr_timer.c
151
 * Handling of state 0 and connection release is in netrom.c.
152
 */
153
static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype)
154
{
155
        struct sk_buff_head temp_queue;
156
        struct sk_buff *skbn;
157
        unsigned short save_vr;
158
        unsigned short nr, ns;
159
        int queued = 0;
160
 
161
        nr = skb->data[18];
162
        ns = skb->data[17];
163
 
164
        switch (frametype) {
165
 
166
                case NR_CONNREQ:
167
                        nr_write_internal(sk, NR_CONNACK);
168
                        break;
169
 
170
                case NR_DISCREQ:
171
                        nr_write_internal(sk, NR_DISCACK);
172
                        nr_disconnect(sk, 0);
173
                        break;
174
 
175
                case NR_CONNACK | NR_CHOKE_FLAG:
176
                case NR_DISCACK:
177
                        nr_disconnect(sk, ECONNRESET);
178
                        break;
179
 
180
                case NR_INFOACK:
181
                case NR_INFOACK | NR_CHOKE_FLAG:
182
                case NR_INFOACK | NR_NAK_FLAG:
183
                case NR_INFOACK | NR_NAK_FLAG | NR_CHOKE_FLAG:
184
                        if (frametype & NR_CHOKE_FLAG) {
185
                                sk->protinfo.nr->condition |= NR_COND_PEER_RX_BUSY;
186
                                nr_start_t4timer(sk);
187
                        } else {
188
                                sk->protinfo.nr->condition &= ~NR_COND_PEER_RX_BUSY;
189
                                nr_stop_t4timer(sk);
190
                        }
191
                        if (!nr_validate_nr(sk, nr)) {
192
                                break;
193
                        }
194
                        if (frametype & NR_NAK_FLAG) {
195
                                nr_frames_acked(sk, nr);
196
                                nr_send_nak_frame(sk);
197
                        } else {
198
                                if (sk->protinfo.nr->condition & NR_COND_PEER_RX_BUSY) {
199
                                        nr_frames_acked(sk, nr);
200
                                } else {
201
                                        nr_check_iframes_acked(sk, nr);
202
                                }
203
                        }
204
                        break;
205
 
206
                case NR_INFO:
207
                case NR_INFO | NR_NAK_FLAG:
208
                case NR_INFO | NR_CHOKE_FLAG:
209
                case NR_INFO | NR_MORE_FLAG:
210
                case NR_INFO | NR_NAK_FLAG | NR_CHOKE_FLAG:
211
                case NR_INFO | NR_CHOKE_FLAG | NR_MORE_FLAG:
212
                case NR_INFO | NR_NAK_FLAG | NR_MORE_FLAG:
213
                case NR_INFO | NR_NAK_FLAG | NR_CHOKE_FLAG | NR_MORE_FLAG:
214
                        if (frametype & NR_CHOKE_FLAG) {
215
                                sk->protinfo.nr->condition |= NR_COND_PEER_RX_BUSY;
216
                                nr_start_t4timer(sk);
217
                        } else {
218
                                sk->protinfo.nr->condition &= ~NR_COND_PEER_RX_BUSY;
219
                                nr_stop_t4timer(sk);
220
                        }
221
                        if (nr_validate_nr(sk, nr)) {
222
                                if (frametype & NR_NAK_FLAG) {
223
                                        nr_frames_acked(sk, nr);
224
                                        nr_send_nak_frame(sk);
225
                                } else {
226
                                        if (sk->protinfo.nr->condition & NR_COND_PEER_RX_BUSY) {
227
                                                nr_frames_acked(sk, nr);
228
                                        } else {
229
                                                nr_check_iframes_acked(sk, nr);
230
                                        }
231
                                }
232
                        }
233
                        queued = 1;
234
                        skb_queue_head(&sk->protinfo.nr->reseq_queue, skb);
235
                        if (sk->protinfo.nr->condition & NR_COND_OWN_RX_BUSY)
236
                                break;
237
                        skb_queue_head_init(&temp_queue);
238
                        do {
239
                                save_vr = sk->protinfo.nr->vr;
240
                                while ((skbn = skb_dequeue(&sk->protinfo.nr->reseq_queue)) != NULL) {
241
                                        ns = skbn->data[17];
242
                                        if (ns == sk->protinfo.nr->vr) {
243
                                                if (nr_queue_rx_frame(sk, skbn, frametype & NR_MORE_FLAG) == 0) {
244
                                                        sk->protinfo.nr->vr = (sk->protinfo.nr->vr + 1) % NR_MODULUS;
245
                                                } else {
246
                                                        sk->protinfo.nr->condition |= NR_COND_OWN_RX_BUSY;
247
                                                        skb_queue_tail(&temp_queue, skbn);
248
                                                }
249
                                        } else if (nr_in_rx_window(sk, ns)) {
250
                                                skb_queue_tail(&temp_queue, skbn);
251
                                        } else {
252
                                                kfree_skb(skbn);
253
                                        }
254
                                }
255
                                while ((skbn = skb_dequeue(&temp_queue)) != NULL) {
256
                                        skb_queue_tail(&sk->protinfo.nr->reseq_queue, skbn);
257
                                }
258
                        } while (save_vr != sk->protinfo.nr->vr);
259
                        /*
260
                         * Window is full, ack it immediately.
261
                         */
262
                        if (((sk->protinfo.nr->vl + sk->protinfo.nr->window) % NR_MODULUS) == sk->protinfo.nr->vr) {
263
                                nr_enquiry_response(sk);
264
                        } else {
265
                                if (!(sk->protinfo.nr->condition & NR_COND_ACK_PENDING)) {
266
                                        sk->protinfo.nr->condition |= NR_COND_ACK_PENDING;
267
                                        nr_start_t2timer(sk);
268
                                }
269
                        }
270
                        break;
271
 
272
                default:
273
                        break;
274
        }
275
 
276
        return queued;
277
}
278
 
279
/* Higher level upcall for a LAPB frame */
280
int nr_process_rx_frame(struct sock *sk, struct sk_buff *skb)
281
{
282
        int queued = 0, frametype;
283
 
284
        if (sk->protinfo.nr->state == NR_STATE_0)
285
                return 0;
286
 
287
        frametype = skb->data[19];
288
 
289
        switch (sk->protinfo.nr->state) {
290
                case NR_STATE_1:
291
                        queued = nr_state1_machine(sk, skb, frametype);
292
                        break;
293
                case NR_STATE_2:
294
                        queued = nr_state2_machine(sk, skb, frametype);
295
                        break;
296
                case NR_STATE_3:
297
                        queued = nr_state3_machine(sk, skb, frametype);
298
                        break;
299
        }
300
 
301
        nr_kick(sk);
302
 
303
        return queued;
304
}

powered by: WebSVN 2.1.0

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