port more changes to make PCI work
[linux-2.4.git] / net / x25 / x25_in.c
1 /*
2  *      X.25 Packet Layer 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 2.1.15 or higher
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  *      X.25 001        Jonathan Naylor   Started coding.
17  *      X.25 002        Jonathan Naylor   Centralised disconnection code.
18  *                                        New timer architecture.
19  *      2000-03-20      Daniela Squassoni Disabling/enabling of facilities 
20  *                                        negotiation.
21  *      2000-11-10      Henner Eisen      Check and reset for out-of-sequence
22  *                                        i-frames.
23  */
24
25 #include <linux/errno.h>
26 #include <linux/types.h>
27 #include <linux/socket.h>
28 #include <linux/in.h>
29 #include <linux/kernel.h>
30 #include <linux/sched.h>
31 #include <linux/timer.h>
32 #include <linux/string.h>
33 #include <linux/sockios.h>
34 #include <linux/net.h>
35 #include <linux/inet.h>
36 #include <linux/netdevice.h>
37 #include <linux/skbuff.h>
38 #include <net/sock.h>
39 #include <net/ip.h>                     /* For ip_rcv */
40 #include <asm/segment.h>
41 #include <asm/system.h>
42 #include <linux/fcntl.h>
43 #include <linux/mm.h>
44 #include <linux/interrupt.h>
45 #include <net/x25.h>
46
47 static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
48 {
49         struct sk_buff *skbo, *skbn = skb;
50
51         if (more) {
52                 sk->protinfo.x25->fraglen += skb->len;
53                 skb_queue_tail(&sk->protinfo.x25->fragment_queue, skb);
54                 skb_set_owner_r(skb, sk);
55                 return 0;
56         }
57
58         if (!more && sk->protinfo.x25->fraglen > 0) {   /* End of fragment */
59                 int len = sk->protinfo.x25->fraglen + skb->len;
60
61                 if ((skbn = alloc_skb(len, GFP_ATOMIC)) == NULL){
62                         kfree_skb(skb);
63                         return 1;
64                 }
65
66                 skb_queue_tail(&sk->protinfo.x25->fragment_queue, skb);
67
68                 skbn->h.raw = skbn->data;
69
70                 skbo = skb_dequeue(&sk->protinfo.x25->fragment_queue);
71                 memcpy(skb_put(skbn, skbo->len), skbo->data, skbo->len);
72                 kfree_skb(skbo);
73
74                 while ((skbo = skb_dequeue(&sk->protinfo.x25->fragment_queue)) != NULL) {
75                         skb_pull(skbo, (sk->protinfo.x25->neighbour->extended) ? X25_EXT_MIN_LEN : X25_STD_MIN_LEN);
76                         memcpy(skb_put(skbn, skbo->len), skbo->data, skbo->len);
77                         kfree_skb(skbo);
78                 }
79
80                 sk->protinfo.x25->fraglen = 0;          
81         }
82
83         skb_set_owner_r(skbn, sk);
84         skb_queue_tail(&sk->receive_queue, skbn);
85         if (!sk->dead)
86                 sk->data_ready(sk,skbn->len);
87
88         return 0;
89 }
90
91 /*
92  * State machine for state 1, Awaiting Call Accepted State.
93  * The handling of the timer(s) is in file x25_timer.c.
94  * Handling of state 0 and connection release is in af_x25.c.
95  */
96 static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype)
97 {
98         x25_address source_addr, dest_addr;
99
100         switch (frametype) {
101
102                 case X25_CALL_ACCEPTED:
103                         x25_stop_timer(sk);
104                         sk->protinfo.x25->condition = 0x00;
105                         sk->protinfo.x25->vs        = 0;
106                         sk->protinfo.x25->va        = 0;
107                         sk->protinfo.x25->vr        = 0;
108                         sk->protinfo.x25->vl        = 0;
109                         sk->protinfo.x25->state     = X25_STATE_3;
110                         sk->state                   = TCP_ESTABLISHED;
111                         /*
112                          *      Parse the data in the frame.
113                          */
114                         skb_pull(skb, X25_STD_MIN_LEN);
115                         skb_pull(skb, x25_addr_ntoa(skb->data, &source_addr, &dest_addr));
116                         skb_pull(skb, x25_parse_facilities(skb, &sk->protinfo.x25->facilities, &sk->protinfo.x25->vc_facil_mask));
117                         /*
118                          *      Copy any Call User Data.
119                          */
120                         if (skb->len >= 0) {
121                                 memcpy(sk->protinfo.x25->calluserdata.cuddata, skb->data, skb->len);
122                                 sk->protinfo.x25->calluserdata.cudlength = skb->len;
123                         }
124                         if (!sk->dead)
125                                 sk->state_change(sk);
126                         break;
127
128                 case X25_CLEAR_REQUEST:
129                         x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
130                         x25_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]);
131                         break;
132
133                 default:
134                         break;
135         }
136
137         return 0;
138 }
139
140 /*
141  * State machine for state 2, Awaiting Clear Confirmation State.
142  * The handling of the timer(s) is in file x25_timer.c
143  * Handling of state 0 and connection release is in af_x25.c.
144  */
145 static int x25_state2_machine(struct sock *sk, struct sk_buff *skb, int frametype)
146 {
147         switch (frametype) {
148
149                 case X25_CLEAR_REQUEST:
150                         x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
151                         x25_disconnect(sk, 0, skb->data[3], skb->data[4]);
152                         break;
153
154                 case X25_CLEAR_CONFIRMATION:
155                         x25_disconnect(sk, 0, 0, 0);
156                         break;
157
158                 default:
159                         break;
160         }
161
162         return 0;
163 }
164
165 /*
166  * State machine for state 3, Connected State.
167  * The handling of the timer(s) is in file x25_timer.c
168  * Handling of state 0 and connection release is in af_x25.c.
169  */
170 static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype, int ns, int nr, int q, int d, int m)
171 {
172         int queued = 0;
173         int modulus;
174         
175         modulus = (sk->protinfo.x25->neighbour->extended) ? X25_EMODULUS : X25_SMODULUS;
176
177         switch (frametype) {
178
179                 case X25_RESET_REQUEST:
180                         x25_write_internal(sk, X25_RESET_CONFIRMATION);
181                         x25_stop_timer(sk);
182                         sk->protinfo.x25->condition = 0x00;
183                         sk->protinfo.x25->vs        = 0;
184                         sk->protinfo.x25->vr        = 0;
185                         sk->protinfo.x25->va        = 0;
186                         sk->protinfo.x25->vl        = 0;
187                         x25_requeue_frames(sk);
188                         break;
189
190                 case X25_CLEAR_REQUEST:
191                         x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
192                         x25_disconnect(sk, 0, skb->data[3], skb->data[4]);
193                         break;
194
195                 case X25_RR:
196                 case X25_RNR:
197                         if (!x25_validate_nr(sk, nr)) {
198                                 x25_clear_queues(sk);
199                                 x25_write_internal(sk, X25_RESET_REQUEST);
200                                 x25_start_t22timer(sk);
201                                 sk->protinfo.x25->condition = 0x00;
202                                 sk->protinfo.x25->vs        = 0;
203                                 sk->protinfo.x25->vr        = 0;
204                                 sk->protinfo.x25->va        = 0;
205                                 sk->protinfo.x25->vl        = 0;
206                                 sk->protinfo.x25->state     = X25_STATE_4;
207                         } else {
208                                 x25_frames_acked(sk, nr);
209                                 if (frametype == X25_RNR) {
210                                         sk->protinfo.x25->condition |= X25_COND_PEER_RX_BUSY;
211                                 } else {
212                                         sk->protinfo.x25->condition &= ~X25_COND_PEER_RX_BUSY;
213                                 }
214                         }
215                         break;
216
217                 case X25_DATA:  /* XXX */
218                         sk->protinfo.x25->condition &= ~X25_COND_PEER_RX_BUSY;
219                         if ((ns!=sk->protinfo.x25->vr) || 
220                             !x25_validate_nr(sk, nr)) {
221                                 x25_clear_queues(sk);
222                                 x25_write_internal(sk, X25_RESET_REQUEST);
223                                 x25_start_t22timer(sk);
224                                 sk->protinfo.x25->condition = 0x00;
225                                 sk->protinfo.x25->vs        = 0;
226                                 sk->protinfo.x25->vr        = 0;
227                                 sk->protinfo.x25->va        = 0;
228                                 sk->protinfo.x25->vl        = 0;
229                                 sk->protinfo.x25->state     = X25_STATE_4;
230                                 break;
231                         }
232                         x25_frames_acked(sk, nr);
233                         if (ns == sk->protinfo.x25->vr) {
234                                 if (x25_queue_rx_frame(sk, skb, m) == 0) {
235                                         sk->protinfo.x25->vr = (sk->protinfo.x25->vr + 1) % modulus;
236                                         queued = 1;
237                                 } else {
238                                         /* Should never happen */
239                                         x25_clear_queues(sk);
240                                         x25_write_internal(sk, X25_RESET_REQUEST);
241                                         x25_start_t22timer(sk);
242                                         sk->protinfo.x25->condition = 0x00;
243                                         sk->protinfo.x25->vs        = 0;
244                                         sk->protinfo.x25->vr        = 0;
245                                         sk->protinfo.x25->va        = 0;
246                                         sk->protinfo.x25->vl        = 0;
247                                         sk->protinfo.x25->state     = X25_STATE_4;
248                                         break;
249                                 }
250                                 if (atomic_read(&sk->rmem_alloc) > (sk->rcvbuf / 2))
251                                         sk->protinfo.x25->condition |= X25_COND_OWN_RX_BUSY;
252                         }
253                         /*
254                          *      If the window is full Ack it immediately, else
255                          *      start the holdback timer.
256                          */
257                         if (((sk->protinfo.x25->vl + sk->protinfo.x25->facilities.winsize_in) % modulus) == sk->protinfo.x25->vr) {
258                                 sk->protinfo.x25->condition &= ~X25_COND_ACK_PENDING;
259                                 x25_stop_timer(sk);
260                                 x25_enquiry_response(sk);
261                         } else {
262                                 sk->protinfo.x25->condition |= X25_COND_ACK_PENDING;
263                                 x25_start_t2timer(sk);
264                         }
265                         break;
266
267                 case X25_INTERRUPT_CONFIRMATION:
268                         sk->protinfo.x25->intflag = 0;
269                         break;
270
271                 case X25_INTERRUPT:
272                         if (sk->urginline) {
273                                 queued = (sock_queue_rcv_skb(sk, skb) == 0);
274                         } else {
275                                 skb_set_owner_r(skb, sk);
276                                 skb_queue_tail(&sk->protinfo.x25->interrupt_in_queue, skb);
277                                 queued = 1;
278                         }
279                         if (sk->proc != 0) {
280                                 if (sk->proc > 0)
281                                         kill_proc(sk->proc, SIGURG, 1);
282                                 else
283                                         kill_pg(-sk->proc, SIGURG, 1);
284                                 sock_wake_async(sk->socket, 3, POLL_PRI);
285                         }
286                         x25_write_internal(sk, X25_INTERRUPT_CONFIRMATION);
287                         break;
288
289                 default:
290                         printk(KERN_WARNING "x25: unknown %02X in state 3\n", frametype);
291                         break;
292         }
293
294         return queued;
295 }
296
297 /*
298  * State machine for state 4, Awaiting Reset Confirmation State.
299  * The handling of the timer(s) is in file x25_timer.c
300  * Handling of state 0 and connection release is in af_x25.c.
301  */
302 static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametype)
303 {
304         switch (frametype) {
305
306                 case X25_RESET_REQUEST:
307                         x25_write_internal(sk, X25_RESET_CONFIRMATION);
308                 case X25_RESET_CONFIRMATION:
309                         x25_stop_timer(sk);
310                         sk->protinfo.x25->condition = 0x00;
311                         sk->protinfo.x25->va        = 0;
312                         sk->protinfo.x25->vr        = 0;
313                         sk->protinfo.x25->vs        = 0;
314                         sk->protinfo.x25->vl        = 0;
315                         sk->protinfo.x25->state     = X25_STATE_3;
316                         x25_requeue_frames(sk);
317                         break;
318
319                 case X25_CLEAR_REQUEST:
320                         x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
321                         x25_disconnect(sk, 0, skb->data[3], skb->data[4]);
322                         break;
323
324                 default:
325                         break;
326         }
327
328         return 0;
329 }
330
331 /* Higher level upcall for a LAPB frame */
332 int x25_process_rx_frame(struct sock *sk, struct sk_buff *skb)
333 {
334         int queued = 0, frametype, ns, nr, q, d, m;
335
336         if (sk->protinfo.x25->state == X25_STATE_0)
337                 return 0;
338
339         frametype = x25_decode(sk, skb, &ns, &nr, &q, &d, &m);
340
341         switch (sk->protinfo.x25->state) {
342                 case X25_STATE_1:
343                         queued = x25_state1_machine(sk, skb, frametype);
344                         break;
345                 case X25_STATE_2:
346                         queued = x25_state2_machine(sk, skb, frametype);
347                         break;
348                 case X25_STATE_3:
349                         queued = x25_state3_machine(sk, skb, frametype, ns, nr, q, d, m);
350                         break;
351                 case X25_STATE_4:
352                         queued = x25_state4_machine(sk, skb, frametype);
353                         break;
354         }
355
356         x25_kick(sk);
357
358         return queued;
359 }
360
361 int x25_backlog_rcv(struct sock *sk, struct sk_buff *skb)
362 {
363         int queued;
364
365         queued = x25_process_rx_frame(sk,skb);
366         if(!queued) kfree_skb(skb);
367
368         return 0;
369 }