2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
9 #include <linux/errno.h>
10 #include <linux/types.h>
11 #include <linux/socket.h>
13 #include <linux/kernel.h>
14 #include <linux/sched.h>
15 #include <linux/timer.h>
16 #include <linux/string.h>
17 #include <linux/sockios.h>
18 #include <linux/net.h>
20 #include <linux/inet.h>
21 #include <linux/netdevice.h>
22 #include <linux/skbuff.h>
24 #include <net/tcp_states.h>
25 #include <asm/uaccess.h>
26 #include <asm/system.h>
27 #include <linux/fcntl.h>
29 #include <linux/interrupt.h>
30 #include <net/netrom.h>
33 * This routine purges all of the queues of frames.
35 void nr_clear_queues(struct sock
*sk
)
37 struct nr_sock
*nr
= nr_sk(sk
);
39 skb_queue_purge(&sk
->sk_write_queue
);
40 skb_queue_purge(&nr
->ack_queue
);
41 skb_queue_purge(&nr
->reseq_queue
);
42 skb_queue_purge(&nr
->frag_queue
);
46 * This routine purges the input queue of those frames that have been
47 * acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the
50 void nr_frames_acked(struct sock
*sk
, unsigned short nr
)
52 struct nr_sock
*nrom
= nr_sk(sk
);
56 * Remove all the ack-ed frames from the ack queue.
59 while (skb_peek(&nrom
->ack_queue
) != NULL
&& nrom
->va
!= nr
) {
60 skb
= skb_dequeue(&nrom
->ack_queue
);
62 nrom
->va
= (nrom
->va
+ 1) % NR_MODULUS
;
68 * Requeue all the un-ack-ed frames on the output queue to be picked
69 * up by nr_kick called from the timer. This arrangement handles the
70 * possibility of an empty output queue.
72 void nr_requeue_frames(struct sock
*sk
)
74 struct sk_buff
*skb
, *skb_prev
= NULL
;
76 while ((skb
= skb_dequeue(&nr_sk(sk
)->ack_queue
)) != NULL
) {
78 skb_queue_head(&sk
->sk_write_queue
, skb
);
80 skb_append(skb_prev
, skb
, &sk
->sk_write_queue
);
86 * Validate that the value of nr is between va and vs. Return true or
89 int nr_validate_nr(struct sock
*sk
, unsigned short nr
)
91 struct nr_sock
*nrom
= nr_sk(sk
);
92 unsigned short vc
= nrom
->va
;
94 while (vc
!= nrom
->vs
) {
95 if (nr
== vc
) return 1;
96 vc
= (vc
+ 1) % NR_MODULUS
;
99 return nr
== nrom
->vs
;
103 * Check that ns is within the receive window.
105 int nr_in_rx_window(struct sock
*sk
, unsigned short ns
)
107 struct nr_sock
*nr
= nr_sk(sk
);
108 unsigned short vc
= nr
->vr
;
109 unsigned short vt
= (nr
->vl
+ nr
->window
) % NR_MODULUS
;
112 if (ns
== vc
) return 1;
113 vc
= (vc
+ 1) % NR_MODULUS
;
120 * This routine is called when the HDLC layer internally generates a
123 void nr_write_internal(struct sock
*sk
, int frametype
)
125 struct nr_sock
*nr
= nr_sk(sk
);
130 len
= NR_NETWORK_LEN
+ NR_TRANSPORT_LEN
;
132 switch (frametype
& 0x0F) {
137 len
+= (nr
->bpqext
) ? 2 : 1;
144 printk(KERN_ERR
"NET/ROM: nr_write_internal - invalid frame type %d\n", frametype
);
148 if ((skb
= alloc_skb(len
, GFP_ATOMIC
)) == NULL
)
152 * Space for AX.25 and NET/ROM network header
154 skb_reserve(skb
, NR_NETWORK_LEN
);
156 dptr
= skb_put(skb
, skb_tailroom(skb
));
158 switch (frametype
& 0x0F) {
160 timeout
= nr
->t1
/ HZ
;
161 *dptr
++ = nr
->my_index
;
166 *dptr
++ = nr
->window
;
167 memcpy(dptr
, &nr
->user_addr
, AX25_ADDR_LEN
);
168 dptr
[6] &= ~AX25_CBIT
;
169 dptr
[6] &= ~AX25_EBIT
;
170 dptr
[6] |= AX25_SSSID_SPARE
;
171 dptr
+= AX25_ADDR_LEN
;
172 memcpy(dptr
, &nr
->source_addr
, AX25_ADDR_LEN
);
173 dptr
[6] &= ~AX25_CBIT
;
174 dptr
[6] &= ~AX25_EBIT
;
175 dptr
[6] |= AX25_SSSID_SPARE
;
176 dptr
+= AX25_ADDR_LEN
;
177 *dptr
++ = timeout
% 256;
178 *dptr
++ = timeout
/ 256;
182 *dptr
++ = nr
->your_index
;
183 *dptr
++ = nr
->your_id
;
184 *dptr
++ = nr
->my_index
;
187 *dptr
++ = nr
->window
;
188 if (nr
->bpqext
) *dptr
++ = sysctl_netrom_network_ttl_initialiser
;
193 *dptr
++ = nr
->your_index
;
194 *dptr
++ = nr
->your_id
;
201 *dptr
++ = nr
->your_index
;
202 *dptr
++ = nr
->your_id
;
209 nr_transmit_buffer(sk
, skb
);
213 * This routine is called to send an error reply.
215 void __nr_transmit_reply(struct sk_buff
*skb
, int mine
, unsigned char cmdflags
)
217 struct sk_buff
*skbn
;
221 len
= NR_NETWORK_LEN
+ NR_TRANSPORT_LEN
+ 1;
223 if ((skbn
= alloc_skb(len
, GFP_ATOMIC
)) == NULL
)
226 skb_reserve(skbn
, 0);
228 dptr
= skb_put(skbn
, NR_NETWORK_LEN
+ NR_TRANSPORT_LEN
);
230 memcpy(dptr
, skb
->data
+ 7, AX25_ADDR_LEN
);
231 dptr
[6] &= ~AX25_CBIT
;
232 dptr
[6] &= ~AX25_EBIT
;
233 dptr
[6] |= AX25_SSSID_SPARE
;
234 dptr
+= AX25_ADDR_LEN
;
236 memcpy(dptr
, skb
->data
+ 0, AX25_ADDR_LEN
);
237 dptr
[6] &= ~AX25_CBIT
;
238 dptr
[6] |= AX25_EBIT
;
239 dptr
[6] |= AX25_SSSID_SPARE
;
240 dptr
+= AX25_ADDR_LEN
;
242 *dptr
++ = sysctl_netrom_network_ttl_initialiser
;
247 *dptr
++ = skb
->data
[15];
248 *dptr
++ = skb
->data
[16];
250 *dptr
++ = skb
->data
[15];
251 *dptr
++ = skb
->data
[16];
259 if (!nr_route_frame(skbn
, NULL
))
263 void nr_disconnect(struct sock
*sk
, int reason
)
268 nr_stop_idletimer(sk
);
272 nr_sk(sk
)->state
= NR_STATE_0
;
274 sk
->sk_state
= TCP_CLOSE
;
276 sk
->sk_shutdown
|= SEND_SHUTDOWN
;
278 if (!sock_flag(sk
, SOCK_DEAD
)) {
279 sk
->sk_state_change(sk
);
280 sock_set_flag(sk
, SOCK_DEAD
);