Commit | Line | Data |
---|---|---|
ee5d8f4d | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
1da177e4 LT |
2 | /* |
3 | * LAPB release 002 | |
4 | * | |
5 | * This code REQUIRES 2.1.15 or higher/ NET3.038 | |
6 | * | |
1da177e4 LT |
7 | * History |
8 | * LAPB 001 Jonathan Naylor Started Coding | |
9 | */ | |
10 | ||
a508da6c JP |
11 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
12 | ||
1da177e4 LT |
13 | #include <linux/errno.h> |
14 | #include <linux/types.h> | |
15 | #include <linux/socket.h> | |
16 | #include <linux/in.h> | |
17 | #include <linux/kernel.h> | |
1da177e4 LT |
18 | #include <linux/timer.h> |
19 | #include <linux/string.h> | |
20 | #include <linux/sockios.h> | |
21 | #include <linux/net.h> | |
22 | #include <linux/inet.h> | |
23 | #include <linux/skbuff.h> | |
5a0e3ad6 | 24 | #include <linux/slab.h> |
1da177e4 | 25 | #include <net/sock.h> |
7c0f6ba6 | 26 | #include <linux/uaccess.h> |
1da177e4 LT |
27 | #include <linux/fcntl.h> |
28 | #include <linux/mm.h> | |
29 | #include <linux/interrupt.h> | |
30 | #include <net/lapb.h> | |
31 | ||
32 | /* | |
33 | * This routine purges all the queues of frames. | |
34 | */ | |
35 | void lapb_clear_queues(struct lapb_cb *lapb) | |
36 | { | |
37 | skb_queue_purge(&lapb->write_queue); | |
38 | skb_queue_purge(&lapb->ack_queue); | |
39 | } | |
40 | ||
41 | /* | |
42 | * This routine purges the input queue of those frames that have been | |
43 | * acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the | |
44 | * SDL diagram. | |
45 | */ | |
46 | void lapb_frames_acked(struct lapb_cb *lapb, unsigned short nr) | |
47 | { | |
48 | struct sk_buff *skb; | |
49 | int modulus; | |
50 | ||
51 | modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS : LAPB_SMODULUS; | |
52 | ||
53 | /* | |
54 | * Remove all the ack-ed frames from the ack queue. | |
55 | */ | |
56 | if (lapb->va != nr) | |
57 | while (skb_peek(&lapb->ack_queue) && lapb->va != nr) { | |
56d6c3d7 | 58 | skb = skb_dequeue(&lapb->ack_queue); |
1da177e4 LT |
59 | kfree_skb(skb); |
60 | lapb->va = (lapb->va + 1) % modulus; | |
61 | } | |
62 | } | |
63 | ||
64 | void lapb_requeue_frames(struct lapb_cb *lapb) | |
65 | { | |
56d6c3d7 | 66 | struct sk_buff *skb, *skb_prev = NULL; |
1da177e4 LT |
67 | |
68 | /* | |
69 | * Requeue all the un-ack-ed frames on the output queue to be picked | |
70 | * up by lapb_kick called from the timer. This arrangement handles the | |
71 | * possibility of an empty output queue. | |
72 | */ | |
73 | while ((skb = skb_dequeue(&lapb->ack_queue)) != NULL) { | |
74 | if (!skb_prev) | |
75 | skb_queue_head(&lapb->write_queue, skb); | |
76 | else | |
8728b834 | 77 | skb_append(skb_prev, skb, &lapb->write_queue); |
1da177e4 LT |
78 | skb_prev = skb; |
79 | } | |
80 | } | |
81 | ||
82 | /* | |
83 | * Validate that the value of nr is between va and vs. Return true or | |
84 | * false for testing. | |
85 | */ | |
86 | int lapb_validate_nr(struct lapb_cb *lapb, unsigned short nr) | |
87 | { | |
88 | unsigned short vc = lapb->va; | |
89 | int modulus; | |
56d6c3d7 | 90 | |
1da177e4 LT |
91 | modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS : LAPB_SMODULUS; |
92 | ||
93 | while (vc != lapb->vs) { | |
94 | if (nr == vc) | |
95 | return 1; | |
96 | vc = (vc + 1) % modulus; | |
97 | } | |
56d6c3d7 | 98 | |
1da177e4 LT |
99 | return nr == lapb->vs; |
100 | } | |
101 | ||
102 | /* | |
103 | * This routine is the centralised routine for parsing the control | |
104 | * information for the different frame formats. | |
105 | */ | |
106 | int lapb_decode(struct lapb_cb *lapb, struct sk_buff *skb, | |
107 | struct lapb_frame *frame) | |
108 | { | |
109 | frame->type = LAPB_ILLEGAL; | |
110 | ||
0d08df6c | 111 | lapb_dbg(2, "(%p) S%d RX %3ph\n", lapb->dev, lapb->state, skb->data); |
1da177e4 LT |
112 | |
113 | /* We always need to look at 2 bytes, sometimes we need | |
114 | * to look at 3 and those cases are handled below. | |
115 | */ | |
116 | if (!pskb_may_pull(skb, 2)) | |
117 | return -1; | |
118 | ||
119 | if (lapb->mode & LAPB_MLP) { | |
120 | if (lapb->mode & LAPB_DCE) { | |
121 | if (skb->data[0] == LAPB_ADDR_D) | |
122 | frame->cr = LAPB_COMMAND; | |
123 | if (skb->data[0] == LAPB_ADDR_C) | |
124 | frame->cr = LAPB_RESPONSE; | |
125 | } else { | |
126 | if (skb->data[0] == LAPB_ADDR_C) | |
127 | frame->cr = LAPB_COMMAND; | |
128 | if (skb->data[0] == LAPB_ADDR_D) | |
129 | frame->cr = LAPB_RESPONSE; | |
130 | } | |
131 | } else { | |
132 | if (lapb->mode & LAPB_DCE) { | |
133 | if (skb->data[0] == LAPB_ADDR_B) | |
134 | frame->cr = LAPB_COMMAND; | |
135 | if (skb->data[0] == LAPB_ADDR_A) | |
136 | frame->cr = LAPB_RESPONSE; | |
137 | } else { | |
138 | if (skb->data[0] == LAPB_ADDR_A) | |
139 | frame->cr = LAPB_COMMAND; | |
140 | if (skb->data[0] == LAPB_ADDR_B) | |
141 | frame->cr = LAPB_RESPONSE; | |
142 | } | |
143 | } | |
56d6c3d7 | 144 | |
1da177e4 LT |
145 | skb_pull(skb, 1); |
146 | ||
147 | if (lapb->mode & LAPB_EXTENDED) { | |
148 | if (!(skb->data[0] & LAPB_S)) { | |
149 | if (!pskb_may_pull(skb, 2)) | |
150 | return -1; | |
151 | /* | |
152 | * I frame - carries NR/NS/PF | |
153 | */ | |
154 | frame->type = LAPB_I; | |
155 | frame->ns = (skb->data[0] >> 1) & 0x7F; | |
156 | frame->nr = (skb->data[1] >> 1) & 0x7F; | |
157 | frame->pf = skb->data[1] & LAPB_EPF; | |
158 | frame->control[0] = skb->data[0]; | |
159 | frame->control[1] = skb->data[1]; | |
160 | skb_pull(skb, 2); | |
161 | } else if ((skb->data[0] & LAPB_U) == 1) { | |
162 | if (!pskb_may_pull(skb, 2)) | |
163 | return -1; | |
164 | /* | |
165 | * S frame - take out PF/NR | |
166 | */ | |
167 | frame->type = skb->data[0] & 0x0F; | |
168 | frame->nr = (skb->data[1] >> 1) & 0x7F; | |
169 | frame->pf = skb->data[1] & LAPB_EPF; | |
170 | frame->control[0] = skb->data[0]; | |
171 | frame->control[1] = skb->data[1]; | |
172 | skb_pull(skb, 2); | |
173 | } else if ((skb->data[0] & LAPB_U) == 3) { | |
174 | /* | |
175 | * U frame - take out PF | |
176 | */ | |
177 | frame->type = skb->data[0] & ~LAPB_SPF; | |
178 | frame->pf = skb->data[0] & LAPB_SPF; | |
179 | frame->control[0] = skb->data[0]; | |
180 | frame->control[1] = 0x00; | |
181 | skb_pull(skb, 1); | |
182 | } | |
183 | } else { | |
184 | if (!(skb->data[0] & LAPB_S)) { | |
185 | /* | |
186 | * I frame - carries NR/NS/PF | |
187 | */ | |
188 | frame->type = LAPB_I; | |
189 | frame->ns = (skb->data[0] >> 1) & 0x07; | |
190 | frame->nr = (skb->data[0] >> 5) & 0x07; | |
191 | frame->pf = skb->data[0] & LAPB_SPF; | |
192 | } else if ((skb->data[0] & LAPB_U) == 1) { | |
193 | /* | |
194 | * S frame - take out PF/NR | |
195 | */ | |
196 | frame->type = skb->data[0] & 0x0F; | |
197 | frame->nr = (skb->data[0] >> 5) & 0x07; | |
198 | frame->pf = skb->data[0] & LAPB_SPF; | |
199 | } else if ((skb->data[0] & LAPB_U) == 3) { | |
200 | /* | |
201 | * U frame - take out PF | |
202 | */ | |
203 | frame->type = skb->data[0] & ~LAPB_SPF; | |
204 | frame->pf = skb->data[0] & LAPB_SPF; | |
205 | } | |
206 | ||
207 | frame->control[0] = skb->data[0]; | |
208 | ||
209 | skb_pull(skb, 1); | |
210 | } | |
211 | ||
212 | return 0; | |
213 | } | |
214 | ||
56d6c3d7 | 215 | /* |
1da177e4 | 216 | * This routine is called when the HDLC layer internally generates a |
56d6c3d7 | 217 | * command or response for the remote machine ( eg. RR, UA etc. ). |
1da177e4 LT |
218 | * Only supervisory or unnumbered frames are processed, FRMRs are handled |
219 | * by lapb_transmit_frmr below. | |
220 | */ | |
221 | void lapb_send_control(struct lapb_cb *lapb, int frametype, | |
222 | int poll_bit, int type) | |
223 | { | |
224 | struct sk_buff *skb; | |
225 | unsigned char *dptr; | |
226 | ||
227 | if ((skb = alloc_skb(LAPB_HEADER_LEN + 3, GFP_ATOMIC)) == NULL) | |
228 | return; | |
229 | ||
230 | skb_reserve(skb, LAPB_HEADER_LEN + 1); | |
231 | ||
232 | if (lapb->mode & LAPB_EXTENDED) { | |
233 | if ((frametype & LAPB_U) == LAPB_U) { | |
234 | dptr = skb_put(skb, 1); | |
235 | *dptr = frametype; | |
236 | *dptr |= poll_bit ? LAPB_SPF : 0; | |
237 | } else { | |
238 | dptr = skb_put(skb, 2); | |
239 | dptr[0] = frametype; | |
240 | dptr[1] = (lapb->vr << 1); | |
241 | dptr[1] |= poll_bit ? LAPB_EPF : 0; | |
242 | } | |
243 | } else { | |
244 | dptr = skb_put(skb, 1); | |
245 | *dptr = frametype; | |
246 | *dptr |= poll_bit ? LAPB_SPF : 0; | |
247 | if ((frametype & LAPB_U) == LAPB_S) /* S frames carry NR */ | |
248 | *dptr |= (lapb->vr << 5); | |
249 | } | |
250 | ||
251 | lapb_transmit_buffer(lapb, skb, type); | |
252 | } | |
253 | ||
56d6c3d7 | 254 | /* |
1da177e4 LT |
255 | * This routine generates FRMRs based on information previously stored in |
256 | * the LAPB control block. | |
257 | */ | |
258 | void lapb_transmit_frmr(struct lapb_cb *lapb) | |
259 | { | |
260 | struct sk_buff *skb; | |
261 | unsigned char *dptr; | |
262 | ||
263 | if ((skb = alloc_skb(LAPB_HEADER_LEN + 7, GFP_ATOMIC)) == NULL) | |
264 | return; | |
265 | ||
266 | skb_reserve(skb, LAPB_HEADER_LEN + 1); | |
267 | ||
268 | if (lapb->mode & LAPB_EXTENDED) { | |
269 | dptr = skb_put(skb, 6); | |
270 | *dptr++ = LAPB_FRMR; | |
271 | *dptr++ = lapb->frmr_data.control[0]; | |
272 | *dptr++ = lapb->frmr_data.control[1]; | |
273 | *dptr++ = (lapb->vs << 1) & 0xFE; | |
274 | *dptr = (lapb->vr << 1) & 0xFE; | |
275 | if (lapb->frmr_data.cr == LAPB_RESPONSE) | |
276 | *dptr |= 0x01; | |
277 | dptr++; | |
278 | *dptr++ = lapb->frmr_type; | |
279 | ||
0d08df6c | 280 | lapb_dbg(1, "(%p) S%d TX FRMR %5ph\n", |
a508da6c | 281 | lapb->dev, lapb->state, |
0d08df6c | 282 | &skb->data[1]); |
1da177e4 LT |
283 | } else { |
284 | dptr = skb_put(skb, 4); | |
285 | *dptr++ = LAPB_FRMR; | |
286 | *dptr++ = lapb->frmr_data.control[0]; | |
287 | *dptr = (lapb->vs << 1) & 0x0E; | |
288 | *dptr |= (lapb->vr << 5) & 0xE0; | |
289 | if (lapb->frmr_data.cr == LAPB_RESPONSE) | |
290 | *dptr |= 0x10; | |
291 | dptr++; | |
292 | *dptr++ = lapb->frmr_type; | |
293 | ||
0d08df6c AS |
294 | lapb_dbg(1, "(%p) S%d TX FRMR %3ph\n", |
295 | lapb->dev, lapb->state, &skb->data[1]); | |
1da177e4 LT |
296 | } |
297 | ||
298 | lapb_transmit_buffer(lapb, skb, LAPB_RESPONSE); | |
299 | } |