bnep.c revision 1.8 1 1.8 plunky /* $NetBSD: bnep.c,v 1.8 2009/05/12 21:08:30 plunky Exp $ */
2 1.1 plunky
3 1.1 plunky /*-
4 1.1 plunky * Copyright (c) 2008 Iain Hibbert
5 1.1 plunky * All rights reserved.
6 1.1 plunky *
7 1.1 plunky * Redistribution and use in source and binary forms, with or without
8 1.1 plunky * modification, are permitted provided that the following conditions
9 1.1 plunky * are met:
10 1.1 plunky * 1. Redistributions of source code must retain the above copyright
11 1.1 plunky * notice, this list of conditions and the following disclaimer.
12 1.1 plunky * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 plunky * notice, this list of conditions and the following disclaimer in the
14 1.1 plunky * documentation and/or other materials provided with the distribution.
15 1.1 plunky *
16 1.1 plunky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 1.1 plunky * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 1.1 plunky * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 1.1 plunky * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 1.1 plunky * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 1.1 plunky * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 1.1 plunky * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 1.1 plunky * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 1.1 plunky * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 1.1 plunky * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 1.1 plunky */
27 1.1 plunky
28 1.1 plunky #include <sys/cdefs.h>
29 1.8 plunky __RCSID("$NetBSD: bnep.c,v 1.8 2009/05/12 21:08:30 plunky Exp $");
30 1.1 plunky
31 1.1 plunky #include <bluetooth.h>
32 1.1 plunky #include <sdp.h>
33 1.1 plunky #include <stdarg.h>
34 1.1 plunky #include <string.h>
35 1.1 plunky
36 1.1 plunky #include "btpand.h"
37 1.1 plunky #include "bnep.h"
38 1.1 plunky
39 1.1 plunky static bool bnep_recv_extension(packet_t *);
40 1.1 plunky static size_t bnep_recv_control(channel_t *, uint8_t *, size_t, bool);
41 1.1 plunky static size_t bnep_recv_control_command_not_understood(channel_t *, uint8_t *, size_t);
42 1.1 plunky static size_t bnep_recv_setup_connection_req(channel_t *, uint8_t *, size_t);
43 1.1 plunky static size_t bnep_recv_setup_connection_rsp(channel_t *, uint8_t *, size_t);
44 1.1 plunky static size_t bnep_recv_filter_net_type_set(channel_t *, uint8_t *, size_t);
45 1.1 plunky static size_t bnep_recv_filter_net_type_rsp(channel_t *, uint8_t *, size_t);
46 1.1 plunky static size_t bnep_recv_filter_multi_addr_set(channel_t *, uint8_t *, size_t);
47 1.1 plunky static size_t bnep_recv_filter_multi_addr_rsp(channel_t *, uint8_t *, size_t);
48 1.1 plunky
49 1.1 plunky static bool bnep_pfilter(channel_t *, packet_t *);
50 1.1 plunky static bool bnep_mfilter(channel_t *, packet_t *);
51 1.1 plunky
52 1.1 plunky static uint8_t NAP_UUID[] = {
53 1.1 plunky 0x00, 0x00, 0x11, 0x16,
54 1.1 plunky 0x00, 0x00,
55 1.1 plunky 0x10, 0x00,
56 1.1 plunky 0x80, 0x00,
57 1.1 plunky 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb
58 1.1 plunky };
59 1.1 plunky
60 1.1 plunky static uint8_t GN_UUID[] = {
61 1.1 plunky 0x00, 0x00, 0x11, 0x17,
62 1.1 plunky 0x00, 0x00,
63 1.1 plunky 0x10, 0x00,
64 1.1 plunky 0x80, 0x00,
65 1.1 plunky 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
66 1.1 plunky };
67 1.1 plunky
68 1.1 plunky static uint8_t PANU_UUID[] = {
69 1.1 plunky 0x00, 0x00, 0x11, 0x15,
70 1.1 plunky 0x00, 0x00,
71 1.1 plunky 0x10, 0x00,
72 1.1 plunky 0x80, 0x00,
73 1.1 plunky 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb
74 1.1 plunky };
75 1.1 plunky
76 1.1 plunky /*
77 1.1 plunky * receive BNEP packet
78 1.1 plunky * return true if packet is to be forwarded
79 1.1 plunky */
80 1.1 plunky bool
81 1.1 plunky bnep_recv(packet_t *pkt)
82 1.1 plunky {
83 1.1 plunky size_t len;
84 1.1 plunky uint8_t type;
85 1.1 plunky
86 1.1 plunky if (pkt->len < 1)
87 1.1 plunky return false;
88 1.1 plunky
89 1.1 plunky type = pkt->ptr[0];
90 1.1 plunky packet_adj(pkt, 1);
91 1.1 plunky
92 1.1 plunky switch (BNEP_TYPE(type)) {
93 1.1 plunky case BNEP_GENERAL_ETHERNET:
94 1.1 plunky if (pkt->len < (ETHER_ADDR_LEN * 2) + ETHER_TYPE_LEN) {
95 1.1 plunky log_debug("dropped short packet (type 0x%2.2x)", type);
96 1.1 plunky return false;
97 1.1 plunky }
98 1.1 plunky
99 1.1 plunky pkt->dst = pkt->ptr;
100 1.1 plunky packet_adj(pkt, ETHER_ADDR_LEN);
101 1.1 plunky pkt->src = pkt->ptr;
102 1.1 plunky packet_adj(pkt, ETHER_ADDR_LEN);
103 1.1 plunky pkt->type = pkt->ptr;
104 1.1 plunky packet_adj(pkt, ETHER_TYPE_LEN);
105 1.1 plunky break;
106 1.1 plunky
107 1.1 plunky case BNEP_CONTROL:
108 1.1 plunky len = bnep_recv_control(pkt->chan, pkt->ptr, pkt->len, false);
109 1.1 plunky if (len == 0)
110 1.1 plunky return false;
111 1.1 plunky
112 1.1 plunky packet_adj(pkt, len);
113 1.1 plunky break;
114 1.1 plunky
115 1.1 plunky case BNEP_COMPRESSED_ETHERNET:
116 1.1 plunky if (pkt->len < ETHER_TYPE_LEN) {
117 1.1 plunky log_debug("dropped short packet (type 0x%2.2x)", type);
118 1.1 plunky return false;
119 1.1 plunky }
120 1.1 plunky
121 1.1 plunky pkt->dst = pkt->chan->laddr;
122 1.1 plunky pkt->src = pkt->chan->raddr;
123 1.1 plunky pkt->type = pkt->ptr;
124 1.1 plunky packet_adj(pkt, ETHER_TYPE_LEN);
125 1.1 plunky break;
126 1.1 plunky
127 1.1 plunky case BNEP_COMPRESSED_ETHERNET_SRC_ONLY:
128 1.1 plunky if (pkt->len < ETHER_ADDR_LEN + ETHER_TYPE_LEN) {
129 1.1 plunky log_debug("dropped short packet (type 0x%2.2x)", type);
130 1.1 plunky return false;
131 1.1 plunky }
132 1.1 plunky
133 1.1 plunky pkt->dst = pkt->chan->laddr;
134 1.1 plunky pkt->src = pkt->ptr;
135 1.1 plunky packet_adj(pkt, ETHER_ADDR_LEN);
136 1.1 plunky pkt->type = pkt->ptr;
137 1.1 plunky packet_adj(pkt, ETHER_TYPE_LEN);
138 1.1 plunky break;
139 1.1 plunky
140 1.1 plunky case BNEP_COMPRESSED_ETHERNET_DST_ONLY:
141 1.1 plunky if (pkt->len < ETHER_ADDR_LEN + ETHER_TYPE_LEN) {
142 1.1 plunky log_debug("dropped short packet (type 0x%2.2x)", type);
143 1.1 plunky return false;
144 1.1 plunky }
145 1.1 plunky
146 1.1 plunky pkt->dst = pkt->ptr;
147 1.1 plunky packet_adj(pkt, ETHER_ADDR_LEN);
148 1.1 plunky pkt->src = pkt->chan->raddr;
149 1.1 plunky pkt->type = pkt->ptr;
150 1.1 plunky packet_adj(pkt, ETHER_TYPE_LEN);
151 1.1 plunky break;
152 1.1 plunky
153 1.1 plunky default:
154 1.1 plunky /*
155 1.1 plunky * Any packet containing a reserved BNEP
156 1.1 plunky * header packet type SHALL be dropped.
157 1.1 plunky */
158 1.1 plunky
159 1.1 plunky log_debug("dropped packet with reserved type 0x%2.2x", type);
160 1.1 plunky return false;
161 1.1 plunky }
162 1.1 plunky
163 1.1 plunky if (BNEP_TYPE_EXT(type)
164 1.1 plunky && !bnep_recv_extension(pkt))
165 1.1 plunky return false; /* invalid extensions */
166 1.1 plunky
167 1.1 plunky if (BNEP_TYPE(type) == BNEP_CONTROL
168 1.1 plunky || pkt->chan->state != CHANNEL_OPEN)
169 1.1 plunky return false; /* no forwarding */
170 1.1 plunky
171 1.5 plunky if (pkt->len > ETHER_MAX_LEN)
172 1.5 plunky log_debug("received long packet "
173 1.6 kefren "(type=0x%2.2x, proto=0x%4.4x, len=%zu)",
174 1.5 plunky type, be16dec(pkt->type), pkt->len);
175 1.5 plunky
176 1.1 plunky return true;
177 1.1 plunky }
178 1.1 plunky
179 1.1 plunky static bool
180 1.1 plunky bnep_recv_extension(packet_t *pkt)
181 1.1 plunky {
182 1.1 plunky exthdr_t *eh;
183 1.3 plunky size_t len, size;
184 1.3 plunky uint8_t type;
185 1.1 plunky
186 1.1 plunky do {
187 1.1 plunky if (pkt->len < 2)
188 1.1 plunky return false;
189 1.1 plunky
190 1.1 plunky type = pkt->ptr[0];
191 1.1 plunky size = pkt->ptr[1];
192 1.1 plunky
193 1.1 plunky if (pkt->len < size + 2)
194 1.1 plunky return false;
195 1.1 plunky
196 1.1 plunky switch (type) {
197 1.1 plunky case BNEP_EXTENSION_CONTROL:
198 1.1 plunky len = bnep_recv_control(pkt->chan, pkt->ptr + 2, size, true);
199 1.1 plunky if (len != size)
200 1.1 plunky log_err("ignored spurious data in exthdr");
201 1.1 plunky
202 1.1 plunky break;
203 1.1 plunky
204 1.1 plunky default:
205 1.1 plunky /* Unknown extension headers in data packets */
206 1.1 plunky /* SHALL be forwarded irrespective of any */
207 1.1 plunky /* network protocol or multicast filter settings */
208 1.1 plunky /* and any local filtering policy. */
209 1.1 plunky
210 1.1 plunky eh = malloc(sizeof(exthdr_t));
211 1.1 plunky if (eh == NULL) {
212 1.1 plunky log_err("exthdr malloc() failed: %m");
213 1.1 plunky break;
214 1.1 plunky }
215 1.1 plunky
216 1.1 plunky eh->ptr = pkt->ptr;
217 1.1 plunky eh->len = size;
218 1.1 plunky STAILQ_INSERT_TAIL(&pkt->extlist, eh, next);
219 1.1 plunky break;
220 1.1 plunky }
221 1.1 plunky
222 1.1 plunky packet_adj(pkt, size + 2);
223 1.1 plunky } while (BNEP_TYPE_EXT(type));
224 1.1 plunky
225 1.1 plunky return true;
226 1.1 plunky }
227 1.1 plunky
228 1.1 plunky static size_t
229 1.1 plunky bnep_recv_control(channel_t *chan, uint8_t *ptr, size_t size, bool isext)
230 1.1 plunky {
231 1.1 plunky uint8_t type;
232 1.1 plunky size_t len;
233 1.1 plunky
234 1.1 plunky if (size-- < 1)
235 1.1 plunky return 0;
236 1.1 plunky
237 1.1 plunky type = *ptr++;
238 1.1 plunky
239 1.1 plunky switch (type) {
240 1.1 plunky case BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD:
241 1.1 plunky len = bnep_recv_control_command_not_understood(chan, ptr, size);
242 1.1 plunky break;
243 1.1 plunky
244 1.1 plunky case BNEP_SETUP_CONNECTION_REQUEST:
245 1.1 plunky if (isext)
246 1.1 plunky return 0; /* not allowed in extension headers */
247 1.1 plunky
248 1.1 plunky len = bnep_recv_setup_connection_req(chan, ptr, size);
249 1.1 plunky break;
250 1.1 plunky
251 1.1 plunky case BNEP_SETUP_CONNECTION_RESPONSE:
252 1.1 plunky if (isext)
253 1.1 plunky return 0; /* not allowed in extension headers */
254 1.1 plunky
255 1.1 plunky len = bnep_recv_setup_connection_rsp(chan, ptr, size);
256 1.1 plunky break;
257 1.1 plunky
258 1.1 plunky case BNEP_FILTER_NET_TYPE_SET:
259 1.1 plunky len = bnep_recv_filter_net_type_set(chan, ptr, size);
260 1.1 plunky break;
261 1.1 plunky
262 1.1 plunky case BNEP_FILTER_NET_TYPE_RESPONSE:
263 1.1 plunky len = bnep_recv_filter_net_type_rsp(chan, ptr, size);
264 1.1 plunky break;
265 1.1 plunky
266 1.1 plunky case BNEP_FILTER_MULTI_ADDR_SET:
267 1.1 plunky len = bnep_recv_filter_multi_addr_set(chan, ptr, size);
268 1.1 plunky break;
269 1.1 plunky
270 1.1 plunky case BNEP_FILTER_MULTI_ADDR_RESPONSE:
271 1.1 plunky len = bnep_recv_filter_multi_addr_rsp(chan, ptr, size);
272 1.1 plunky break;
273 1.1 plunky
274 1.1 plunky default:
275 1.1 plunky len = 0;
276 1.1 plunky break;
277 1.1 plunky }
278 1.1 plunky
279 1.1 plunky if (len == 0)
280 1.1 plunky bnep_send_control(chan, BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD, type);
281 1.1 plunky
282 1.1 plunky return len;
283 1.1 plunky }
284 1.1 plunky
285 1.1 plunky static size_t
286 1.1 plunky bnep_recv_control_command_not_understood(channel_t *chan, uint8_t *ptr, size_t size)
287 1.1 plunky {
288 1.1 plunky uint8_t type;
289 1.1 plunky
290 1.1 plunky if (size < 1)
291 1.1 plunky return 0;
292 1.1 plunky
293 1.1 plunky type = *ptr++;
294 1.1 plunky log_err("received Control Command Not Understood (0x%2.2x)", type);
295 1.1 plunky
296 1.8 plunky /* we didn't send any reserved commands, just shut them down */
297 1.8 plunky chan->down(chan);
298 1.1 plunky
299 1.1 plunky return 1;
300 1.1 plunky }
301 1.1 plunky
302 1.1 plunky static size_t
303 1.1 plunky bnep_recv_setup_connection_req(channel_t *chan, uint8_t *ptr, size_t size)
304 1.1 plunky {
305 1.3 plunky size_t len;
306 1.3 plunky uint8_t off;
307 1.1 plunky int src, dst, rsp;
308 1.1 plunky
309 1.1 plunky if (size < 1)
310 1.1 plunky return 0;
311 1.1 plunky
312 1.1 plunky len = *ptr++;
313 1.1 plunky if (size < (len * 2 + 1))
314 1.1 plunky return 0;
315 1.1 plunky
316 1.1 plunky if (chan->state != CHANNEL_WAIT_CONNECT_REQ
317 1.1 plunky && chan->state != CHANNEL_OPEN) {
318 1.1 plunky log_debug("ignored");
319 1.1 plunky return (len * 2 + 1);
320 1.1 plunky }
321 1.1 plunky
322 1.1 plunky if (len == 2)
323 1.1 plunky off = 2;
324 1.1 plunky else if (len == 4)
325 1.1 plunky off = 0;
326 1.1 plunky else if (len == 16)
327 1.1 plunky off = 0;
328 1.1 plunky else {
329 1.1 plunky rsp = BNEP_SETUP_INVALID_UUID_SIZE;
330 1.1 plunky goto done;
331 1.1 plunky }
332 1.1 plunky
333 1.1 plunky if (memcmp(ptr, NAP_UUID + off, len) == 0)
334 1.1 plunky dst = SDP_SERVICE_CLASS_NAP;
335 1.1 plunky else if (memcmp(ptr, GN_UUID + off, len) == 0)
336 1.1 plunky dst = SDP_SERVICE_CLASS_GN;
337 1.1 plunky else if (memcmp(ptr, PANU_UUID + off, len) == 0)
338 1.1 plunky dst = SDP_SERVICE_CLASS_PANU;
339 1.1 plunky else
340 1.1 plunky dst = 0;
341 1.1 plunky
342 1.1 plunky if (dst != service_class) {
343 1.1 plunky rsp = BNEP_SETUP_INVALID_DST_UUID;
344 1.1 plunky goto done;
345 1.1 plunky }
346 1.1 plunky
347 1.1 plunky ptr += len;
348 1.1 plunky
349 1.2 plunky if (memcmp(ptr, NAP_UUID + off, len) == 0)
350 1.1 plunky src = SDP_SERVICE_CLASS_NAP;
351 1.1 plunky else if (memcmp(ptr, GN_UUID + off, len) == 0)
352 1.1 plunky src = SDP_SERVICE_CLASS_GN;
353 1.2 plunky else if (memcmp(ptr, PANU_UUID + off, len) == 0)
354 1.1 plunky src = SDP_SERVICE_CLASS_PANU;
355 1.1 plunky else
356 1.1 plunky src = 0;
357 1.1 plunky
358 1.1 plunky if ((dst != SDP_SERVICE_CLASS_PANU && src != SDP_SERVICE_CLASS_PANU)
359 1.1 plunky || src == 0) {
360 1.1 plunky rsp = BNEP_SETUP_INVALID_SRC_UUID;
361 1.1 plunky goto done;
362 1.1 plunky }
363 1.1 plunky
364 1.1 plunky rsp = BNEP_SETUP_SUCCESS;
365 1.1 plunky chan->state = CHANNEL_OPEN;
366 1.1 plunky channel_timeout(chan, 0);
367 1.1 plunky
368 1.1 plunky done:
369 1.1 plunky log_debug("addr %s response 0x%2.2x",
370 1.1 plunky ether_ntoa((struct ether_addr *)chan->raddr), rsp);
371 1.1 plunky
372 1.1 plunky bnep_send_control(chan, BNEP_SETUP_CONNECTION_RESPONSE, rsp);
373 1.1 plunky return (len * 2 + 1);
374 1.1 plunky }
375 1.1 plunky
376 1.1 plunky static size_t
377 1.1 plunky bnep_recv_setup_connection_rsp(channel_t *chan, uint8_t *ptr, size_t size)
378 1.1 plunky {
379 1.1 plunky int rsp;
380 1.1 plunky
381 1.1 plunky if (size < 2)
382 1.1 plunky return 0;
383 1.1 plunky
384 1.1 plunky rsp = be16dec(ptr);
385 1.1 plunky
386 1.1 plunky if (chan->state != CHANNEL_WAIT_CONNECT_RSP) {
387 1.1 plunky log_debug("ignored");
388 1.1 plunky return 2;
389 1.1 plunky }
390 1.1 plunky
391 1.1 plunky log_debug("addr %s response 0x%2.2x",
392 1.1 plunky ether_ntoa((struct ether_addr *)chan->raddr), rsp);
393 1.1 plunky
394 1.1 plunky if (rsp == BNEP_SETUP_SUCCESS) {
395 1.1 plunky chan->state = CHANNEL_OPEN;
396 1.1 plunky channel_timeout(chan, 0);
397 1.1 plunky } else {
398 1.8 plunky chan->down(chan);
399 1.1 plunky }
400 1.1 plunky
401 1.1 plunky return 2;
402 1.1 plunky }
403 1.1 plunky
404 1.1 plunky static size_t
405 1.1 plunky bnep_recv_filter_net_type_set(channel_t *chan, uint8_t *ptr, size_t size)
406 1.1 plunky {
407 1.1 plunky pfilter_t *pf;
408 1.3 plunky int i, nf, rsp;
409 1.3 plunky size_t len;
410 1.1 plunky
411 1.1 plunky if (size < 2)
412 1.1 plunky return 0;
413 1.1 plunky
414 1.1 plunky len = be16dec(ptr);
415 1.1 plunky ptr += 2;
416 1.1 plunky
417 1.1 plunky if (size < (len + 2))
418 1.1 plunky return 0;
419 1.1 plunky
420 1.1 plunky if (chan->state != CHANNEL_OPEN) {
421 1.1 plunky log_debug("ignored");
422 1.1 plunky return (len + 2);
423 1.1 plunky }
424 1.1 plunky
425 1.1 plunky nf = len / 4;
426 1.1 plunky pf = malloc(nf * sizeof(pfilter_t));
427 1.1 plunky if (pf == NULL) {
428 1.1 plunky rsp = BNEP_FILTER_TOO_MANY_FILTERS;
429 1.1 plunky goto done;
430 1.1 plunky }
431 1.1 plunky
432 1.1 plunky log_debug("nf = %d", nf);
433 1.1 plunky
434 1.1 plunky for (i = 0; i < nf; i++) {
435 1.1 plunky pf[i].start = be16dec(ptr);
436 1.1 plunky ptr += 2;
437 1.1 plunky pf[i].end = be16dec(ptr);
438 1.1 plunky ptr += 2;
439 1.1 plunky
440 1.1 plunky if (pf[i].start > pf[i].end) {
441 1.1 plunky free(pf);
442 1.1 plunky rsp = BNEP_FILTER_INVALID_RANGE;
443 1.1 plunky goto done;
444 1.1 plunky }
445 1.1 plunky
446 1.1 plunky log_debug("pf[%d] = %#4.4x, %#4.4x", i, pf[i].start, pf[i].end);
447 1.1 plunky }
448 1.1 plunky
449 1.1 plunky if (chan->pfilter)
450 1.1 plunky free(chan->pfilter);
451 1.1 plunky
452 1.1 plunky chan->pfilter = pf;
453 1.1 plunky chan->npfilter = nf;
454 1.1 plunky
455 1.1 plunky rsp = BNEP_FILTER_SUCCESS;
456 1.1 plunky
457 1.1 plunky done:
458 1.1 plunky log_debug("addr %s response 0x%2.2x",
459 1.1 plunky ether_ntoa((struct ether_addr *)chan->raddr), rsp);
460 1.1 plunky
461 1.1 plunky bnep_send_control(chan, BNEP_FILTER_NET_TYPE_RESPONSE, rsp);
462 1.1 plunky return (len + 2);
463 1.1 plunky }
464 1.1 plunky
465 1.1 plunky static size_t
466 1.1 plunky bnep_recv_filter_net_type_rsp(channel_t *chan, uint8_t *ptr, size_t size)
467 1.1 plunky {
468 1.1 plunky int rsp;
469 1.1 plunky
470 1.1 plunky if (size < 2)
471 1.1 plunky return 0;
472 1.1 plunky
473 1.1 plunky if (chan->state != CHANNEL_OPEN) {
474 1.1 plunky log_debug("ignored");
475 1.1 plunky return 2;
476 1.1 plunky }
477 1.1 plunky
478 1.1 plunky rsp = be16dec(ptr);
479 1.7 plunky if (rsp != BNEP_FILTER_SUCCESS)
480 1.7 plunky log_err("filter_net_type: addr %s response 0x%2.2x",
481 1.7 plunky ether_ntoa((struct ether_addr *)chan->raddr), rsp);
482 1.1 plunky
483 1.1 plunky /* we did not send any filter_net_type_set message */
484 1.1 plunky return 2;
485 1.1 plunky }
486 1.1 plunky
487 1.1 plunky static size_t
488 1.1 plunky bnep_recv_filter_multi_addr_set(channel_t *chan, uint8_t *ptr, size_t size)
489 1.1 plunky {
490 1.1 plunky mfilter_t *mf;
491 1.3 plunky int i, nf, rsp;
492 1.3 plunky size_t len;
493 1.1 plunky
494 1.1 plunky if (size < 2)
495 1.1 plunky return 0;
496 1.1 plunky
497 1.1 plunky len = be16dec(ptr);
498 1.1 plunky ptr += 2;
499 1.1 plunky
500 1.1 plunky if (size < (len + 2))
501 1.1 plunky return 0;
502 1.1 plunky
503 1.1 plunky if (chan->state != CHANNEL_OPEN) {
504 1.1 plunky log_debug("ignored");
505 1.1 plunky return (len + 2);
506 1.1 plunky }
507 1.1 plunky
508 1.1 plunky nf = len / (ETHER_ADDR_LEN * 2);
509 1.1 plunky mf = malloc(nf * sizeof(mfilter_t));
510 1.1 plunky if (mf == NULL) {
511 1.1 plunky rsp = BNEP_FILTER_TOO_MANY_FILTERS;
512 1.1 plunky goto done;
513 1.1 plunky }
514 1.1 plunky
515 1.1 plunky log_debug("nf = %d", nf);
516 1.1 plunky
517 1.1 plunky for (i = 0; i < nf; i++) {
518 1.1 plunky memcpy(mf[i].start, ptr, ETHER_ADDR_LEN);
519 1.1 plunky ptr += ETHER_ADDR_LEN;
520 1.1 plunky
521 1.1 plunky memcpy(mf[i].end, ptr, ETHER_ADDR_LEN);
522 1.1 plunky ptr += ETHER_ADDR_LEN;
523 1.1 plunky
524 1.1 plunky if (memcmp(mf[i].start, mf[i].end, ETHER_ADDR_LEN) > 0) {
525 1.1 plunky free(mf);
526 1.1 plunky rsp = BNEP_FILTER_INVALID_RANGE;
527 1.1 plunky goto done;
528 1.1 plunky }
529 1.1 plunky
530 1.1 plunky log_debug("pf[%d] = "
531 1.1 plunky "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
532 1.1 plunky "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", i,
533 1.1 plunky mf[i].start[0], mf[i].start[1], mf[i].start[2],
534 1.1 plunky mf[i].start[3], mf[i].start[4], mf[i].start[5],
535 1.1 plunky mf[i].end[0], mf[i].end[1], mf[i].end[2],
536 1.1 plunky mf[i].end[3], mf[i].end[4], mf[i].end[5]);
537 1.1 plunky }
538 1.1 plunky
539 1.1 plunky if (chan->mfilter)
540 1.1 plunky free(chan->mfilter);
541 1.1 plunky
542 1.1 plunky chan->mfilter = mf;
543 1.1 plunky chan->nmfilter = nf;
544 1.1 plunky
545 1.1 plunky rsp = BNEP_FILTER_SUCCESS;
546 1.1 plunky
547 1.1 plunky done:
548 1.1 plunky log_debug("addr %s response 0x%2.2x",
549 1.1 plunky ether_ntoa((struct ether_addr *)chan->raddr), rsp);
550 1.1 plunky
551 1.1 plunky bnep_send_control(chan, BNEP_FILTER_MULTI_ADDR_RESPONSE, rsp);
552 1.1 plunky return (len + 2);
553 1.1 plunky }
554 1.1 plunky
555 1.1 plunky static size_t
556 1.1 plunky bnep_recv_filter_multi_addr_rsp(channel_t *chan, uint8_t *ptr, size_t size)
557 1.1 plunky {
558 1.1 plunky int rsp;
559 1.1 plunky
560 1.1 plunky if (size < 2)
561 1.1 plunky return false;
562 1.1 plunky
563 1.1 plunky if (chan->state != CHANNEL_OPEN) {
564 1.1 plunky log_debug("ignored");
565 1.1 plunky return 2;
566 1.1 plunky }
567 1.1 plunky
568 1.1 plunky rsp = be16dec(ptr);
569 1.7 plunky if (rsp != BNEP_FILTER_SUCCESS)
570 1.7 plunky log_err("filter_multi_addr: addr %s response 0x%2.2x",
571 1.7 plunky ether_ntoa((struct ether_addr *)chan->raddr), rsp);
572 1.1 plunky
573 1.1 plunky /* we did not send any filter_multi_addr_set message */
574 1.1 plunky return 2;
575 1.1 plunky }
576 1.1 plunky
577 1.1 plunky void
578 1.1 plunky bnep_send_control(channel_t *chan, uint8_t type, ...)
579 1.1 plunky {
580 1.1 plunky packet_t *pkt;
581 1.1 plunky uint8_t *p;
582 1.1 plunky va_list ap;
583 1.1 plunky
584 1.4 plunky assert(chan->state != CHANNEL_CLOSED);
585 1.1 plunky
586 1.1 plunky pkt = packet_alloc(chan);
587 1.1 plunky if (pkt == NULL)
588 1.1 plunky return;
589 1.1 plunky
590 1.1 plunky p = pkt->ptr;
591 1.1 plunky va_start(ap, type);
592 1.1 plunky
593 1.1 plunky *p++ = BNEP_CONTROL;
594 1.1 plunky *p++ = type;
595 1.1 plunky
596 1.1 plunky switch(type) {
597 1.1 plunky case BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD:
598 1.1 plunky *p++ = va_arg(ap, int);
599 1.1 plunky break;
600 1.1 plunky
601 1.1 plunky case BNEP_SETUP_CONNECTION_REQUEST:
602 1.1 plunky *p++ = va_arg(ap, int);
603 1.1 plunky be16enc(p, va_arg(ap, int));
604 1.1 plunky p += 2;
605 1.1 plunky be16enc(p, va_arg(ap, int));
606 1.1 plunky p += 2;
607 1.1 plunky break;
608 1.1 plunky
609 1.1 plunky case BNEP_SETUP_CONNECTION_RESPONSE:
610 1.1 plunky case BNEP_FILTER_NET_TYPE_RESPONSE:
611 1.1 plunky case BNEP_FILTER_MULTI_ADDR_RESPONSE:
612 1.1 plunky be16enc(p, va_arg(ap, int));
613 1.1 plunky p += 2;
614 1.1 plunky break;
615 1.1 plunky
616 1.1 plunky case BNEP_FILTER_NET_TYPE_SET: /* TODO */
617 1.1 plunky case BNEP_FILTER_MULTI_ADDR_SET: /* TODO */
618 1.1 plunky default:
619 1.1 plunky log_err("Can't send control type 0x%2.2x", type);
620 1.1 plunky break;
621 1.1 plunky }
622 1.1 plunky
623 1.1 plunky va_end(ap);
624 1.1 plunky pkt->len = p - pkt->ptr;
625 1.1 plunky
626 1.1 plunky channel_put(chan, pkt);
627 1.1 plunky packet_free(pkt);
628 1.1 plunky }
629 1.1 plunky
630 1.1 plunky /*
631 1.1 plunky * BNEP send packet routine
632 1.1 plunky * return true if packet can be removed from queue
633 1.1 plunky */
634 1.1 plunky bool
635 1.1 plunky bnep_send(channel_t *chan, packet_t *pkt)
636 1.1 plunky {
637 1.1 plunky struct iovec iov[2];
638 1.1 plunky uint8_t *p, *type, *proto;
639 1.1 plunky exthdr_t *eh;
640 1.1 plunky bool src, dst;
641 1.1 plunky size_t nw;
642 1.1 plunky
643 1.1 plunky if (pkt->type == NULL) {
644 1.1 plunky iov[0].iov_base = pkt->ptr;
645 1.1 plunky iov[0].iov_len = pkt->len;
646 1.1 plunky iov[1].iov_base = NULL;
647 1.1 plunky iov[1].iov_len = 0;
648 1.1 plunky } else {
649 1.1 plunky p = chan->sendbuf;
650 1.1 plunky
651 1.1 plunky dst = (memcmp(pkt->dst, chan->raddr, ETHER_ADDR_LEN) != 0);
652 1.1 plunky src = (memcmp(pkt->src, chan->laddr, ETHER_ADDR_LEN) != 0);
653 1.1 plunky
654 1.1 plunky type = p;
655 1.1 plunky p += 1;
656 1.1 plunky
657 1.1 plunky if (dst && src)
658 1.1 plunky *type = BNEP_GENERAL_ETHERNET;
659 1.1 plunky else if (dst && !src)
660 1.1 plunky *type = BNEP_COMPRESSED_ETHERNET_DST_ONLY;
661 1.1 plunky else if (!dst && src)
662 1.1 plunky *type = BNEP_COMPRESSED_ETHERNET_SRC_ONLY;
663 1.1 plunky else /* (!dst && !src) */
664 1.1 plunky *type = BNEP_COMPRESSED_ETHERNET;
665 1.1 plunky
666 1.1 plunky if (dst) {
667 1.1 plunky memcpy(p, pkt->dst, ETHER_ADDR_LEN);
668 1.1 plunky p += ETHER_ADDR_LEN;
669 1.1 plunky }
670 1.1 plunky
671 1.1 plunky if (src) {
672 1.1 plunky memcpy(p, pkt->src, ETHER_ADDR_LEN);
673 1.1 plunky p += ETHER_ADDR_LEN;
674 1.1 plunky }
675 1.1 plunky
676 1.1 plunky proto = p;
677 1.1 plunky memcpy(p, pkt->type, ETHER_TYPE_LEN);
678 1.1 plunky p += ETHER_TYPE_LEN;
679 1.1 plunky
680 1.1 plunky STAILQ_FOREACH(eh, &pkt->extlist, next) {
681 1.1 plunky if (p + eh->len > chan->sendbuf + chan->mtu)
682 1.1 plunky break;
683 1.1 plunky
684 1.1 plunky *type |= BNEP_EXT;
685 1.1 plunky type = p;
686 1.1 plunky
687 1.1 plunky memcpy(p, eh->ptr, eh->len);
688 1.1 plunky p += eh->len;
689 1.1 plunky }
690 1.1 plunky
691 1.1 plunky *type &= ~BNEP_EXT;
692 1.1 plunky
693 1.1 plunky iov[0].iov_base = chan->sendbuf;
694 1.1 plunky iov[0].iov_len = (p - chan->sendbuf);
695 1.1 plunky
696 1.1 plunky if ((chan->npfilter == 0 || bnep_pfilter(chan, pkt))
697 1.1 plunky && (chan->nmfilter == 0 || bnep_mfilter(chan, pkt))) {
698 1.1 plunky iov[1].iov_base = pkt->ptr;
699 1.1 plunky iov[1].iov_len = pkt->len;
700 1.1 plunky } else if (be16dec(proto) == ETHERTYPE_VLAN
701 1.1 plunky && pkt->len >= ETHER_VLAN_ENCAP_LEN) {
702 1.1 plunky iov[1].iov_base = pkt->ptr;
703 1.1 plunky iov[1].iov_len = ETHER_VLAN_ENCAP_LEN;
704 1.1 plunky } else {
705 1.1 plunky iov[1].iov_base = NULL;
706 1.1 plunky iov[1].iov_len = 0;
707 1.1 plunky memset(proto, 0, ETHER_TYPE_LEN);
708 1.1 plunky }
709 1.1 plunky }
710 1.1 plunky
711 1.1 plunky if (iov[0].iov_len + iov[1].iov_len > chan->mtu) {
712 1.1 plunky log_err("packet exceeded MTU (dropped)");
713 1.1 plunky return false;
714 1.1 plunky }
715 1.1 plunky
716 1.1 plunky nw = writev(chan->fd, iov, __arraycount(iov));
717 1.1 plunky return (nw > 0);
718 1.1 plunky }
719 1.1 plunky
720 1.1 plunky static bool
721 1.1 plunky bnep_pfilter(channel_t *chan, packet_t *pkt)
722 1.1 plunky {
723 1.1 plunky int proto, i;
724 1.1 plunky
725 1.1 plunky proto = be16dec(pkt->type);
726 1.1 plunky if (proto == ETHERTYPE_VLAN) { /* IEEE 802.1Q tag header */
727 1.1 plunky if (pkt->len < 4)
728 1.1 plunky return false;
729 1.1 plunky
730 1.1 plunky proto = be16dec(pkt->ptr + 2);
731 1.1 plunky }
732 1.1 plunky
733 1.1 plunky for (i = 0; i < chan->npfilter; i++) {
734 1.1 plunky if (chan->pfilter[i].start <= proto
735 1.1 plunky && chan->pfilter[i].end >=proto)
736 1.1 plunky return true;
737 1.1 plunky }
738 1.1 plunky
739 1.1 plunky return false;
740 1.1 plunky }
741 1.1 plunky
742 1.1 plunky static bool
743 1.1 plunky bnep_mfilter(channel_t *chan, packet_t *pkt)
744 1.1 plunky {
745 1.1 plunky int i;
746 1.1 plunky
747 1.1 plunky if (!ETHER_IS_MULTICAST(pkt->dst))
748 1.1 plunky return true;
749 1.1 plunky
750 1.1 plunky for (i = 0; i < chan->nmfilter; i++) {
751 1.1 plunky if (memcmp(pkt->dst, chan->mfilter[i].start, ETHER_ADDR_LEN) >= 0
752 1.1 plunky && memcmp(pkt->dst, chan->mfilter[i].end, ETHER_ADDR_LEN) <= 0)
753 1.1 plunky return true;
754 1.1 plunky }
755 1.1 plunky
756 1.1 plunky return false;
757 1.1 plunky }
758