Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
net
netrom
nr_subr.c
Go to the documentation of this file.
1
/*
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.
6
*
7
* Copyright Jonathan Naylor G4KLX (
[email protected]
)
8
*/
9
#include <linux/errno.h>
10
#include <linux/types.h>
11
#include <linux/socket.h>
12
#include <linux/in.h>
13
#include <linux/kernel.h>
14
#include <
linux/timer.h
>
15
#include <linux/string.h>
16
#include <
linux/sockios.h
>
17
#include <linux/net.h>
18
#include <linux/slab.h>
19
#include <
net/ax25.h
>
20
#include <
linux/inet.h
>
21
#include <linux/netdevice.h>
22
#include <
linux/skbuff.h
>
23
#include <
net/sock.h
>
24
#include <
net/tcp_states.h
>
25
#include <asm/uaccess.h>
26
#include <linux/fcntl.h>
27
#include <
linux/mm.h
>
28
#include <
linux/interrupt.h
>
29
#include <
net/netrom.h
>
30
31
/*
32
* This routine purges all of the queues of frames.
33
*/
34
void
nr_clear_queues
(
struct
sock
*
sk
)
35
{
36
struct
nr_sock
*
nr
=
nr_sk
(sk);
37
38
skb_queue_purge
(&sk->
sk_write_queue
);
39
skb_queue_purge
(&nr->
ack_queue
);
40
skb_queue_purge
(&nr->
reseq_queue
);
41
skb_queue_purge
(&nr->
frag_queue
);
42
}
43
44
/*
45
* This routine purges the input queue of those frames that have been
46
* acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the
47
* SDL diagram.
48
*/
49
void
nr_frames_acked
(
struct
sock
*
sk
,
unsigned
short
nr
)
50
{
51
struct
nr_sock
*nrom =
nr_sk
(sk);
52
struct
sk_buff
*
skb
;
53
54
/*
55
* Remove all the ack-ed frames from the ack queue.
56
*/
57
if
(nrom->
va
!= nr) {
58
while
(skb_peek(&nrom->
ack_queue
) !=
NULL
&& nrom->
va
!= nr) {
59
skb =
skb_dequeue
(&nrom->
ack_queue
);
60
kfree_skb
(skb);
61
nrom->
va
= (nrom->
va
+ 1) %
NR_MODULUS
;
62
}
63
}
64
}
65
66
/*
67
* Requeue all the un-ack-ed frames on the output queue to be picked
68
* up by nr_kick called from the timer. This arrangement handles the
69
* possibility of an empty output queue.
70
*/
71
void
nr_requeue_frames
(
struct
sock
*
sk
)
72
{
73
struct
sk_buff
*
skb
, *skb_prev =
NULL
;
74
75
while
((skb =
skb_dequeue
(&
nr_sk
(sk)->ack_queue)) !=
NULL
) {
76
if
(skb_prev ==
NULL
)
77
skb_queue_head
(&sk->
sk_write_queue
, skb);
78
else
79
skb_append
(skb_prev, skb, &sk->
sk_write_queue
);
80
skb_prev =
skb
;
81
}
82
}
83
84
/*
85
* Validate that the value of nr is between va and vs. Return true or
86
* false for testing.
87
*/
88
int
nr_validate_nr
(
struct
sock
*
sk
,
unsigned
short
nr
)
89
{
90
struct
nr_sock
*nrom =
nr_sk
(sk);
91
unsigned
short
vc
= nrom->
va
;
92
93
while
(vc != nrom->
vs
) {
94
if
(nr == vc)
return
1;
95
vc = (vc + 1) %
NR_MODULUS
;
96
}
97
98
return
nr == nrom->
vs
;
99
}
100
101
/*
102
* Check that ns is within the receive window.
103
*/
104
int
nr_in_rx_window
(
struct
sock
*
sk
,
unsigned
short
ns
)
105
{
106
struct
nr_sock
*
nr
=
nr_sk
(sk);
107
unsigned
short
vc
= nr->
vr
;
108
unsigned
short
vt = (nr->
vl
+ nr->
window
) %
NR_MODULUS
;
109
110
while
(vc != vt) {
111
if
(ns == vc)
return
1;
112
vc = (vc + 1) %
NR_MODULUS
;
113
}
114
115
return
0;
116
}
117
118
/*
119
* This routine is called when the HDLC layer internally generates a
120
* control frame.
121
*/
122
void
nr_write_internal
(
struct
sock
*
sk
,
int
frametype)
123
{
124
struct
nr_sock
*
nr
=
nr_sk
(sk);
125
struct
sk_buff
*
skb
;
126
unsigned
char
*dptr;
127
int
len
,
timeout
;
128
129
len =
NR_NETWORK_LEN
+
NR_TRANSPORT_LEN
;
130
131
switch
(frametype & 0x0F) {
132
case
NR_CONNREQ
:
133
len += 17;
134
break
;
135
case
NR_CONNACK
:
136
len += (nr->
bpqext
) ? 2 : 1;
137
break
;
138
case
NR_DISCREQ
:
139
case
NR_DISCACK
:
140
case
NR_INFOACK
:
141
break
;
142
default
:
143
printk
(
KERN_ERR
"NET/ROM: nr_write_internal - invalid frame type %d\n"
, frametype);
144
return
;
145
}
146
147
if
((skb = alloc_skb(len,
GFP_ATOMIC
)) ==
NULL
)
148
return
;
149
150
/*
151
* Space for AX.25 and NET/ROM network header
152
*/
153
skb_reserve(skb,
NR_NETWORK_LEN
);
154
155
dptr =
skb_put
(skb, skb_tailroom(skb));
156
157
switch
(frametype & 0x0F) {
158
case
NR_CONNREQ
:
159
timeout = nr->
t1
/
HZ
;
160
*dptr++ = nr->
my_index
;
161
*dptr++ = nr->
my_id
;
162
*dptr++ = 0;
163
*dptr++ = 0;
164
*dptr++ = frametype;
165
*dptr++ = nr->
window
;
166
memcpy
(dptr, &nr->
user_addr
,
AX25_ADDR_LEN
);
167
dptr[6] &= ~
AX25_CBIT
;
168
dptr[6] &= ~
AX25_EBIT
;
169
dptr[6] |=
AX25_SSSID_SPARE
;
170
dptr +=
AX25_ADDR_LEN
;
171
memcpy
(dptr, &nr->
source_addr
,
AX25_ADDR_LEN
);
172
dptr[6] &= ~
AX25_CBIT
;
173
dptr[6] &= ~
AX25_EBIT
;
174
dptr[6] |=
AX25_SSSID_SPARE
;
175
dptr +=
AX25_ADDR_LEN
;
176
*dptr++ = timeout % 256;
177
*dptr++ = timeout / 256;
178
break
;
179
180
case
NR_CONNACK
:
181
*dptr++ = nr->
your_index
;
182
*dptr++ = nr->
your_id
;
183
*dptr++ = nr->
my_index
;
184
*dptr++ = nr->
my_id
;
185
*dptr++ = frametype;
186
*dptr++ = nr->
window
;
187
if
(nr->
bpqext
) *dptr++ =
sysctl_netrom_network_ttl_initialiser
;
188
break
;
189
190
case
NR_DISCREQ
:
191
case
NR_DISCACK
:
192
*dptr++ = nr->
your_index
;
193
*dptr++ = nr->
your_id
;
194
*dptr++ = 0;
195
*dptr++ = 0;
196
*dptr++ = frametype;
197
break
;
198
199
case
NR_INFOACK
:
200
*dptr++ = nr->
your_index
;
201
*dptr++ = nr->
your_id
;
202
*dptr++ = 0;
203
*dptr++ = nr->
vr
;
204
*dptr++ = frametype;
205
break
;
206
}
207
208
nr_transmit_buffer
(sk, skb);
209
}
210
211
/*
212
* This routine is called to send an error reply.
213
*/
214
void
__nr_transmit_reply
(
struct
sk_buff
*
skb
,
int
mine,
unsigned
char
cmdflags)
215
{
216
struct
sk_buff
*skbn;
217
unsigned
char
*dptr;
218
int
len
;
219
220
len =
NR_NETWORK_LEN
+
NR_TRANSPORT_LEN
+ 1;
221
222
if
((skbn = alloc_skb(len,
GFP_ATOMIC
)) ==
NULL
)
223
return
;
224
225
skb_reserve(skbn, 0);
226
227
dptr =
skb_put
(skbn,
NR_NETWORK_LEN
+ NR_TRANSPORT_LEN);
228
229
skb_copy_from_linear_data_offset(skb, 7, dptr,
AX25_ADDR_LEN
);
230
dptr[6] &= ~
AX25_CBIT
;
231
dptr[6] &= ~
AX25_EBIT
;
232
dptr[6] |=
AX25_SSSID_SPARE
;
233
dptr +=
AX25_ADDR_LEN
;
234
235
skb_copy_from_linear_data(skb, dptr,
AX25_ADDR_LEN
);
236
dptr[6] &= ~
AX25_CBIT
;
237
dptr[6] |=
AX25_EBIT
;
238
dptr[6] |=
AX25_SSSID_SPARE
;
239
dptr +=
AX25_ADDR_LEN
;
240
241
*dptr++ =
sysctl_netrom_network_ttl_initialiser
;
242
243
if
(mine) {
244
*dptr++ = 0;
245
*dptr++ = 0;
246
*dptr++ = skb->
data
[15];
247
*dptr++ = skb->
data
[16];
248
}
else
{
249
*dptr++ = skb->
data
[15];
250
*dptr++ = skb->
data
[16];
251
*dptr++ = 0;
252
*dptr++ = 0;
253
}
254
255
*dptr++ = cmdflags;
256
*dptr++ = 0;
257
258
if
(!
nr_route_frame
(skbn,
NULL
))
259
kfree_skb
(skbn);
260
}
261
262
void
nr_disconnect
(
struct
sock
*
sk
,
int
reason
)
263
{
264
nr_stop_t1timer
(sk);
265
nr_stop_t2timer
(sk);
266
nr_stop_t4timer
(sk);
267
nr_stop_idletimer
(sk);
268
269
nr_clear_queues
(sk);
270
271
nr_sk
(sk)->state =
NR_STATE_0
;
272
273
sk->sk_state =
TCP_CLOSE
;
274
sk->
sk_err
=
reason
;
275
sk->
sk_shutdown
|=
SEND_SHUTDOWN
;
276
277
if
(!sock_flag(sk,
SOCK_DEAD
)) {
278
sk->
sk_state_change
(sk);
279
sock_set_flag(sk,
SOCK_DEAD
);
280
}
281
}
Generated on Thu Jan 10 2013 15:01:10 for Linux Kernel by
1.8.2