Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/net/netrom/nr_subr.c
15109 views
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 <asm/system.h>
27
#include <linux/fcntl.h>
28
#include <linux/mm.h>
29
#include <linux/interrupt.h>
30
#include <net/netrom.h>
31
32
/*
33
* This routine purges all of the queues of frames.
34
*/
35
void nr_clear_queues(struct sock *sk)
36
{
37
struct nr_sock *nr = nr_sk(sk);
38
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);
43
}
44
45
/*
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
48
* SDL diagram.
49
*/
50
void nr_frames_acked(struct sock *sk, unsigned short nr)
51
{
52
struct nr_sock *nrom = nr_sk(sk);
53
struct sk_buff *skb;
54
55
/*
56
* Remove all the ack-ed frames from the ack queue.
57
*/
58
if (nrom->va != nr) {
59
while (skb_peek(&nrom->ack_queue) != NULL && nrom->va != nr) {
60
skb = skb_dequeue(&nrom->ack_queue);
61
kfree_skb(skb);
62
nrom->va = (nrom->va + 1) % NR_MODULUS;
63
}
64
}
65
}
66
67
/*
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.
71
*/
72
void nr_requeue_frames(struct sock *sk)
73
{
74
struct sk_buff *skb, *skb_prev = NULL;
75
76
while ((skb = skb_dequeue(&nr_sk(sk)->ack_queue)) != NULL) {
77
if (skb_prev == NULL)
78
skb_queue_head(&sk->sk_write_queue, skb);
79
else
80
skb_append(skb_prev, skb, &sk->sk_write_queue);
81
skb_prev = skb;
82
}
83
}
84
85
/*
86
* Validate that the value of nr is between va and vs. Return true or
87
* false for testing.
88
*/
89
int nr_validate_nr(struct sock *sk, unsigned short nr)
90
{
91
struct nr_sock *nrom = nr_sk(sk);
92
unsigned short vc = nrom->va;
93
94
while (vc != nrom->vs) {
95
if (nr == vc) return 1;
96
vc = (vc + 1) % NR_MODULUS;
97
}
98
99
return nr == nrom->vs;
100
}
101
102
/*
103
* Check that ns is within the receive window.
104
*/
105
int nr_in_rx_window(struct sock *sk, unsigned short ns)
106
{
107
struct nr_sock *nr = nr_sk(sk);
108
unsigned short vc = nr->vr;
109
unsigned short vt = (nr->vl + nr->window) % NR_MODULUS;
110
111
while (vc != vt) {
112
if (ns == vc) return 1;
113
vc = (vc + 1) % NR_MODULUS;
114
}
115
116
return 0;
117
}
118
119
/*
120
* This routine is called when the HDLC layer internally generates a
121
* control frame.
122
*/
123
void nr_write_internal(struct sock *sk, int frametype)
124
{
125
struct nr_sock *nr = nr_sk(sk);
126
struct sk_buff *skb;
127
unsigned char *dptr;
128
int len, timeout;
129
130
len = NR_NETWORK_LEN + NR_TRANSPORT_LEN;
131
132
switch (frametype & 0x0F) {
133
case NR_CONNREQ:
134
len += 17;
135
break;
136
case NR_CONNACK:
137
len += (nr->bpqext) ? 2 : 1;
138
break;
139
case NR_DISCREQ:
140
case NR_DISCACK:
141
case NR_INFOACK:
142
break;
143
default:
144
printk(KERN_ERR "NET/ROM: nr_write_internal - invalid frame type %d\n", frametype);
145
return;
146
}
147
148
if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
149
return;
150
151
/*
152
* Space for AX.25 and NET/ROM network header
153
*/
154
skb_reserve(skb, NR_NETWORK_LEN);
155
156
dptr = skb_put(skb, skb_tailroom(skb));
157
158
switch (frametype & 0x0F) {
159
case NR_CONNREQ:
160
timeout = nr->t1 / HZ;
161
*dptr++ = nr->my_index;
162
*dptr++ = nr->my_id;
163
*dptr++ = 0;
164
*dptr++ = 0;
165
*dptr++ = frametype;
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;
179
break;
180
181
case NR_CONNACK:
182
*dptr++ = nr->your_index;
183
*dptr++ = nr->your_id;
184
*dptr++ = nr->my_index;
185
*dptr++ = nr->my_id;
186
*dptr++ = frametype;
187
*dptr++ = nr->window;
188
if (nr->bpqext) *dptr++ = sysctl_netrom_network_ttl_initialiser;
189
break;
190
191
case NR_DISCREQ:
192
case NR_DISCACK:
193
*dptr++ = nr->your_index;
194
*dptr++ = nr->your_id;
195
*dptr++ = 0;
196
*dptr++ = 0;
197
*dptr++ = frametype;
198
break;
199
200
case NR_INFOACK:
201
*dptr++ = nr->your_index;
202
*dptr++ = nr->your_id;
203
*dptr++ = 0;
204
*dptr++ = nr->vr;
205
*dptr++ = frametype;
206
break;
207
}
208
209
nr_transmit_buffer(sk, skb);
210
}
211
212
/*
213
* This routine is called to send an error reply.
214
*/
215
void __nr_transmit_reply(struct sk_buff *skb, int mine, unsigned char cmdflags)
216
{
217
struct sk_buff *skbn;
218
unsigned char *dptr;
219
int len;
220
221
len = NR_NETWORK_LEN + NR_TRANSPORT_LEN + 1;
222
223
if ((skbn = alloc_skb(len, GFP_ATOMIC)) == NULL)
224
return;
225
226
skb_reserve(skbn, 0);
227
228
dptr = skb_put(skbn, NR_NETWORK_LEN + NR_TRANSPORT_LEN);
229
230
skb_copy_from_linear_data_offset(skb, 7, dptr, AX25_ADDR_LEN);
231
dptr[6] &= ~AX25_CBIT;
232
dptr[6] &= ~AX25_EBIT;
233
dptr[6] |= AX25_SSSID_SPARE;
234
dptr += AX25_ADDR_LEN;
235
236
skb_copy_from_linear_data(skb, dptr, AX25_ADDR_LEN);
237
dptr[6] &= ~AX25_CBIT;
238
dptr[6] |= AX25_EBIT;
239
dptr[6] |= AX25_SSSID_SPARE;
240
dptr += AX25_ADDR_LEN;
241
242
*dptr++ = sysctl_netrom_network_ttl_initialiser;
243
244
if (mine) {
245
*dptr++ = 0;
246
*dptr++ = 0;
247
*dptr++ = skb->data[15];
248
*dptr++ = skb->data[16];
249
} else {
250
*dptr++ = skb->data[15];
251
*dptr++ = skb->data[16];
252
*dptr++ = 0;
253
*dptr++ = 0;
254
}
255
256
*dptr++ = cmdflags;
257
*dptr++ = 0;
258
259
if (!nr_route_frame(skbn, NULL))
260
kfree_skb(skbn);
261
}
262
263
void nr_disconnect(struct sock *sk, int reason)
264
{
265
nr_stop_t1timer(sk);
266
nr_stop_t2timer(sk);
267
nr_stop_t4timer(sk);
268
nr_stop_idletimer(sk);
269
270
nr_clear_queues(sk);
271
272
nr_sk(sk)->state = NR_STATE_0;
273
274
sk->sk_state = TCP_CLOSE;
275
sk->sk_err = reason;
276
sk->sk_shutdown |= SEND_SHUTDOWN;
277
278
if (!sock_flag(sk, SOCK_DEAD)) {
279
sk->sk_state_change(sk);
280
sock_set_flag(sk, SOCK_DEAD);
281
}
282
}
283
284