bnep.c revision 1.8.2.1 1 1.8.2.1 bouyer /* $NetBSD: bnep.c,v 1.8.2.1 2011/02/08 16:20:13 bouyer 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.2.1 bouyer __RCSID("$NetBSD: bnep.c,v 1.8.2.1 2011/02/08 16:20:13 bouyer 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.8.2.1 bouyer if (rsp == BNEP_SETUP_SUCCESS) {
374 1.8.2.1 bouyer bnep_send_control(chan, BNEP_FILTER_NET_TYPE_SET);
375 1.8.2.1 bouyer bnep_send_control(chan, BNEP_FILTER_MULTI_ADDR_SET);
376 1.8.2.1 bouyer }
377 1.1 plunky return (len * 2 + 1);
378 1.1 plunky }
379 1.1 plunky
380 1.1 plunky static size_t
381 1.1 plunky bnep_recv_setup_connection_rsp(channel_t *chan, uint8_t *ptr, size_t size)
382 1.1 plunky {
383 1.1 plunky int rsp;
384 1.1 plunky
385 1.1 plunky if (size < 2)
386 1.1 plunky return 0;
387 1.1 plunky
388 1.1 plunky rsp = be16dec(ptr);
389 1.1 plunky
390 1.1 plunky if (chan->state != CHANNEL_WAIT_CONNECT_RSP) {
391 1.1 plunky log_debug("ignored");
392 1.1 plunky return 2;
393 1.1 plunky }
394 1.1 plunky
395 1.1 plunky log_debug("addr %s response 0x%2.2x",
396 1.1 plunky ether_ntoa((struct ether_addr *)chan->raddr), rsp);
397 1.1 plunky
398 1.1 plunky if (rsp == BNEP_SETUP_SUCCESS) {
399 1.1 plunky chan->state = CHANNEL_OPEN;
400 1.1 plunky channel_timeout(chan, 0);
401 1.8.2.1 bouyer bnep_send_control(chan, BNEP_FILTER_NET_TYPE_SET);
402 1.8.2.1 bouyer bnep_send_control(chan, BNEP_FILTER_MULTI_ADDR_SET);
403 1.1 plunky } else {
404 1.8 plunky chan->down(chan);
405 1.1 plunky }
406 1.1 plunky
407 1.1 plunky return 2;
408 1.1 plunky }
409 1.1 plunky
410 1.1 plunky static size_t
411 1.1 plunky bnep_recv_filter_net_type_set(channel_t *chan, uint8_t *ptr, size_t size)
412 1.1 plunky {
413 1.1 plunky pfilter_t *pf;
414 1.3 plunky int i, nf, rsp;
415 1.3 plunky size_t len;
416 1.1 plunky
417 1.1 plunky if (size < 2)
418 1.1 plunky return 0;
419 1.1 plunky
420 1.1 plunky len = be16dec(ptr);
421 1.1 plunky ptr += 2;
422 1.1 plunky
423 1.1 plunky if (size < (len + 2))
424 1.1 plunky return 0;
425 1.1 plunky
426 1.1 plunky if (chan->state != CHANNEL_OPEN) {
427 1.1 plunky log_debug("ignored");
428 1.1 plunky return (len + 2);
429 1.1 plunky }
430 1.1 plunky
431 1.1 plunky nf = len / 4;
432 1.1 plunky pf = malloc(nf * sizeof(pfilter_t));
433 1.1 plunky if (pf == NULL) {
434 1.1 plunky rsp = BNEP_FILTER_TOO_MANY_FILTERS;
435 1.1 plunky goto done;
436 1.1 plunky }
437 1.1 plunky
438 1.1 plunky log_debug("nf = %d", nf);
439 1.1 plunky
440 1.1 plunky for (i = 0; i < nf; i++) {
441 1.1 plunky pf[i].start = be16dec(ptr);
442 1.1 plunky ptr += 2;
443 1.1 plunky pf[i].end = be16dec(ptr);
444 1.1 plunky ptr += 2;
445 1.1 plunky
446 1.1 plunky if (pf[i].start > pf[i].end) {
447 1.1 plunky free(pf);
448 1.1 plunky rsp = BNEP_FILTER_INVALID_RANGE;
449 1.1 plunky goto done;
450 1.1 plunky }
451 1.1 plunky
452 1.1 plunky log_debug("pf[%d] = %#4.4x, %#4.4x", i, pf[i].start, pf[i].end);
453 1.1 plunky }
454 1.1 plunky
455 1.1 plunky if (chan->pfilter)
456 1.1 plunky free(chan->pfilter);
457 1.1 plunky
458 1.1 plunky chan->pfilter = pf;
459 1.1 plunky chan->npfilter = nf;
460 1.1 plunky
461 1.1 plunky rsp = BNEP_FILTER_SUCCESS;
462 1.1 plunky
463 1.1 plunky done:
464 1.1 plunky log_debug("addr %s response 0x%2.2x",
465 1.1 plunky ether_ntoa((struct ether_addr *)chan->raddr), rsp);
466 1.1 plunky
467 1.1 plunky bnep_send_control(chan, BNEP_FILTER_NET_TYPE_RESPONSE, rsp);
468 1.1 plunky return (len + 2);
469 1.1 plunky }
470 1.1 plunky
471 1.1 plunky static size_t
472 1.1 plunky bnep_recv_filter_net_type_rsp(channel_t *chan, uint8_t *ptr, size_t size)
473 1.1 plunky {
474 1.1 plunky int rsp;
475 1.1 plunky
476 1.1 plunky if (size < 2)
477 1.1 plunky return 0;
478 1.1 plunky
479 1.1 plunky if (chan->state != CHANNEL_OPEN) {
480 1.1 plunky log_debug("ignored");
481 1.1 plunky return 2;
482 1.1 plunky }
483 1.1 plunky
484 1.1 plunky rsp = be16dec(ptr);
485 1.7 plunky if (rsp != BNEP_FILTER_SUCCESS)
486 1.7 plunky log_err("filter_net_type: addr %s response 0x%2.2x",
487 1.7 plunky ether_ntoa((struct ether_addr *)chan->raddr), rsp);
488 1.1 plunky
489 1.1 plunky return 2;
490 1.1 plunky }
491 1.1 plunky
492 1.1 plunky static size_t
493 1.1 plunky bnep_recv_filter_multi_addr_set(channel_t *chan, uint8_t *ptr, size_t size)
494 1.1 plunky {
495 1.1 plunky mfilter_t *mf;
496 1.3 plunky int i, nf, rsp;
497 1.3 plunky size_t len;
498 1.1 plunky
499 1.1 plunky if (size < 2)
500 1.1 plunky return 0;
501 1.1 plunky
502 1.1 plunky len = be16dec(ptr);
503 1.1 plunky ptr += 2;
504 1.1 plunky
505 1.1 plunky if (size < (len + 2))
506 1.1 plunky return 0;
507 1.1 plunky
508 1.1 plunky if (chan->state != CHANNEL_OPEN) {
509 1.1 plunky log_debug("ignored");
510 1.1 plunky return (len + 2);
511 1.1 plunky }
512 1.1 plunky
513 1.1 plunky nf = len / (ETHER_ADDR_LEN * 2);
514 1.1 plunky mf = malloc(nf * sizeof(mfilter_t));
515 1.1 plunky if (mf == NULL) {
516 1.1 plunky rsp = BNEP_FILTER_TOO_MANY_FILTERS;
517 1.1 plunky goto done;
518 1.1 plunky }
519 1.1 plunky
520 1.1 plunky log_debug("nf = %d", nf);
521 1.1 plunky
522 1.1 plunky for (i = 0; i < nf; i++) {
523 1.1 plunky memcpy(mf[i].start, ptr, ETHER_ADDR_LEN);
524 1.1 plunky ptr += ETHER_ADDR_LEN;
525 1.1 plunky
526 1.1 plunky memcpy(mf[i].end, ptr, ETHER_ADDR_LEN);
527 1.1 plunky ptr += ETHER_ADDR_LEN;
528 1.1 plunky
529 1.1 plunky if (memcmp(mf[i].start, mf[i].end, ETHER_ADDR_LEN) > 0) {
530 1.1 plunky free(mf);
531 1.1 plunky rsp = BNEP_FILTER_INVALID_RANGE;
532 1.1 plunky goto done;
533 1.1 plunky }
534 1.1 plunky
535 1.1 plunky log_debug("pf[%d] = "
536 1.1 plunky "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
537 1.1 plunky "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", i,
538 1.1 plunky mf[i].start[0], mf[i].start[1], mf[i].start[2],
539 1.1 plunky mf[i].start[3], mf[i].start[4], mf[i].start[5],
540 1.1 plunky mf[i].end[0], mf[i].end[1], mf[i].end[2],
541 1.1 plunky mf[i].end[3], mf[i].end[4], mf[i].end[5]);
542 1.1 plunky }
543 1.1 plunky
544 1.1 plunky if (chan->mfilter)
545 1.1 plunky free(chan->mfilter);
546 1.1 plunky
547 1.1 plunky chan->mfilter = mf;
548 1.1 plunky chan->nmfilter = nf;
549 1.1 plunky
550 1.1 plunky rsp = BNEP_FILTER_SUCCESS;
551 1.1 plunky
552 1.1 plunky done:
553 1.1 plunky log_debug("addr %s response 0x%2.2x",
554 1.1 plunky ether_ntoa((struct ether_addr *)chan->raddr), rsp);
555 1.1 plunky
556 1.1 plunky bnep_send_control(chan, BNEP_FILTER_MULTI_ADDR_RESPONSE, rsp);
557 1.1 plunky return (len + 2);
558 1.1 plunky }
559 1.1 plunky
560 1.1 plunky static size_t
561 1.1 plunky bnep_recv_filter_multi_addr_rsp(channel_t *chan, uint8_t *ptr, size_t size)
562 1.1 plunky {
563 1.1 plunky int rsp;
564 1.1 plunky
565 1.1 plunky if (size < 2)
566 1.1 plunky return false;
567 1.1 plunky
568 1.1 plunky if (chan->state != CHANNEL_OPEN) {
569 1.1 plunky log_debug("ignored");
570 1.1 plunky return 2;
571 1.1 plunky }
572 1.1 plunky
573 1.1 plunky rsp = be16dec(ptr);
574 1.7 plunky if (rsp != BNEP_FILTER_SUCCESS)
575 1.7 plunky log_err("filter_multi_addr: addr %s response 0x%2.2x",
576 1.7 plunky ether_ntoa((struct ether_addr *)chan->raddr), rsp);
577 1.1 plunky
578 1.1 plunky return 2;
579 1.1 plunky }
580 1.1 plunky
581 1.1 plunky void
582 1.1 plunky bnep_send_control(channel_t *chan, uint8_t type, ...)
583 1.1 plunky {
584 1.1 plunky packet_t *pkt;
585 1.1 plunky uint8_t *p;
586 1.1 plunky va_list ap;
587 1.1 plunky
588 1.4 plunky assert(chan->state != CHANNEL_CLOSED);
589 1.1 plunky
590 1.1 plunky pkt = packet_alloc(chan);
591 1.1 plunky if (pkt == NULL)
592 1.1 plunky return;
593 1.1 plunky
594 1.1 plunky p = pkt->ptr;
595 1.1 plunky va_start(ap, type);
596 1.1 plunky
597 1.1 plunky *p++ = BNEP_CONTROL;
598 1.1 plunky *p++ = type;
599 1.1 plunky
600 1.1 plunky switch(type) {
601 1.1 plunky case BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD:
602 1.1 plunky *p++ = va_arg(ap, int);
603 1.1 plunky break;
604 1.1 plunky
605 1.1 plunky case BNEP_SETUP_CONNECTION_REQUEST:
606 1.1 plunky *p++ = va_arg(ap, int);
607 1.1 plunky be16enc(p, va_arg(ap, int));
608 1.1 plunky p += 2;
609 1.1 plunky be16enc(p, va_arg(ap, int));
610 1.1 plunky p += 2;
611 1.1 plunky break;
612 1.1 plunky
613 1.1 plunky case BNEP_SETUP_CONNECTION_RESPONSE:
614 1.1 plunky case BNEP_FILTER_NET_TYPE_RESPONSE:
615 1.1 plunky case BNEP_FILTER_MULTI_ADDR_RESPONSE:
616 1.1 plunky be16enc(p, va_arg(ap, int));
617 1.1 plunky p += 2;
618 1.1 plunky break;
619 1.1 plunky
620 1.8.2.1 bouyer case BNEP_FILTER_NET_TYPE_SET:
621 1.8.2.1 bouyer case BNEP_FILTER_MULTI_ADDR_SET:
622 1.8.2.1 bouyer be16enc(p, 0); /* just clear filters for now */
623 1.8.2.1 bouyer p += 2;
624 1.8.2.1 bouyer break;
625 1.8.2.1 bouyer
626 1.1 plunky default:
627 1.1 plunky log_err("Can't send control type 0x%2.2x", type);
628 1.1 plunky break;
629 1.1 plunky }
630 1.1 plunky
631 1.1 plunky va_end(ap);
632 1.1 plunky pkt->len = p - pkt->ptr;
633 1.1 plunky
634 1.1 plunky channel_put(chan, pkt);
635 1.1 plunky packet_free(pkt);
636 1.1 plunky }
637 1.1 plunky
638 1.1 plunky /*
639 1.1 plunky * BNEP send packet routine
640 1.1 plunky * return true if packet can be removed from queue
641 1.1 plunky */
642 1.1 plunky bool
643 1.1 plunky bnep_send(channel_t *chan, packet_t *pkt)
644 1.1 plunky {
645 1.1 plunky struct iovec iov[2];
646 1.1 plunky uint8_t *p, *type, *proto;
647 1.1 plunky exthdr_t *eh;
648 1.1 plunky bool src, dst;
649 1.1 plunky size_t nw;
650 1.1 plunky
651 1.1 plunky if (pkt->type == NULL) {
652 1.1 plunky iov[0].iov_base = pkt->ptr;
653 1.1 plunky iov[0].iov_len = pkt->len;
654 1.1 plunky iov[1].iov_base = NULL;
655 1.1 plunky iov[1].iov_len = 0;
656 1.1 plunky } else {
657 1.1 plunky p = chan->sendbuf;
658 1.1 plunky
659 1.1 plunky dst = (memcmp(pkt->dst, chan->raddr, ETHER_ADDR_LEN) != 0);
660 1.1 plunky src = (memcmp(pkt->src, chan->laddr, ETHER_ADDR_LEN) != 0);
661 1.1 plunky
662 1.1 plunky type = p;
663 1.1 plunky p += 1;
664 1.1 plunky
665 1.1 plunky if (dst && src)
666 1.1 plunky *type = BNEP_GENERAL_ETHERNET;
667 1.1 plunky else if (dst && !src)
668 1.1 plunky *type = BNEP_COMPRESSED_ETHERNET_DST_ONLY;
669 1.1 plunky else if (!dst && src)
670 1.1 plunky *type = BNEP_COMPRESSED_ETHERNET_SRC_ONLY;
671 1.1 plunky else /* (!dst && !src) */
672 1.1 plunky *type = BNEP_COMPRESSED_ETHERNET;
673 1.1 plunky
674 1.1 plunky if (dst) {
675 1.1 plunky memcpy(p, pkt->dst, ETHER_ADDR_LEN);
676 1.1 plunky p += ETHER_ADDR_LEN;
677 1.1 plunky }
678 1.1 plunky
679 1.1 plunky if (src) {
680 1.1 plunky memcpy(p, pkt->src, ETHER_ADDR_LEN);
681 1.1 plunky p += ETHER_ADDR_LEN;
682 1.1 plunky }
683 1.1 plunky
684 1.1 plunky proto = p;
685 1.1 plunky memcpy(p, pkt->type, ETHER_TYPE_LEN);
686 1.1 plunky p += ETHER_TYPE_LEN;
687 1.1 plunky
688 1.1 plunky STAILQ_FOREACH(eh, &pkt->extlist, next) {
689 1.1 plunky if (p + eh->len > chan->sendbuf + chan->mtu)
690 1.1 plunky break;
691 1.1 plunky
692 1.1 plunky *type |= BNEP_EXT;
693 1.1 plunky type = p;
694 1.1 plunky
695 1.1 plunky memcpy(p, eh->ptr, eh->len);
696 1.1 plunky p += eh->len;
697 1.1 plunky }
698 1.1 plunky
699 1.1 plunky *type &= ~BNEP_EXT;
700 1.1 plunky
701 1.1 plunky iov[0].iov_base = chan->sendbuf;
702 1.1 plunky iov[0].iov_len = (p - chan->sendbuf);
703 1.1 plunky
704 1.1 plunky if ((chan->npfilter == 0 || bnep_pfilter(chan, pkt))
705 1.1 plunky && (chan->nmfilter == 0 || bnep_mfilter(chan, pkt))) {
706 1.1 plunky iov[1].iov_base = pkt->ptr;
707 1.1 plunky iov[1].iov_len = pkt->len;
708 1.1 plunky } else if (be16dec(proto) == ETHERTYPE_VLAN
709 1.1 plunky && pkt->len >= ETHER_VLAN_ENCAP_LEN) {
710 1.1 plunky iov[1].iov_base = pkt->ptr;
711 1.1 plunky iov[1].iov_len = ETHER_VLAN_ENCAP_LEN;
712 1.1 plunky } else {
713 1.1 plunky iov[1].iov_base = NULL;
714 1.1 plunky iov[1].iov_len = 0;
715 1.1 plunky memset(proto, 0, ETHER_TYPE_LEN);
716 1.1 plunky }
717 1.1 plunky }
718 1.1 plunky
719 1.1 plunky if (iov[0].iov_len + iov[1].iov_len > chan->mtu) {
720 1.1 plunky log_err("packet exceeded MTU (dropped)");
721 1.1 plunky return false;
722 1.1 plunky }
723 1.1 plunky
724 1.1 plunky nw = writev(chan->fd, iov, __arraycount(iov));
725 1.1 plunky return (nw > 0);
726 1.1 plunky }
727 1.1 plunky
728 1.1 plunky static bool
729 1.1 plunky bnep_pfilter(channel_t *chan, packet_t *pkt)
730 1.1 plunky {
731 1.1 plunky int proto, i;
732 1.1 plunky
733 1.1 plunky proto = be16dec(pkt->type);
734 1.1 plunky if (proto == ETHERTYPE_VLAN) { /* IEEE 802.1Q tag header */
735 1.1 plunky if (pkt->len < 4)
736 1.1 plunky return false;
737 1.1 plunky
738 1.1 plunky proto = be16dec(pkt->ptr + 2);
739 1.1 plunky }
740 1.1 plunky
741 1.1 plunky for (i = 0; i < chan->npfilter; i++) {
742 1.1 plunky if (chan->pfilter[i].start <= proto
743 1.1 plunky && chan->pfilter[i].end >=proto)
744 1.1 plunky return true;
745 1.1 plunky }
746 1.1 plunky
747 1.1 plunky return false;
748 1.1 plunky }
749 1.1 plunky
750 1.1 plunky static bool
751 1.1 plunky bnep_mfilter(channel_t *chan, packet_t *pkt)
752 1.1 plunky {
753 1.1 plunky int i;
754 1.1 plunky
755 1.1 plunky if (!ETHER_IS_MULTICAST(pkt->dst))
756 1.1 plunky return true;
757 1.1 plunky
758 1.1 plunky for (i = 0; i < chan->nmfilter; i++) {
759 1.1 plunky if (memcmp(pkt->dst, chan->mfilter[i].start, ETHER_ADDR_LEN) >= 0
760 1.1 plunky && memcmp(pkt->dst, chan->mfilter[i].end, ETHER_ADDR_LEN) <= 0)
761 1.1 plunky return true;
762 1.1 plunky }
763 1.1 plunky
764 1.1 plunky return false;
765 1.1 plunky }
766