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