diff options
Diffstat (limited to 'src/transport/plugin_transport_bluetooth.c')
-rw-r--r-- | src/transport/plugin_transport_bluetooth.c | 1879 |
1 files changed, 1879 insertions, 0 deletions
diff --git a/src/transport/plugin_transport_bluetooth.c b/src/transport/plugin_transport_bluetooth.c new file mode 100644 index 000000000..57de3022b --- /dev/null +++ b/src/transport/plugin_transport_bluetooth.c | |||
@@ -0,0 +1,1879 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | (C) 2010, 2011, 2012 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file transport/plugin_transport_bluetooth.c | ||
23 | * @brief transport plugin for bluetooth | ||
24 | * @author David Brodski | ||
25 | * @author Christian Grothoff | ||
26 | * | ||
27 | * THIS IS A COPY OF plugin_transport_wlan.c | ||
28 | */ | ||
29 | #include "platform.h" | ||
30 | #include "gnunet_hello_lib.h" | ||
31 | #include "gnunet_protocols.h" | ||
32 | #include "gnunet_util_lib.h" | ||
33 | #include "gnunet_statistics_service.h" | ||
34 | #include "gnunet_transport_service.h" | ||
35 | #include "gnunet_transport_plugin.h" | ||
36 | #include "plugin_transport_wlan.h" | ||
37 | #include "gnunet_common.h" | ||
38 | #include "gnunet_crypto_lib.h" | ||
39 | #include "gnunet_fragmentation_lib.h" | ||
40 | #include "gnunet_constants.h" | ||
41 | |||
42 | #define LOG(kind,...) GNUNET_log_from (kind, "transport-bluetooth",__VA_ARGS__) | ||
43 | |||
44 | #define PLUGIN_NAME "bluetooth" | ||
45 | |||
46 | /** | ||
47 | * Max size of packet (that we give to the WLAN driver for transmission) | ||
48 | */ | ||
49 | #define WLAN_MTU 1430 | ||
50 | |||
51 | /** | ||
52 | * time out of a mac endpoint | ||
53 | */ | ||
54 | #define MACENDPOINT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, 2) | ||
55 | |||
56 | /** | ||
57 | * We reduce the frequence of HELLO beacons in relation to | ||
58 | * the number of MAC addresses currently visible to us. | ||
59 | * This is the multiplication factor. | ||
60 | */ | ||
61 | #define HELLO_BEACON_SCALING_FACTOR GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2) | ||
62 | |||
63 | /** | ||
64 | * Maximum number of messages in defragmentation queue per MAC | ||
65 | */ | ||
66 | #define MESSAGES_IN_DEFRAG_QUEUE_PER_MAC 2 | ||
67 | |||
68 | /** | ||
69 | * Link layer control fields for better compatibility | ||
70 | * (i.e. GNUnet over WLAN is not IP-over-WLAN). | ||
71 | */ | ||
72 | #define WLAN_LLC_DSAP_FIELD 0x1f | ||
73 | #define WLAN_LLC_SSAP_FIELD 0x1f | ||
74 | |||
75 | |||
76 | GNUNET_NETWORK_STRUCT_BEGIN | ||
77 | /** | ||
78 | * Header for messages which need fragmentation. This is the format of | ||
79 | * a message we obtain AFTER defragmentation. We then need to check | ||
80 | * the CRC and then tokenize the payload and pass it to the | ||
81 | * 'receive' callback. | ||
82 | */ | ||
83 | struct WlanHeader | ||
84 | { | ||
85 | |||
86 | /** | ||
87 | * Message type is GNUNET_MESSAGE_TYPE_WLAN_DATA. | ||
88 | */ | ||
89 | struct GNUNET_MessageHeader header; | ||
90 | |||
91 | /** | ||
92 | * CRC32 checksum (only over the payload), in NBO. | ||
93 | */ | ||
94 | uint32_t crc GNUNET_PACKED; | ||
95 | |||
96 | /** | ||
97 | * Sender of the message. | ||
98 | */ | ||
99 | struct GNUNET_PeerIdentity sender; | ||
100 | |||
101 | /** | ||
102 | * Target of the message. | ||
103 | */ | ||
104 | struct GNUNET_PeerIdentity target; | ||
105 | |||
106 | /* followed by payload, possibly including | ||
107 | multiple messages! */ | ||
108 | |||
109 | }; | ||
110 | |||
111 | |||
112 | struct WlanAddress | ||
113 | { | ||
114 | uint32_t options GNUNET_PACKED; | ||
115 | |||
116 | struct GNUNET_TRANSPORT_WLAN_MacAddress mac; | ||
117 | }; | ||
118 | |||
119 | |||
120 | GNUNET_NETWORK_STRUCT_END | ||
121 | |||
122 | |||
123 | /** | ||
124 | * Information kept for each message that is yet to be fragmented and | ||
125 | * transmitted. | ||
126 | */ | ||
127 | struct PendingMessage | ||
128 | { | ||
129 | /** | ||
130 | * next entry in the DLL | ||
131 | */ | ||
132 | struct PendingMessage *next; | ||
133 | |||
134 | /** | ||
135 | * previous entry in the DLL | ||
136 | */ | ||
137 | struct PendingMessage *prev; | ||
138 | |||
139 | /** | ||
140 | * The pending message | ||
141 | */ | ||
142 | struct WlanHeader *msg; | ||
143 | |||
144 | /** | ||
145 | * Continuation function to call once the message | ||
146 | * has been sent. Can be NULL if there is no | ||
147 | * continuation to call. | ||
148 | */ | ||
149 | GNUNET_TRANSPORT_TransmitContinuation transmit_cont; | ||
150 | |||
151 | /** | ||
152 | * Cls for transmit_cont | ||
153 | */ | ||
154 | void *transmit_cont_cls; | ||
155 | |||
156 | /** | ||
157 | * Timeout task (for this message). | ||
158 | */ | ||
159 | GNUNET_SCHEDULER_TaskIdentifier timeout_task; | ||
160 | |||
161 | }; | ||
162 | |||
163 | |||
164 | /** | ||
165 | * Session handle for connections with other peers. | ||
166 | */ | ||
167 | struct Session | ||
168 | { | ||
169 | /** | ||
170 | * To whom are we talking to (set to our identity | ||
171 | * if we are still waiting for the welcome message) | ||
172 | */ | ||
173 | struct GNUNET_PeerIdentity target; | ||
174 | |||
175 | /** | ||
176 | * API requirement (must be first). | ||
177 | */ | ||
178 | struct SessionHeader header; | ||
179 | |||
180 | /** | ||
181 | * We keep all sessions in a DLL at their respective | ||
182 | * 'struct MACEndpoint'. | ||
183 | */ | ||
184 | struct Session *next; | ||
185 | |||
186 | /** | ||
187 | * We keep all sessions in a DLL at their respective | ||
188 | * 'struct MACEndpoint'. | ||
189 | */ | ||
190 | struct Session *prev; | ||
191 | |||
192 | /** | ||
193 | * MAC endpoint with the address of this peer. | ||
194 | */ | ||
195 | struct MacEndpoint *mac; | ||
196 | |||
197 | /** | ||
198 | * Head of messages currently pending for transmission to this peer. | ||
199 | */ | ||
200 | struct PendingMessage *pending_message_head; | ||
201 | |||
202 | /** | ||
203 | * Tail of messages currently pending for transmission to this peer. | ||
204 | */ | ||
205 | struct PendingMessage *pending_message_tail; | ||
206 | |||
207 | /** | ||
208 | * When should this session time out? | ||
209 | */ | ||
210 | struct GNUNET_TIME_Absolute timeout; | ||
211 | |||
212 | /** | ||
213 | * Timeout task (for the session). | ||
214 | */ | ||
215 | GNUNET_SCHEDULER_TaskIdentifier timeout_task; | ||
216 | |||
217 | }; | ||
218 | |||
219 | |||
220 | /** | ||
221 | * Struct for messages that are being fragmented in a MAC's transmission queue. | ||
222 | */ | ||
223 | struct FragmentMessage | ||
224 | { | ||
225 | |||
226 | /** | ||
227 | * This is a doubly-linked list. | ||
228 | */ | ||
229 | struct FragmentMessage *next; | ||
230 | |||
231 | /** | ||
232 | * This is a doubly-linked list. | ||
233 | */ | ||
234 | struct FragmentMessage *prev; | ||
235 | |||
236 | /** | ||
237 | * MAC endpoint this message belongs to | ||
238 | */ | ||
239 | struct MacEndpoint *macendpoint; | ||
240 | |||
241 | /** | ||
242 | * Fragmentation context | ||
243 | */ | ||
244 | struct GNUNET_FRAGMENT_Context *fragcontext; | ||
245 | |||
246 | /** | ||
247 | * Transmission handle to helper (to cancel if the frag context | ||
248 | * is destroyed early for some reason). | ||
249 | */ | ||
250 | struct GNUNET_HELPER_SendHandle *sh; | ||
251 | |||
252 | /** | ||
253 | * Intended recipient. | ||
254 | */ | ||
255 | struct GNUNET_PeerIdentity target; | ||
256 | |||
257 | /** | ||
258 | * Timeout value for the message. | ||
259 | */ | ||
260 | struct GNUNET_TIME_Absolute timeout; | ||
261 | |||
262 | /** | ||
263 | * Timeout task. | ||
264 | */ | ||
265 | GNUNET_SCHEDULER_TaskIdentifier timeout_task; | ||
266 | |||
267 | /** | ||
268 | * Continuation to call when we're done with this message. | ||
269 | */ | ||
270 | GNUNET_TRANSPORT_TransmitContinuation cont; | ||
271 | |||
272 | /** | ||
273 | * Closure for 'cont' | ||
274 | */ | ||
275 | void *cont_cls; | ||
276 | |||
277 | /** | ||
278 | * Size of original message | ||
279 | */ | ||
280 | size_t size_payload; | ||
281 | |||
282 | /** | ||
283 | * Number of bytes used to transmit message | ||
284 | */ | ||
285 | size_t size_on_wire; | ||
286 | |||
287 | }; | ||
288 | |||
289 | |||
290 | /** | ||
291 | * Struct to represent one network card connection | ||
292 | */ | ||
293 | struct MacEndpoint | ||
294 | { | ||
295 | |||
296 | /** | ||
297 | * We keep all MACs in a DLL in the plugin. | ||
298 | */ | ||
299 | struct MacEndpoint *next; | ||
300 | |||
301 | /** | ||
302 | * We keep all MACs in a DLL in the plugin. | ||
303 | */ | ||
304 | struct MacEndpoint *prev; | ||
305 | |||
306 | /** | ||
307 | * Pointer to the global plugin struct. | ||
308 | */ | ||
309 | struct Plugin *plugin; | ||
310 | |||
311 | /** | ||
312 | * Head of sessions that use this MAC. | ||
313 | */ | ||
314 | struct Session *sessions_head; | ||
315 | |||
316 | /** | ||
317 | * Tail of sessions that use this MAC. | ||
318 | */ | ||
319 | struct Session *sessions_tail; | ||
320 | |||
321 | /** | ||
322 | * Head of messages we are currently sending to this MAC. | ||
323 | */ | ||
324 | struct FragmentMessage *sending_messages_head; | ||
325 | |||
326 | /** | ||
327 | * Tail of messages we are currently sending to this MAC. | ||
328 | */ | ||
329 | struct FragmentMessage *sending_messages_tail; | ||
330 | |||
331 | /** | ||
332 | * Defrag context for this MAC | ||
333 | */ | ||
334 | struct GNUNET_DEFRAGMENT_Context *defrag; | ||
335 | |||
336 | /** | ||
337 | * When should this endpoint time out? | ||
338 | */ | ||
339 | struct GNUNET_TIME_Absolute timeout; | ||
340 | |||
341 | /** | ||
342 | * Timeout task. | ||
343 | */ | ||
344 | GNUNET_SCHEDULER_TaskIdentifier timeout_task; | ||
345 | |||
346 | /** | ||
347 | * count of messages in the fragment out queue for this mac endpoint | ||
348 | */ | ||
349 | unsigned int fragment_messages_out_count; | ||
350 | |||
351 | /** | ||
352 | * peer mac address | ||
353 | */ | ||
354 | struct WlanAddress addr; | ||
355 | |||
356 | /** | ||
357 | * Message delay for fragmentation context | ||
358 | */ | ||
359 | struct GNUNET_TIME_Relative msg_delay; | ||
360 | |||
361 | /** | ||
362 | * ACK delay for fragmentation context | ||
363 | */ | ||
364 | struct GNUNET_TIME_Relative ack_delay; | ||
365 | |||
366 | /** | ||
367 | * Desired transmission power for this MAC | ||
368 | */ | ||
369 | uint16_t tx_power; | ||
370 | |||
371 | /** | ||
372 | * Desired transmission rate for this MAC | ||
373 | */ | ||
374 | uint8_t rate; | ||
375 | |||
376 | /** | ||
377 | * Antenna we should use for this MAC | ||
378 | */ | ||
379 | uint8_t antenna; | ||
380 | |||
381 | }; | ||
382 | |||
383 | |||
384 | /** | ||
385 | * Encapsulation of all of the state of the plugin. | ||
386 | */ | ||
387 | struct Plugin | ||
388 | { | ||
389 | /** | ||
390 | * Our environment. | ||
391 | */ | ||
392 | struct GNUNET_TRANSPORT_PluginEnvironment *env; | ||
393 | |||
394 | /** | ||
395 | * Handle to helper process for priviledged operations. | ||
396 | */ | ||
397 | struct GNUNET_HELPER_Handle *suid_helper; | ||
398 | |||
399 | /** | ||
400 | * ARGV-vector for the helper (all helpers take only the binary | ||
401 | * name, one actual argument, plus the NULL terminator for 'argv'). | ||
402 | */ | ||
403 | char * helper_argv[3]; | ||
404 | |||
405 | /** | ||
406 | * The interface of the wlan card given to us by the user. | ||
407 | */ | ||
408 | char *interface; | ||
409 | |||
410 | /** | ||
411 | * Tokenizer for demultiplexing of data packets resulting from defragmentation. | ||
412 | */ | ||
413 | struct GNUNET_SERVER_MessageStreamTokenizer *fragment_data_tokenizer; | ||
414 | |||
415 | /** | ||
416 | * Tokenizer for demultiplexing of data packets received from the suid helper | ||
417 | */ | ||
418 | struct GNUNET_SERVER_MessageStreamTokenizer *helper_payload_tokenizer; | ||
419 | |||
420 | /** | ||
421 | * Tokenizer for demultiplexing of data packets that follow the WLAN Header | ||
422 | */ | ||
423 | struct GNUNET_SERVER_MessageStreamTokenizer *wlan_header_payload_tokenizer; | ||
424 | |||
425 | /** | ||
426 | * Head of list of open connections. | ||
427 | */ | ||
428 | struct MacEndpoint *mac_head; | ||
429 | |||
430 | /** | ||
431 | * Tail of list of open connections. | ||
432 | */ | ||
433 | struct MacEndpoint *mac_tail; | ||
434 | |||
435 | /** | ||
436 | * Number of connections | ||
437 | */ | ||
438 | unsigned int mac_count; | ||
439 | |||
440 | /** | ||
441 | * Task that periodically sends a HELLO beacon via the helper. | ||
442 | */ | ||
443 | GNUNET_SCHEDULER_TaskIdentifier beacon_task; | ||
444 | |||
445 | /** | ||
446 | * Tracker for bandwidth limit | ||
447 | */ | ||
448 | struct GNUNET_BANDWIDTH_Tracker tracker; | ||
449 | |||
450 | /** | ||
451 | * The mac_address of the wlan card given to us by the helper. | ||
452 | */ | ||
453 | struct GNUNET_TRANSPORT_WLAN_MacAddress mac_address; | ||
454 | |||
455 | /** | ||
456 | * Have we received a control message with our MAC address yet? | ||
457 | */ | ||
458 | int have_mac; | ||
459 | |||
460 | /** | ||
461 | * Options for addresses | ||
462 | */ | ||
463 | uint32_t options; | ||
464 | |||
465 | }; | ||
466 | |||
467 | |||
468 | /** | ||
469 | * Information associated with a message. Can contain | ||
470 | * the session or the MAC endpoint associated with the | ||
471 | * message (or both). | ||
472 | */ | ||
473 | struct MacAndSession | ||
474 | { | ||
475 | /** | ||
476 | * NULL if the identity of the other peer is not known. | ||
477 | */ | ||
478 | struct Session *session; | ||
479 | |||
480 | /** | ||
481 | * MAC address of the other peer, NULL if not known. | ||
482 | */ | ||
483 | struct MacEndpoint *endpoint; | ||
484 | }; | ||
485 | |||
486 | /** | ||
487 | * Function called for a quick conversion of the binary address to | ||
488 | * a numeric address. Note that the caller must not free the | ||
489 | * address and that the next call to this function is allowed | ||
490 | * to override the address again. | ||
491 | * | ||
492 | * @param cls closure | ||
493 | * @param addr binary address | ||
494 | * @param addrlen length of the address | ||
495 | * @return string representing the same address | ||
496 | */ | ||
497 | static const char * | ||
498 | bluetooth_plugin_address_to_string (void *cls, const void *addr, size_t addrlen); | ||
499 | |||
500 | /** | ||
501 | * Print MAC addresses nicely. | ||
502 | * | ||
503 | * @param mac the mac address | ||
504 | * @return string to a static buffer with the human-readable mac, will be overwritten during the next call to this function | ||
505 | */ | ||
506 | static const char * | ||
507 | mac_to_string (const struct GNUNET_TRANSPORT_WLAN_MacAddress * mac) | ||
508 | { | ||
509 | static char macstr[20]; | ||
510 | |||
511 | GNUNET_snprintf (macstr, sizeof (macstr), "%.2X:%.2X:%.2X:%.2X:%.2X:%.2X", | ||
512 | mac->mac[0], mac->mac[1], | ||
513 | mac->mac[2], mac->mac[3], mac->mac[4], mac->mac[5]); | ||
514 | return macstr; | ||
515 | } | ||
516 | |||
517 | |||
518 | /** | ||
519 | * Fill the radiotap header | ||
520 | * | ||
521 | * @param endpoint pointer to the endpoint, can be NULL | ||
522 | * @param header pointer to the radiotap header | ||
523 | * @param size total message size | ||
524 | */ | ||
525 | static void | ||
526 | get_radiotap_header (struct MacEndpoint *endpoint, | ||
527 | struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *header, | ||
528 | uint16_t size) | ||
529 | { | ||
530 | header->header.type = ntohs (GNUNET_MESSAGE_TYPE_WLAN_DATA_TO_HELPER); | ||
531 | header->header.size = ntohs (size); | ||
532 | if (NULL != endpoint) | ||
533 | { | ||
534 | header->rate = endpoint->rate; | ||
535 | header->tx_power = endpoint->tx_power; | ||
536 | header->antenna = endpoint->antenna; | ||
537 | } | ||
538 | else | ||
539 | { | ||
540 | header->rate = 255; | ||
541 | header->tx_power = 0; | ||
542 | header->antenna = 0; | ||
543 | } | ||
544 | } | ||
545 | |||
546 | |||
547 | /** | ||
548 | * Generate the WLAN hardware header for one packet | ||
549 | * | ||
550 | * @param plugin the plugin handle | ||
551 | * @param header address to write the header to | ||
552 | * @param to_mac_addr address of the recipient | ||
553 | * @param size size of the whole packet, needed to calculate the time to send the packet | ||
554 | */ | ||
555 | static void | ||
556 | get_wlan_header (struct Plugin *plugin, | ||
557 | struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *header, | ||
558 | const struct GNUNET_TRANSPORT_WLAN_MacAddress *to_mac_addr, | ||
559 | unsigned int size) | ||
560 | { | ||
561 | const int rate = 11000000; | ||
562 | |||
563 | header->frame_control = htons (IEEE80211_FC0_TYPE_DATA); | ||
564 | header->addr1 = *to_mac_addr; | ||
565 | header->addr2 = plugin->mac_address; | ||
566 | header->addr3 = mac_bssid_gnunet; | ||
567 | header->duration = GNUNET_htole16 ((size * 1000000) / rate + 290); | ||
568 | header->sequence_control = 0; // FIXME? | ||
569 | header->llc[0] = WLAN_LLC_DSAP_FIELD; | ||
570 | header->llc[1] = WLAN_LLC_SSAP_FIELD; | ||
571 | header->llc[2] = 0; // FIXME? | ||
572 | header->llc[3] = 0; // FIXME? | ||
573 | } | ||
574 | |||
575 | |||
576 | /** | ||
577 | * Send an ACK for a fragment we received. | ||
578 | * | ||
579 | * @param cls the 'struct MacEndpoint' the ACK must be sent to | ||
580 | * @param msg_id id of the message | ||
581 | * @param hdr pointer to the hdr where the ack is stored | ||
582 | */ | ||
583 | static void | ||
584 | send_ack (void *cls, uint32_t msg_id, | ||
585 | const struct GNUNET_MessageHeader *hdr) | ||
586 | { | ||
587 | struct MacEndpoint *endpoint = cls; | ||
588 | struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage* radio_header; | ||
589 | uint16_t msize = ntohs (hdr->size); | ||
590 | size_t size = sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage) + msize; | ||
591 | char buf[size]; | ||
592 | |||
593 | if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE) | ||
594 | { | ||
595 | GNUNET_break (0); | ||
596 | return; | ||
597 | } | ||
598 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
599 | "Sending ACK to helper\n"); | ||
600 | radio_header = (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *) buf; | ||
601 | get_radiotap_header (endpoint, radio_header, size); | ||
602 | get_wlan_header (endpoint->plugin, | ||
603 | &radio_header->frame, | ||
604 | &endpoint->addr.mac, | ||
605 | size); | ||
606 | memcpy (&radio_header[1], hdr, msize); | ||
607 | if (NULL != | ||
608 | GNUNET_HELPER_send (endpoint->plugin->suid_helper, | ||
609 | &radio_header->header, | ||
610 | GNUNET_NO /* dropping ACKs is bad */, | ||
611 | NULL, NULL)) | ||
612 | GNUNET_STATISTICS_update (endpoint->plugin->env->stats, _("# Bluetooth ACKs sent"), | ||
613 | 1, GNUNET_NO); | ||
614 | } | ||
615 | |||
616 | |||
617 | /** | ||
618 | * Handles the data after all fragments are put together | ||
619 | * | ||
620 | * @param cls macendpoint this messages belongs to | ||
621 | * @param hdr pointer to the data | ||
622 | */ | ||
623 | static void | ||
624 | bluetooth_data_message_handler (void *cls, const struct GNUNET_MessageHeader *hdr) | ||
625 | { | ||
626 | struct MacEndpoint *endpoint = cls; | ||
627 | struct Plugin *plugin = endpoint->plugin; | ||
628 | struct MacAndSession mas; | ||
629 | |||
630 | GNUNET_STATISTICS_update (plugin->env->stats, | ||
631 | _("# Bluetooth messages defragmented"), 1, | ||
632 | GNUNET_NO); | ||
633 | mas.session = NULL; | ||
634 | mas.endpoint = endpoint; | ||
635 | (void) GNUNET_SERVER_mst_receive (plugin->fragment_data_tokenizer, | ||
636 | &mas, | ||
637 | (const char *) hdr, | ||
638 | ntohs (hdr->size), | ||
639 | GNUNET_YES, GNUNET_NO); | ||
640 | } | ||
641 | |||
642 | |||
643 | /** | ||
644 | * Free a session | ||
645 | * | ||
646 | * @param session the session free | ||
647 | */ | ||
648 | static void | ||
649 | free_session (struct Session *session) | ||
650 | { | ||
651 | struct MacEndpoint *endpoint = session->mac; | ||
652 | struct PendingMessage *pm; | ||
653 | |||
654 | endpoint->plugin->env->session_end (endpoint->plugin->env->cls, | ||
655 | &session->target, | ||
656 | session); | ||
657 | while (NULL != (pm = session->pending_message_head)) | ||
658 | { | ||
659 | GNUNET_CONTAINER_DLL_remove (session->pending_message_head, | ||
660 | session->pending_message_tail, pm); | ||
661 | if (GNUNET_SCHEDULER_NO_TASK != pm->timeout_task) | ||
662 | { | ||
663 | GNUNET_SCHEDULER_cancel (pm->timeout_task); | ||
664 | pm->timeout_task = GNUNET_SCHEDULER_NO_TASK; | ||
665 | } | ||
666 | GNUNET_free (pm->msg); | ||
667 | GNUNET_free (pm); | ||
668 | } | ||
669 | GNUNET_CONTAINER_DLL_remove (endpoint->sessions_head, | ||
670 | endpoint->sessions_tail, | ||
671 | session); | ||
672 | if (session->timeout_task != GNUNET_SCHEDULER_NO_TASK) | ||
673 | { | ||
674 | GNUNET_SCHEDULER_cancel (session->timeout_task); | ||
675 | session->timeout_task = GNUNET_SCHEDULER_NO_TASK; | ||
676 | } | ||
677 | GNUNET_STATISTICS_update (endpoint->plugin->env->stats, _("# Bluetooth sessions allocated"), -1, | ||
678 | GNUNET_NO); | ||
679 | GNUNET_free (session); | ||
680 | } | ||
681 | |||
682 | |||
683 | /** | ||
684 | * A session is timing out. Clean up. | ||
685 | * | ||
686 | * @param cls pointer to the Session | ||
687 | * @param tc pointer to the GNUNET_SCHEDULER_TaskContext | ||
688 | */ | ||
689 | static void | ||
690 | session_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
691 | { | ||
692 | struct Session * session = cls; | ||
693 | struct GNUNET_TIME_Relative timeout; | ||
694 | |||
695 | session->timeout_task = GNUNET_SCHEDULER_NO_TASK; | ||
696 | timeout = GNUNET_TIME_absolute_get_remaining (session->timeout); | ||
697 | if (0 == timeout.rel_value) | ||
698 | { | ||
699 | free_session (session); | ||
700 | return; | ||
701 | } | ||
702 | session->timeout_task = | ||
703 | GNUNET_SCHEDULER_add_delayed (timeout, &session_timeout, session); | ||
704 | } | ||
705 | |||
706 | |||
707 | /** | ||
708 | * Create a new session | ||
709 | * | ||
710 | * @param endpoint pointer to the mac endpoint of the peer | ||
711 | * @param peer peer identity to use for this session | ||
712 | * @return returns the session | ||
713 | */ | ||
714 | static struct Session * | ||
715 | create_session (struct MacEndpoint *endpoint, | ||
716 | const struct GNUNET_PeerIdentity *peer) | ||
717 | { | ||
718 | struct Session *session; | ||
719 | |||
720 | for (session = endpoint->sessions_head; NULL != session; session = session->next) | ||
721 | if (0 == memcmp (peer, &session->target, | ||
722 | sizeof (struct GNUNET_PeerIdentity))) | ||
723 | { | ||
724 | session->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); | ||
725 | return session; | ||
726 | } | ||
727 | GNUNET_STATISTICS_update (endpoint->plugin->env->stats, _("# Bluetooth sessions allocated"), 1, | ||
728 | GNUNET_NO); | ||
729 | session = GNUNET_malloc (sizeof (struct Session)); | ||
730 | GNUNET_CONTAINER_DLL_insert_tail (endpoint->sessions_head, | ||
731 | endpoint->sessions_tail, | ||
732 | session); | ||
733 | session->mac = endpoint; | ||
734 | session->target = *peer; | ||
735 | session->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); | ||
736 | session->timeout_task = | ||
737 | GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, &session_timeout, session); | ||
738 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
739 | "Created new session for peer `%s' with endpoint %s\n", | ||
740 | GNUNET_i2s (peer), | ||
741 | mac_to_string (&endpoint->addr.mac)); | ||
742 | return session; | ||
743 | } | ||
744 | |||
745 | |||
746 | /** | ||
747 | * Function called once we have successfully given the fragment | ||
748 | * message to the SUID helper process and we are thus ready for | ||
749 | * the next fragment. | ||
750 | * | ||
751 | * @param cls the 'struct FragmentMessage' | ||
752 | * @param result result of the operation (GNUNET_OK on success, GNUNET_NO if the helper died, GNUNET_SYSERR | ||
753 | * if the helper was stopped) | ||
754 | */ | ||
755 | static void | ||
756 | fragment_transmission_done (void *cls, | ||
757 | int result) | ||
758 | { | ||
759 | struct FragmentMessage *fm = cls; | ||
760 | |||
761 | |||
762 | fm->sh = NULL; | ||
763 | GNUNET_FRAGMENT_context_transmission_done (fm->fragcontext); | ||
764 | } | ||
765 | |||
766 | |||
767 | /** | ||
768 | * Transmit a fragment of a message. | ||
769 | * | ||
770 | * @param cls 'struct FragmentMessage' this fragment message belongs to | ||
771 | * @param hdr pointer to the start of the fragment message | ||
772 | */ | ||
773 | static void | ||
774 | transmit_fragment (void *cls, | ||
775 | const struct GNUNET_MessageHeader *hdr) | ||
776 | { | ||
777 | struct FragmentMessage *fm = cls; | ||
778 | struct MacEndpoint *endpoint = fm->macendpoint; | ||
779 | size_t size; | ||
780 | uint16_t msize; | ||
781 | |||
782 | msize = ntohs (hdr->size); | ||
783 | size = sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage) + msize; | ||
784 | { | ||
785 | char buf[size]; | ||
786 | struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *radio_header; | ||
787 | |||
788 | radio_header = (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *) buf; | ||
789 | get_radiotap_header (endpoint, radio_header, size); | ||
790 | get_wlan_header (endpoint->plugin, | ||
791 | &radio_header->frame, | ||
792 | &endpoint->addr.mac, | ||
793 | size); | ||
794 | memcpy (&radio_header[1], hdr, msize); | ||
795 | GNUNET_assert (NULL == fm->sh); | ||
796 | fm->sh = GNUNET_HELPER_send (endpoint->plugin->suid_helper, | ||
797 | &radio_header->header, | ||
798 | GNUNET_NO, | ||
799 | &fragment_transmission_done, fm); | ||
800 | fm->size_on_wire += size; | ||
801 | if (NULL != fm->sh) | ||
802 | GNUNET_STATISTICS_update (endpoint->plugin->env->stats, _("# Bluetooth message fragments sent"), | ||
803 | 1, GNUNET_NO); | ||
804 | else | ||
805 | GNUNET_FRAGMENT_context_transmission_done (fm->fragcontext); | ||
806 | GNUNET_STATISTICS_update (endpoint->plugin->env->stats, | ||
807 | "# bytes currently in Bluetooth buffers", | ||
808 | -msize, GNUNET_NO); | ||
809 | GNUNET_STATISTICS_update (endpoint->plugin->env->stats, | ||
810 | "# bytes transmitted via Bluetooth", | ||
811 | msize, GNUNET_NO); | ||
812 | } | ||
813 | } | ||
814 | |||
815 | |||
816 | /** | ||
817 | * Frees the space of a message in the fragment queue (send queue) | ||
818 | * | ||
819 | * @param fm message to free | ||
820 | */ | ||
821 | static void | ||
822 | free_fragment_message (struct FragmentMessage *fm) | ||
823 | { | ||
824 | struct MacEndpoint *endpoint = fm->macendpoint; | ||
825 | |||
826 | GNUNET_STATISTICS_update (endpoint->plugin->env->stats, _("# Bluetooth messages pending (with fragmentation)"), | ||
827 | -1, GNUNET_NO); | ||
828 | GNUNET_CONTAINER_DLL_remove (endpoint->sending_messages_head, | ||
829 | endpoint->sending_messages_tail, fm); | ||
830 | if (NULL != fm->sh) | ||
831 | { | ||
832 | GNUNET_HELPER_send_cancel (fm->sh); | ||
833 | fm->sh = NULL; | ||
834 | } | ||
835 | GNUNET_FRAGMENT_context_destroy (fm->fragcontext, | ||
836 | &endpoint->msg_delay, | ||
837 | &endpoint->ack_delay); | ||
838 | if (fm->timeout_task != GNUNET_SCHEDULER_NO_TASK) | ||
839 | { | ||
840 | GNUNET_SCHEDULER_cancel (fm->timeout_task); | ||
841 | fm->timeout_task = GNUNET_SCHEDULER_NO_TASK; | ||
842 | } | ||
843 | GNUNET_free (fm); | ||
844 | } | ||
845 | |||
846 | |||
847 | /** | ||
848 | * A FragmentMessage has timed out. Remove it. | ||
849 | * | ||
850 | * @param cls pointer to the 'struct FragmentMessage' | ||
851 | * @param tc pointer to the GNUNET_SCHEDULER_TaskContext | ||
852 | */ | ||
853 | static void | ||
854 | fragmentmessage_timeout (void *cls, | ||
855 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
856 | { | ||
857 | struct FragmentMessage *fm = cls; | ||
858 | |||
859 | fm->timeout_task = GNUNET_SCHEDULER_NO_TASK; | ||
860 | if (NULL != fm->cont) | ||
861 | { | ||
862 | fm->cont (fm->cont_cls, &fm->target, GNUNET_SYSERR, fm->size_payload, fm->size_on_wire); | ||
863 | fm->cont = NULL; | ||
864 | } | ||
865 | free_fragment_message (fm); | ||
866 | } | ||
867 | |||
868 | |||
869 | /** | ||
870 | * Transmit a message to the given destination with fragmentation. | ||
871 | * | ||
872 | * @param endpoint desired destination | ||
873 | * @param timeout how long can the message wait? | ||
874 | * @param target peer that should receive the message | ||
875 | * @param msg message to transmit | ||
876 | * @param payload_size bytes of payload | ||
877 | * @param cont continuation to call once the message has | ||
878 | * been transmitted (or if the transport is ready | ||
879 | * for the next transmission call; or if the | ||
880 | * peer disconnected...); can be NULL | ||
881 | * @param cont_cls closure for cont | ||
882 | */ | ||
883 | static void | ||
884 | send_with_fragmentation (struct MacEndpoint *endpoint, | ||
885 | struct GNUNET_TIME_Relative timeout, | ||
886 | const struct GNUNET_PeerIdentity *target, | ||
887 | const struct GNUNET_MessageHeader *msg, | ||
888 | size_t payload_size, | ||
889 | GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) | ||
890 | |||
891 | { | ||
892 | struct FragmentMessage *fm; | ||
893 | struct Plugin *plugin; | ||
894 | |||
895 | plugin = endpoint->plugin; | ||
896 | fm = GNUNET_malloc (sizeof (struct FragmentMessage)); | ||
897 | fm->macendpoint = endpoint; | ||
898 | fm->target = *target; | ||
899 | fm->size_payload = payload_size; | ||
900 | fm->size_on_wire = 0; | ||
901 | fm->timeout = GNUNET_TIME_relative_to_absolute (timeout); | ||
902 | fm->cont = cont; | ||
903 | fm->cont_cls = cont_cls; | ||
904 | /* 1 MBit/s typical data rate, 1430 byte fragments => ~100 ms per message */ | ||
905 | fm->fragcontext = | ||
906 | GNUNET_FRAGMENT_context_create (plugin->env->stats, WLAN_MTU, | ||
907 | &plugin->tracker, | ||
908 | endpoint->msg_delay, | ||
909 | endpoint->ack_delay, | ||
910 | msg, | ||
911 | &transmit_fragment, fm); | ||
912 | fm->timeout_task = | ||
913 | GNUNET_SCHEDULER_add_delayed (timeout, | ||
914 | &fragmentmessage_timeout, fm); | ||
915 | GNUNET_CONTAINER_DLL_insert_tail (endpoint->sending_messages_head, | ||
916 | endpoint->sending_messages_tail, | ||
917 | fm); | ||
918 | } | ||
919 | |||
920 | |||
921 | /** | ||
922 | * Free a MAC endpoint. | ||
923 | * | ||
924 | * @param endpoint pointer to the MacEndpoint to free | ||
925 | */ | ||
926 | static void | ||
927 | free_macendpoint (struct MacEndpoint *endpoint) | ||
928 | { | ||
929 | struct Plugin *plugin = endpoint->plugin; | ||
930 | struct FragmentMessage *fm; | ||
931 | struct Session *session; | ||
932 | |||
933 | GNUNET_STATISTICS_update (plugin->env->stats, | ||
934 | _("# Bluetooth MAC endpoints allocated"), -1, GNUNET_NO); | ||
935 | while (NULL != (session = endpoint->sessions_head)) | ||
936 | free_session (session); | ||
937 | while (NULL != (fm = endpoint->sending_messages_head)) | ||
938 | free_fragment_message (fm); | ||
939 | GNUNET_CONTAINER_DLL_remove (plugin->mac_head, | ||
940 | plugin->mac_tail, | ||
941 | endpoint); | ||
942 | |||
943 | if (NULL != endpoint->defrag) | ||
944 | { | ||
945 | GNUNET_DEFRAGMENT_context_destroy(endpoint->defrag); | ||
946 | endpoint->defrag = NULL; | ||
947 | } | ||
948 | |||
949 | plugin->mac_count--; | ||
950 | if (GNUNET_SCHEDULER_NO_TASK != endpoint->timeout_task) | ||
951 | { | ||
952 | GNUNET_SCHEDULER_cancel (endpoint->timeout_task); | ||
953 | endpoint->timeout_task = GNUNET_SCHEDULER_NO_TASK; | ||
954 | } | ||
955 | GNUNET_free (endpoint); | ||
956 | } | ||
957 | |||
958 | |||
959 | /** | ||
960 | * A MAC endpoint is timing out. Clean up. | ||
961 | * | ||
962 | * @param cls pointer to the MacEndpoint | ||
963 | * @param tc pointer to the GNUNET_SCHEDULER_TaskContext | ||
964 | */ | ||
965 | static void | ||
966 | macendpoint_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
967 | { | ||
968 | struct MacEndpoint *endpoint = cls; | ||
969 | struct GNUNET_TIME_Relative timeout; | ||
970 | |||
971 | endpoint->timeout_task = GNUNET_SCHEDULER_NO_TASK; | ||
972 | timeout = GNUNET_TIME_absolute_get_remaining (endpoint->timeout); | ||
973 | if (0 == timeout.rel_value) | ||
974 | { | ||
975 | free_macendpoint (endpoint); | ||
976 | return; | ||
977 | } | ||
978 | endpoint->timeout_task = | ||
979 | GNUNET_SCHEDULER_add_delayed (timeout, &macendpoint_timeout, | ||
980 | endpoint); | ||
981 | } | ||
982 | |||
983 | |||
984 | /** | ||
985 | * Find (or create) a MacEndpoint with a specific MAC address | ||
986 | * | ||
987 | * @param plugin pointer to the plugin struct | ||
988 | * @param addr the MAC address of the endpoint | ||
989 | * @return handle to our data structure for this MAC | ||
990 | */ | ||
991 | static struct MacEndpoint * | ||
992 | create_macendpoint (struct Plugin *plugin, | ||
993 | const struct WlanAddress *addr) | ||
994 | { | ||
995 | struct MacEndpoint *pos; | ||
996 | |||
997 | for (pos = plugin->mac_head; NULL != pos; pos = pos->next) | ||
998 | if (0 == memcmp (addr, &pos->addr, sizeof (struct WlanAddress))) | ||
999 | return pos; | ||
1000 | pos = GNUNET_malloc (sizeof (struct MacEndpoint)); | ||
1001 | pos->addr = *addr; | ||
1002 | pos->plugin = plugin; | ||
1003 | pos->defrag = | ||
1004 | GNUNET_DEFRAGMENT_context_create (plugin->env->stats, WLAN_MTU, | ||
1005 | MESSAGES_IN_DEFRAG_QUEUE_PER_MAC, | ||
1006 | pos, | ||
1007 | &bluetooth_data_message_handler, | ||
1008 | &send_ack); | ||
1009 | |||
1010 | pos->msg_delay = GNUNET_TIME_UNIT_MILLISECONDS; | ||
1011 | pos->ack_delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, | ||
1012 | 100); | ||
1013 | pos->timeout = GNUNET_TIME_relative_to_absolute (MACENDPOINT_TIMEOUT); | ||
1014 | pos->timeout_task = | ||
1015 | GNUNET_SCHEDULER_add_delayed (MACENDPOINT_TIMEOUT, &macendpoint_timeout, | ||
1016 | pos); | ||
1017 | GNUNET_CONTAINER_DLL_insert (plugin->mac_head, plugin->mac_tail, pos); | ||
1018 | plugin->mac_count++; | ||
1019 | GNUNET_STATISTICS_update (plugin->env->stats, _("# Bluetooth MAC endpoints allocated"), | ||
1020 | 1, GNUNET_NO); | ||
1021 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1022 | "New MAC endpoint `%s'\n", | ||
1023 | bluetooth_plugin_address_to_string(NULL, addr, sizeof (struct WlanAddress))); | ||
1024 | return pos; | ||
1025 | } | ||
1026 | |||
1027 | /** | ||
1028 | * Function obtain the network type for a session | ||
1029 | * | ||
1030 | * @param cls closure ('struct Plugin*') | ||
1031 | * @param session the session | ||
1032 | * @return the network type in HBO or GNUNET_SYSERR | ||
1033 | */ | ||
1034 | static enum GNUNET_ATS_Network_Type | ||
1035 | bluetooth_get_network (void *cls, void *session) | ||
1036 | { | ||
1037 | GNUNET_assert (NULL != session); | ||
1038 | return GNUNET_ATS_NET_BT; | ||
1039 | } | ||
1040 | |||
1041 | |||
1042 | /** | ||
1043 | * Creates a new outbound session the transport service will use to send data to the | ||
1044 | * peer | ||
1045 | * | ||
1046 | * @param cls the plugin | ||
1047 | * @param address the address | ||
1048 | * @return the session or NULL of max connections exceeded | ||
1049 | */ | ||
1050 | static struct Session * | ||
1051 | bluetooth_plugin_get_session (void *cls, | ||
1052 | const struct GNUNET_HELLO_Address *address) | ||
1053 | { | ||
1054 | struct Plugin *plugin = cls; | ||
1055 | struct MacEndpoint *endpoint; | ||
1056 | |||
1057 | if (NULL == address) | ||
1058 | return NULL; | ||
1059 | if (sizeof (struct WlanAddress) != address->address_length) | ||
1060 | { | ||
1061 | GNUNET_break (0); | ||
1062 | return NULL; | ||
1063 | } | ||
1064 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1065 | "Service asked to create session for peer `%s' with MAC `%s'\n", | ||
1066 | GNUNET_i2s (&address->peer), | ||
1067 | bluetooth_plugin_address_to_string(NULL, address->address, address->address_length)); | ||
1068 | endpoint = create_macendpoint (plugin, address->address); | ||
1069 | return create_session (endpoint, &address->peer); | ||
1070 | } | ||
1071 | |||
1072 | |||
1073 | /** | ||
1074 | * Function that can be used to force the plugin to disconnect | ||
1075 | * from the given peer and cancel all previous transmissions | ||
1076 | * (and their continuation). | ||
1077 | * | ||
1078 | * @param cls closure | ||
1079 | * @param target peer from which to disconnect | ||
1080 | */ | ||
1081 | static void | ||
1082 | bluetooth_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target) | ||
1083 | { | ||
1084 | struct Plugin *plugin = cls; | ||
1085 | struct Session *session; | ||
1086 | struct MacEndpoint *endpoint; | ||
1087 | |||
1088 | for (endpoint = plugin->mac_head; NULL != endpoint; endpoint = endpoint->next) | ||
1089 | for (session = endpoint->sessions_head; NULL != session; session = session->next) | ||
1090 | if (0 == memcmp (target, &session->target, | ||
1091 | sizeof (struct GNUNET_PeerIdentity))) | ||
1092 | { | ||
1093 | free_session (session); | ||
1094 | break; /* inner-loop only (in case peer has another MAC as well!) */ | ||
1095 | } | ||
1096 | } | ||
1097 | |||
1098 | |||
1099 | /** | ||
1100 | * Function that can be used by the transport service to transmit | ||
1101 | * a message using the plugin. Note that in the case of a | ||
1102 | * peer disconnecting, the continuation MUST be called | ||
1103 | * prior to the disconnect notification itself. This function | ||
1104 | * will be called with this peer's HELLO message to initiate | ||
1105 | * a fresh connection to another peer. | ||
1106 | * | ||
1107 | * @param cls closure | ||
1108 | * @param session which session must be used | ||
1109 | * @param msgbuf the message to transmit | ||
1110 | * @param msgbuf_size number of bytes in 'msgbuf' | ||
1111 | * @param priority how important is the message (most plugins will | ||
1112 | * ignore message priority and just FIFO) | ||
1113 | * @param to how long to wait at most for the transmission (does not | ||
1114 | * require plugins to discard the message after the timeout, | ||
1115 | * just advisory for the desired delay; most plugins will ignore | ||
1116 | * this as well) | ||
1117 | * @param cont continuation to call once the message has | ||
1118 | * been transmitted (or if the transport is ready | ||
1119 | * for the next transmission call; or if the | ||
1120 | * peer disconnected...); can be NULL | ||
1121 | * @param cont_cls closure for cont | ||
1122 | * @return number of bytes used (on the physical network, with overheads); | ||
1123 | * -1 on hard errors (i.e. address invalid); 0 is a legal value | ||
1124 | * and does NOT mean that the message was not transmitted (DV) | ||
1125 | */ | ||
1126 | static ssize_t | ||
1127 | bluetooth_plugin_send (void *cls, | ||
1128 | struct Session *session, | ||
1129 | const char *msgbuf, size_t msgbuf_size, | ||
1130 | unsigned int priority, | ||
1131 | struct GNUNET_TIME_Relative to, | ||
1132 | GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) | ||
1133 | { | ||
1134 | struct Plugin *plugin = cls; | ||
1135 | struct WlanHeader *wlanheader; | ||
1136 | size_t size = msgbuf_size + sizeof (struct WlanHeader); | ||
1137 | char buf[size] GNUNET_ALIGN; | ||
1138 | |||
1139 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1140 | "Transmitting %u bytes of payload to peer `%s' (starting with %u byte message of type %u)\n", | ||
1141 | msgbuf_size, | ||
1142 | GNUNET_i2s (&session->target), | ||
1143 | (unsigned int) ntohs (((struct GNUNET_MessageHeader*)msgbuf)->size), | ||
1144 | (unsigned int) ntohs (((struct GNUNET_MessageHeader*)msgbuf)->type)); | ||
1145 | wlanheader = (struct WlanHeader *) buf; | ||
1146 | wlanheader->header.size = htons (msgbuf_size + sizeof (struct WlanHeader)); | ||
1147 | wlanheader->header.type = htons (GNUNET_MESSAGE_TYPE_WLAN_DATA); | ||
1148 | wlanheader->sender = *plugin->env->my_identity; | ||
1149 | wlanheader->target = session->target; | ||
1150 | wlanheader->crc = htonl (GNUNET_CRYPTO_crc32_n (msgbuf, msgbuf_size)); | ||
1151 | memcpy (&wlanheader[1], msgbuf, msgbuf_size); | ||
1152 | |||
1153 | GNUNET_STATISTICS_update (plugin->env->stats, | ||
1154 | "# bytes currently in Bluetooth buffers", | ||
1155 | msgbuf_size, GNUNET_NO); | ||
1156 | |||
1157 | send_with_fragmentation (session->mac, | ||
1158 | to, | ||
1159 | &session->target, | ||
1160 | &wlanheader->header, | ||
1161 | msgbuf_size, | ||
1162 | cont, cont_cls); | ||
1163 | return size; | ||
1164 | } | ||
1165 | |||
1166 | |||
1167 | /** | ||
1168 | * We have received data from the WLAN via some session. Process depending | ||
1169 | * on the message type (HELLO, DATA, FRAGMENTATION or FRAGMENTATION-ACK). | ||
1170 | * | ||
1171 | * @param cls pointer to the plugin | ||
1172 | * @param client pointer to the session this message belongs to | ||
1173 | * @param hdr start of the message | ||
1174 | */ | ||
1175 | static int | ||
1176 | process_data (void *cls, void *client, const struct GNUNET_MessageHeader *hdr) | ||
1177 | { | ||
1178 | struct Plugin *plugin = cls; | ||
1179 | struct MacAndSession *mas = client; | ||
1180 | struct MacAndSession xmas; | ||
1181 | struct GNUNET_ATS_Information ats; | ||
1182 | struct FragmentMessage *fm; | ||
1183 | struct GNUNET_PeerIdentity tmpsource; | ||
1184 | const struct WlanHeader *wlanheader; | ||
1185 | int ret; | ||
1186 | uint16_t msize; | ||
1187 | |||
1188 | ats.type = htonl (GNUNET_ATS_NETWORK_TYPE); | ||
1189 | ats.value = htonl (GNUNET_ATS_NET_BT); | ||
1190 | msize = ntohs (hdr->size); | ||
1191 | |||
1192 | GNUNET_STATISTICS_update (plugin->env->stats, | ||
1193 | "# bytes received via Bluetooth", | ||
1194 | msize, GNUNET_NO); | ||
1195 | |||
1196 | switch (ntohs (hdr->type)) | ||
1197 | { | ||
1198 | case GNUNET_MESSAGE_TYPE_HELLO: | ||
1199 | if (GNUNET_OK != | ||
1200 | GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) hdr, &tmpsource)) | ||
1201 | { | ||
1202 | GNUNET_break_op (0); | ||
1203 | break; | ||
1204 | } | ||
1205 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1206 | "Processing %u bytes of HELLO from peer `%s' at MAC %s\n", | ||
1207 | (unsigned int) msize, | ||
1208 | GNUNET_i2s (&tmpsource), | ||
1209 | bluetooth_plugin_address_to_string (NULL, &mas->endpoint->addr, sizeof (struct WlanAddress))); | ||
1210 | |||
1211 | GNUNET_STATISTICS_update (plugin->env->stats, | ||
1212 | _("# HELLO messages received via WLAN"), 1, | ||
1213 | GNUNET_NO); | ||
1214 | plugin->env->receive (plugin->env->cls, | ||
1215 | &tmpsource, | ||
1216 | hdr, | ||
1217 | mas->session, | ||
1218 | (mas->endpoint == NULL) ? NULL : (const char *) &mas->endpoint->addr, | ||
1219 | (mas->endpoint == NULL) ? 0 : sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)); | ||
1220 | plugin->env->update_address_metrics (plugin->env->cls, | ||
1221 | &tmpsource, | ||
1222 | (mas->endpoint == NULL) ? NULL : (const char *) &mas->endpoint->addr, | ||
1223 | (mas->endpoint == NULL) ? 0 : sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress), | ||
1224 | mas->session, | ||
1225 | &ats, 1); | ||
1226 | break; | ||
1227 | case GNUNET_MESSAGE_TYPE_FRAGMENT: | ||
1228 | if (NULL == mas->endpoint) | ||
1229 | { | ||
1230 | GNUNET_break (0); | ||
1231 | break; | ||
1232 | } | ||
1233 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1234 | "Processing %u bytes of FRAGMENT from MAC %s\n", | ||
1235 | (unsigned int) msize, | ||
1236 | bluetooth_plugin_address_to_string (NULL, &mas->endpoint->addr, sizeof (struct WlanAddress))); | ||
1237 | GNUNET_STATISTICS_update (plugin->env->stats, | ||
1238 | _("# fragments received via Bluetooth"), 1, GNUNET_NO); | ||
1239 | (void) GNUNET_DEFRAGMENT_process_fragment (mas->endpoint->defrag, | ||
1240 | hdr); | ||
1241 | break; | ||
1242 | case GNUNET_MESSAGE_TYPE_FRAGMENT_ACK: | ||
1243 | if (NULL == mas->endpoint) | ||
1244 | { | ||
1245 | GNUNET_break (0); | ||
1246 | break; | ||
1247 | } | ||
1248 | GNUNET_STATISTICS_update (plugin->env->stats, _("# ACKs received via Bluetooth"), | ||
1249 | 1, GNUNET_NO); | ||
1250 | for (fm = mas->endpoint->sending_messages_head; NULL != fm; fm = fm->next) | ||
1251 | { | ||
1252 | ret = GNUNET_FRAGMENT_process_ack (fm->fragcontext, hdr); | ||
1253 | if (GNUNET_OK == ret) | ||
1254 | { | ||
1255 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1256 | "Got last ACK, finished message transmission to `%s' (%p)\n", | ||
1257 | bluetooth_plugin_address_to_string (NULL, &mas->endpoint->addr, sizeof (struct WlanAddress)), | ||
1258 | fm); | ||
1259 | mas->endpoint->timeout = GNUNET_TIME_relative_to_absolute (MACENDPOINT_TIMEOUT); | ||
1260 | if (NULL != fm->cont) | ||
1261 | { | ||
1262 | fm->cont (fm->cont_cls, &fm->target, GNUNET_OK, fm->size_payload, fm->size_on_wire); | ||
1263 | fm->cont = NULL; | ||
1264 | } | ||
1265 | free_fragment_message (fm); | ||
1266 | break; | ||
1267 | } | ||
1268 | if (GNUNET_NO == ret) | ||
1269 | { | ||
1270 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1271 | "Got an ACK, message transmission to `%s' not yet finished\n", | ||
1272 | bluetooth_plugin_address_to_string (NULL, &mas->endpoint->addr, sizeof (struct WlanAddress))); | ||
1273 | break; | ||
1274 | } | ||
1275 | } | ||
1276 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1277 | "ACK not matched against any active fragmentation with MAC `%s'\n", | ||
1278 | bluetooth_plugin_address_to_string (NULL, &mas->endpoint->addr, sizeof (struct WlanAddress))); | ||
1279 | break; | ||
1280 | case GNUNET_MESSAGE_TYPE_WLAN_DATA: | ||
1281 | if (NULL == mas->endpoint) | ||
1282 | { | ||
1283 | GNUNET_break (0); | ||
1284 | break; | ||
1285 | } | ||
1286 | if (msize < sizeof (struct WlanHeader)) | ||
1287 | { | ||
1288 | GNUNET_break (0); | ||
1289 | break; | ||
1290 | } | ||
1291 | wlanheader = (const struct WlanHeader *) hdr; | ||
1292 | if (0 != memcmp (&wlanheader->target, | ||
1293 | plugin->env->my_identity, | ||
1294 | sizeof (struct GNUNET_PeerIdentity))) | ||
1295 | { | ||
1296 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1297 | "Bluetooth data for `%s', not for me, ignoring\n", | ||
1298 | GNUNET_i2s (&wlanheader->target)); | ||
1299 | break; | ||
1300 | } | ||
1301 | if (ntohl (wlanheader->crc) != | ||
1302 | GNUNET_CRYPTO_crc32_n (&wlanheader[1], msize - sizeof (struct WlanHeader))) | ||
1303 | { | ||
1304 | GNUNET_STATISTICS_update (plugin->env->stats, | ||
1305 | _("# BluetoothDATA messages discarded due to CRC32 error"), 1, | ||
1306 | GNUNET_NO); | ||
1307 | break; | ||
1308 | } | ||
1309 | xmas.endpoint = mas->endpoint; | ||
1310 | xmas.session = create_session (mas->endpoint, &wlanheader->sender); | ||
1311 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1312 | "Processing %u bytes of WLAN DATA from peer `%s'\n", | ||
1313 | (unsigned int) msize, | ||
1314 | GNUNET_i2s (&wlanheader->sender)); | ||
1315 | (void) GNUNET_SERVER_mst_receive (plugin->wlan_header_payload_tokenizer, | ||
1316 | &xmas, | ||
1317 | (const char *) &wlanheader[1], | ||
1318 | msize - sizeof (struct WlanHeader), | ||
1319 | GNUNET_YES, GNUNET_NO); | ||
1320 | break; | ||
1321 | default: | ||
1322 | if (NULL == mas->endpoint) | ||
1323 | { | ||
1324 | GNUNET_break (0); | ||
1325 | break; | ||
1326 | } | ||
1327 | if (NULL == mas->session) | ||
1328 | { | ||
1329 | GNUNET_break (0); | ||
1330 | break; | ||
1331 | } | ||
1332 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1333 | "Received packet with %u bytes of type %u from peer %s\n", | ||
1334 | (unsigned int) msize, | ||
1335 | (unsigned int) ntohs (hdr->type), | ||
1336 | GNUNET_i2s (&mas->session->target)); | ||
1337 | plugin->env->receive (plugin->env->cls, | ||
1338 | &mas->session->target, | ||
1339 | hdr, | ||
1340 | mas->session, | ||
1341 | (mas->endpoint == NULL) ? NULL : (const char *) &mas->endpoint->addr, | ||
1342 | (mas->endpoint == NULL) ? 0 : sizeof (struct WlanAddress)); | ||
1343 | plugin->env->update_address_metrics (plugin->env->cls, | ||
1344 | &mas->session->target, | ||
1345 | (mas->endpoint == NULL) ? NULL : (const char *) &mas->endpoint->addr, | ||
1346 | (mas->endpoint == NULL) ? 0 : sizeof (struct WlanAddress), | ||
1347 | mas->session, | ||
1348 | &ats, 1); | ||
1349 | break; | ||
1350 | } | ||
1351 | return GNUNET_OK; | ||
1352 | } | ||
1353 | |||
1354 | |||
1355 | /** | ||
1356 | * Function used for to process the data from the suid process | ||
1357 | * | ||
1358 | * @param cls the plugin handle | ||
1359 | * @param client client that send the data (not used) | ||
1360 | * @param hdr header of the GNUNET_MessageHeader | ||
1361 | */ | ||
1362 | static int | ||
1363 | handle_helper_message (void *cls, void *client, | ||
1364 | const struct GNUNET_MessageHeader *hdr) | ||
1365 | { | ||
1366 | struct Plugin *plugin = cls; | ||
1367 | const struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *rxinfo; | ||
1368 | const struct GNUNET_TRANSPORT_WLAN_HelperControlMessage *cm; | ||
1369 | struct WlanAddress wa; | ||
1370 | struct MacAndSession mas; | ||
1371 | uint16_t msize; | ||
1372 | |||
1373 | msize = ntohs (hdr->size); | ||
1374 | switch (ntohs (hdr->type)) | ||
1375 | { | ||
1376 | case GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL: | ||
1377 | if (msize != sizeof (struct GNUNET_TRANSPORT_WLAN_HelperControlMessage)) | ||
1378 | { | ||
1379 | GNUNET_break (0); | ||
1380 | break; | ||
1381 | } | ||
1382 | cm = (const struct GNUNET_TRANSPORT_WLAN_HelperControlMessage *) hdr; | ||
1383 | if (GNUNET_YES == plugin->have_mac) | ||
1384 | { | ||
1385 | if (0 == memcmp (&plugin->mac_address, | ||
1386 | &cm->mac, | ||
1387 | sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress))) | ||
1388 | break; /* no change */ | ||
1389 | /* remove old address */ | ||
1390 | memset (&wa, 0, sizeof (struct WlanAddress)); | ||
1391 | wa.mac = plugin->mac_address; | ||
1392 | wa.options = htonl(plugin->options); | ||
1393 | plugin->env->notify_address (plugin->env->cls, GNUNET_NO, | ||
1394 | &wa, | ||
1395 | sizeof (wa), | ||
1396 | "wlan"); | ||
1397 | } | ||
1398 | plugin->mac_address = cm->mac; | ||
1399 | plugin->have_mac = GNUNET_YES; | ||
1400 | memset (&wa, 0, sizeof (struct WlanAddress)); | ||
1401 | wa.mac = plugin->mac_address; | ||
1402 | wa.options = htonl(plugin->options); | ||
1403 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1404 | "Received WLAN_HELPER_CONTROL message with MAC address `%s' for peer `%s'\n", | ||
1405 | mac_to_string (&cm->mac), | ||
1406 | GNUNET_i2s (plugin->env->my_identity)); | ||
1407 | plugin->env->notify_address (plugin->env->cls, GNUNET_YES, | ||
1408 | &wa, | ||
1409 | sizeof (struct WlanAddress), | ||
1410 | "wlan"); | ||
1411 | break; | ||
1412 | case GNUNET_MESSAGE_TYPE_WLAN_DATA_FROM_HELPER: | ||
1413 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1414 | "Got data message from helper with %u bytes\n", | ||
1415 | msize); | ||
1416 | GNUNET_STATISTICS_update (plugin->env->stats, | ||
1417 | _("# DATA messages received via Bluetooth"), 1, | ||
1418 | GNUNET_NO); | ||
1419 | if (msize < sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)) | ||
1420 | { | ||
1421 | GNUNET_break (0); | ||
1422 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1423 | "Size of packet is too small (%u bytes)\n", | ||
1424 | msize); | ||
1425 | break; | ||
1426 | } | ||
1427 | rxinfo = (const struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *) hdr; | ||
1428 | |||
1429 | /* check if message is actually for us */ | ||
1430 | if (0 != memcmp (&rxinfo->frame.addr3, &mac_bssid_gnunet, | ||
1431 | sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress))) | ||
1432 | { | ||
1433 | /* Not the GNUnet BSSID */ | ||
1434 | break; | ||
1435 | } | ||
1436 | if ( (0 != memcmp (&rxinfo->frame.addr1, &bc_all_mac, | ||
1437 | sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress))) && | ||
1438 | (0 != memcmp (&rxinfo->frame.addr1, &plugin->mac_address, | ||
1439 | sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress))) ) | ||
1440 | { | ||
1441 | /* Neither broadcast nor specifically for us */ | ||
1442 | break; | ||
1443 | } | ||
1444 | if (0 == memcmp (&rxinfo->frame.addr2, &plugin->mac_address, | ||
1445 | sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress))) | ||
1446 | { | ||
1447 | /* packet is FROM us, thus not FOR us */ | ||
1448 | break; | ||
1449 | } | ||
1450 | |||
1451 | GNUNET_STATISTICS_update (plugin->env->stats, | ||
1452 | _("# Bluetooth DATA messages processed"), | ||
1453 | 1, GNUNET_NO); | ||
1454 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1455 | "Receiving %u bytes of data from MAC `%s'\n", | ||
1456 | (unsigned int) (msize - sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)), | ||
1457 | mac_to_string (&rxinfo->frame.addr2)); | ||
1458 | wa.mac = rxinfo->frame.addr2; | ||
1459 | wa.options = htonl (0); | ||
1460 | mas.endpoint = create_macendpoint (plugin, &wa); | ||
1461 | mas.session = NULL; | ||
1462 | (void) GNUNET_SERVER_mst_receive (plugin->helper_payload_tokenizer, | ||
1463 | &mas, | ||
1464 | (const char*) &rxinfo[1], | ||
1465 | msize - sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage), | ||
1466 | GNUNET_YES, GNUNET_NO); | ||
1467 | break; | ||
1468 | default: | ||
1469 | GNUNET_break (0); | ||
1470 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1471 | "Unexpected message of type %u (%u bytes)", | ||
1472 | ntohs (hdr->type), ntohs (hdr->size)); | ||
1473 | break; | ||
1474 | } | ||
1475 | return GNUNET_OK; | ||
1476 | } | ||
1477 | |||
1478 | |||
1479 | |||
1480 | /** | ||
1481 | * Task to (periodically) send a HELLO beacon | ||
1482 | * | ||
1483 | * @param cls pointer to the plugin struct | ||
1484 | * @param tc scheduler context | ||
1485 | */ | ||
1486 | static void | ||
1487 | send_hello_beacon (void *cls, | ||
1488 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
1489 | { | ||
1490 | struct Plugin *plugin = cls; | ||
1491 | uint16_t size; | ||
1492 | uint16_t hello_size; | ||
1493 | struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *radioHeader; | ||
1494 | const struct GNUNET_MessageHeader *hello; | ||
1495 | |||
1496 | hello = plugin->env->get_our_hello (); | ||
1497 | hello_size = GNUNET_HELLO_size ((struct GNUNET_HELLO_Message *) hello); | ||
1498 | GNUNET_assert (sizeof (struct WlanHeader) + hello_size <= WLAN_MTU); | ||
1499 | size = sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage) + hello_size; | ||
1500 | { | ||
1501 | char buf[size] GNUNET_ALIGN; | ||
1502 | |||
1503 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1504 | "Sending %u byte HELLO beacon\n", | ||
1505 | (unsigned int) size); | ||
1506 | radioHeader = (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage*) buf; | ||
1507 | get_radiotap_header (NULL, radioHeader, size); | ||
1508 | get_wlan_header (plugin, &radioHeader->frame, &bc_all_mac, size); | ||
1509 | memcpy (&radioHeader[1], hello, hello_size); | ||
1510 | if (NULL != | ||
1511 | GNUNET_HELPER_send (plugin->suid_helper, | ||
1512 | &radioHeader->header, | ||
1513 | GNUNET_YES /* can drop */, | ||
1514 | NULL, NULL)) | ||
1515 | GNUNET_STATISTICS_update (plugin->env->stats, _("# HELLO beacons sent via Bluetooth"), | ||
1516 | 1, GNUNET_NO); | ||
1517 | } | ||
1518 | plugin->beacon_task = | ||
1519 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
1520 | (HELLO_BEACON_SCALING_FACTOR, | ||
1521 | plugin->mac_count + 1), | ||
1522 | &send_hello_beacon, | ||
1523 | plugin); | ||
1524 | |||
1525 | } | ||
1526 | |||
1527 | |||
1528 | /** | ||
1529 | * Another peer has suggested an address for this | ||
1530 | * peer and transport plugin. Check that this could be a valid | ||
1531 | * address. If so, consider adding it to the list | ||
1532 | * of addresses. | ||
1533 | * | ||
1534 | * @param cls closure | ||
1535 | * @param addr pointer to the address | ||
1536 | * @param addrlen length of addr | ||
1537 | * @return GNUNET_OK if this is a plausible address for this peer | ||
1538 | * and transport | ||
1539 | */ | ||
1540 | static int | ||
1541 | bluetooth_plugin_address_suggested (void *cls, const void *addr, size_t addrlen) | ||
1542 | { | ||
1543 | struct Plugin *plugin = cls; | ||
1544 | struct WlanAddress *wa = (struct WlanAddress *) addr; | ||
1545 | |||
1546 | if (addrlen != sizeof (struct WlanAddress)) | ||
1547 | { | ||
1548 | GNUNET_break_op (0); | ||
1549 | return GNUNET_SYSERR; | ||
1550 | } | ||
1551 | if (GNUNET_YES != plugin->have_mac) | ||
1552 | { | ||
1553 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1554 | "Rejecting MAC `%s': I don't know my MAC!\n", | ||
1555 | mac_to_string (addr)); | ||
1556 | return GNUNET_NO; /* don't know my MAC */ | ||
1557 | } | ||
1558 | if (0 != memcmp (&wa->mac, | ||
1559 | &plugin->mac_address, | ||
1560 | sizeof (wa->mac))) | ||
1561 | { | ||
1562 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1563 | "Rejecting MAC `%s': not my MAC!\n", | ||
1564 | mac_to_string (addr)); | ||
1565 | return GNUNET_NO; /* not my MAC */ | ||
1566 | } | ||
1567 | return GNUNET_OK; | ||
1568 | } | ||
1569 | |||
1570 | |||
1571 | /** | ||
1572 | * Function called for a quick conversion of the binary address to | ||
1573 | * a numeric address. Note that the caller must not free the | ||
1574 | * address and that the next call to this function is allowed | ||
1575 | * to override the address again. | ||
1576 | * | ||
1577 | * @param cls closure | ||
1578 | * @param addr binary address | ||
1579 | * @param addrlen length of the address | ||
1580 | * @return string representing the same address | ||
1581 | */ | ||
1582 | static const char * | ||
1583 | bluetooth_plugin_address_to_string (void *cls, const void *addr, size_t addrlen) | ||
1584 | { | ||
1585 | const struct GNUNET_TRANSPORT_WLAN_MacAddress *mac; | ||
1586 | static char macstr[36]; | ||
1587 | |||
1588 | if (sizeof (struct WlanAddress) != addrlen) | ||
1589 | { | ||
1590 | GNUNET_break (0); | ||
1591 | return NULL; | ||
1592 | } | ||
1593 | mac = &((struct WlanAddress *) addr)->mac; | ||
1594 | GNUNET_snprintf (macstr, sizeof (macstr), "%s.%u.%s", | ||
1595 | PLUGIN_NAME, ntohl (((struct WlanAddress *) addr)->options), | ||
1596 | mac_to_string (mac)); | ||
1597 | return macstr; | ||
1598 | } | ||
1599 | |||
1600 | |||
1601 | /** | ||
1602 | * Convert the transports address to a nice, human-readable format. | ||
1603 | * | ||
1604 | * @param cls closure | ||
1605 | * @param type name of the transport that generated the address | ||
1606 | * @param addr one of the addresses of the host, NULL for the last address | ||
1607 | * the specific address format depends on the transport | ||
1608 | * @param addrlen length of the address | ||
1609 | * @param numeric should (IP) addresses be displayed in numeric form? | ||
1610 | * @param timeout after how long should we give up? | ||
1611 | * @param asc function to call on each string | ||
1612 | * @param asc_cls closure for asc | ||
1613 | */ | ||
1614 | static void | ||
1615 | bluetooth_plugin_address_pretty_printer (void *cls, const char *type, | ||
1616 | const void *addr, size_t addrlen, | ||
1617 | int numeric, | ||
1618 | struct GNUNET_TIME_Relative timeout, | ||
1619 | GNUNET_TRANSPORT_AddressStringCallback asc, | ||
1620 | void *asc_cls) | ||
1621 | { | ||
1622 | char *ret; | ||
1623 | |||
1624 | if (sizeof (struct WlanAddress) != addrlen) | ||
1625 | { | ||
1626 | /* invalid address */ | ||
1627 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
1628 | _("Bluetooth address with invalid size encountered\n")); | ||
1629 | asc (asc_cls, NULL); | ||
1630 | return; | ||
1631 | } | ||
1632 | ret = GNUNET_strdup (bluetooth_plugin_address_to_string(NULL, addr, addrlen)); | ||
1633 | asc (asc_cls, ret); | ||
1634 | GNUNET_free (ret); | ||
1635 | asc (asc_cls, NULL); | ||
1636 | } | ||
1637 | |||
1638 | |||
1639 | /** | ||
1640 | * Exit point from the plugin. | ||
1641 | * | ||
1642 | * @param cls pointer to the api struct | ||
1643 | */ | ||
1644 | void * | ||
1645 | libgnunet_plugin_transport_bluetooth_done (void *cls) | ||
1646 | { | ||
1647 | struct WlanAddress wa; | ||
1648 | struct GNUNET_TRANSPORT_PluginFunctions *api = cls; | ||
1649 | struct Plugin *plugin = api->cls; | ||
1650 | struct MacEndpoint *endpoint; | ||
1651 | struct MacEndpoint *endpoint_next; | ||
1652 | |||
1653 | if (NULL == plugin) | ||
1654 | { | ||
1655 | GNUNET_free (api); | ||
1656 | return NULL; | ||
1657 | } | ||
1658 | |||
1659 | if (GNUNET_YES == plugin->have_mac) | ||
1660 | { | ||
1661 | memset (&wa, 0, sizeof (wa)); | ||
1662 | wa.options = htonl (plugin->options); | ||
1663 | wa.mac = plugin->mac_address; | ||
1664 | plugin->env->notify_address (plugin->env->cls, GNUNET_NO, | ||
1665 | &wa, | ||
1666 | sizeof (struct WlanAddress), | ||
1667 | "wlan"); | ||
1668 | plugin->have_mac = GNUNET_NO; | ||
1669 | } | ||
1670 | |||
1671 | if (GNUNET_SCHEDULER_NO_TASK != plugin->beacon_task) | ||
1672 | { | ||
1673 | GNUNET_SCHEDULER_cancel (plugin->beacon_task); | ||
1674 | plugin->beacon_task = GNUNET_SCHEDULER_NO_TASK; | ||
1675 | } | ||
1676 | if (NULL != plugin->suid_helper) | ||
1677 | { | ||
1678 | GNUNET_HELPER_stop (plugin->suid_helper, GNUNET_NO); | ||
1679 | plugin->suid_helper = NULL; | ||
1680 | } | ||
1681 | endpoint_next = plugin->mac_head; | ||
1682 | while (NULL != (endpoint = endpoint_next)) | ||
1683 | { | ||
1684 | endpoint_next = endpoint->next; | ||
1685 | free_macendpoint (endpoint); | ||
1686 | } | ||
1687 | if (NULL != plugin->fragment_data_tokenizer) | ||
1688 | { | ||
1689 | GNUNET_SERVER_mst_destroy (plugin->fragment_data_tokenizer); | ||
1690 | plugin->fragment_data_tokenizer = NULL; | ||
1691 | } | ||
1692 | if (NULL != plugin->wlan_header_payload_tokenizer) | ||
1693 | { | ||
1694 | GNUNET_SERVER_mst_destroy (plugin->wlan_header_payload_tokenizer); | ||
1695 | plugin->wlan_header_payload_tokenizer = NULL; | ||
1696 | } | ||
1697 | if (NULL != plugin->helper_payload_tokenizer) | ||
1698 | { | ||
1699 | GNUNET_SERVER_mst_destroy (plugin->helper_payload_tokenizer); | ||
1700 | plugin->helper_payload_tokenizer = NULL; | ||
1701 | } | ||
1702 | GNUNET_free_non_null (plugin->interface); | ||
1703 | GNUNET_free (plugin); | ||
1704 | GNUNET_free (api); | ||
1705 | return NULL; | ||
1706 | } | ||
1707 | |||
1708 | |||
1709 | /** | ||
1710 | * Function called to convert a string address to | ||
1711 | * a binary address. | ||
1712 | * | ||
1713 | * @param cls closure ('struct Plugin*') | ||
1714 | * @param addr string address | ||
1715 | * @param addrlen length of the address | ||
1716 | * @param buf location to store the buffer | ||
1717 | * @param added location to store the number of bytes in the buffer. | ||
1718 | * If the function returns GNUNET_SYSERR, its contents are undefined. | ||
1719 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
1720 | */ | ||
1721 | static int | ||
1722 | bluetooth_string_to_address (void *cls, const char *addr, uint16_t addrlen, | ||
1723 | void **buf, size_t *added) | ||
1724 | { | ||
1725 | struct WlanAddress *wa; | ||
1726 | unsigned int a[6]; | ||
1727 | unsigned int i; | ||
1728 | char plugin[5]; | ||
1729 | uint32_t options; | ||
1730 | |||
1731 | if ((NULL == addr) || (addrlen == 0)) | ||
1732 | { | ||
1733 | GNUNET_break (0); | ||
1734 | return GNUNET_SYSERR; | ||
1735 | } | ||
1736 | if ('\0' != addr[addrlen - 1]) | ||
1737 | { | ||
1738 | GNUNET_break (0); | ||
1739 | return GNUNET_SYSERR; | ||
1740 | } | ||
1741 | if (strlen (addr) != addrlen - 1) | ||
1742 | { | ||
1743 | GNUNET_break (0); | ||
1744 | return GNUNET_SYSERR; | ||
1745 | } | ||
1746 | |||
1747 | if (8 != SSCANF (addr, | ||
1748 | "%4s.%u.%X:%X:%X:%X:%X:%X", | ||
1749 | plugin, &options, | ||
1750 | &a[0], &a[1], &a[2], &a[3], &a[4], &a[5])) | ||
1751 | { | ||
1752 | GNUNET_break (0); | ||
1753 | return GNUNET_SYSERR; | ||
1754 | } | ||
1755 | wa = GNUNET_malloc (sizeof (struct WlanAddress)); | ||
1756 | for (i=0;i<6;i++) | ||
1757 | wa->mac.mac[i] = a[i]; | ||
1758 | wa->options = htonl (0); | ||
1759 | *buf = wa; | ||
1760 | *added = sizeof (struct WlanAddress); | ||
1761 | return GNUNET_OK; | ||
1762 | } | ||
1763 | |||
1764 | |||
1765 | /** | ||
1766 | * Entry point for the plugin. | ||
1767 | * | ||
1768 | * @param cls closure, the 'struct GNUNET_TRANSPORT_PluginEnvironment*' | ||
1769 | * @return the 'struct GNUNET_TRANSPORT_PluginFunctions*' or NULL on error | ||
1770 | */ | ||
1771 | void * | ||
1772 | libgnunet_plugin_transport_bluetooth_init (void *cls) | ||
1773 | { | ||
1774 | struct GNUNET_TRANSPORT_PluginEnvironment *env = cls; | ||
1775 | struct GNUNET_TRANSPORT_PluginFunctions *api; | ||
1776 | struct Plugin *plugin; | ||
1777 | char *interface; | ||
1778 | unsigned long long testmode; | ||
1779 | char *binary; | ||
1780 | |||
1781 | /* check for 'special' mode */ | ||
1782 | if (NULL == env->receive) | ||
1783 | { | ||
1784 | /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully | ||
1785 | initialze the plugin or the API */ | ||
1786 | api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); | ||
1787 | api->cls = NULL; | ||
1788 | api->address_pretty_printer = &bluetooth_plugin_address_pretty_printer; | ||
1789 | api->address_to_string = &bluetooth_plugin_address_to_string; | ||
1790 | api->string_to_address = &bluetooth_string_to_address; | ||
1791 | return api; | ||
1792 | } | ||
1793 | |||
1794 | testmode = 0; | ||
1795 | /* check configuration */ | ||
1796 | if ( (GNUNET_YES == | ||
1797 | GNUNET_CONFIGURATION_have_value (env->cfg, "transport-bluetooth", "TESTMODE")) && | ||
1798 | ( (GNUNET_SYSERR == | ||
1799 | GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-bluetooth", | ||
1800 | "TESTMODE", &testmode)) || | ||
1801 | (testmode > 2) ) ) | ||
1802 | { | ||
1803 | GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, | ||
1804 | "transport-wlan", "TESTMODE"); | ||
1805 | return NULL; | ||
1806 | } | ||
1807 | binary = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-transport-bluetooth"); | ||
1808 | if ( (0 == testmode) && | ||
1809 | (GNUNET_YES != GNUNET_OS_check_helper_binary (binary, GNUNET_YES, NULL)) ) | ||
1810 | { | ||
1811 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1812 | _("Helper binary `%s' not SUID, cannot run WLAN transport\n"), | ||
1813 | "gnunet-helper-transport-bluetooth"); | ||
1814 | GNUNET_free (binary); | ||
1815 | return NULL; | ||
1816 | } | ||
1817 | GNUNET_free (binary); | ||
1818 | if (GNUNET_YES != | ||
1819 | GNUNET_CONFIGURATION_get_value_string | ||
1820 | (env->cfg, "transport-bluetooth", "INTERFACE", | ||
1821 | &interface)) | ||
1822 | { | ||
1823 | GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, | ||
1824 | "transport-bluetooth", "INTERFACE"); | ||
1825 | return NULL; | ||
1826 | } | ||
1827 | |||
1828 | plugin = GNUNET_malloc (sizeof (struct Plugin)); | ||
1829 | plugin->interface = interface; | ||
1830 | plugin->env = env; | ||
1831 | GNUNET_STATISTICS_set (plugin->env->stats, _("# Bluetooth sessions allocated"), | ||
1832 | 0, GNUNET_NO); | ||
1833 | GNUNET_STATISTICS_set (plugin->env->stats, _("# Bluetooth MAC endpoints allocated"), | ||
1834 | 0, 0); | ||
1835 | GNUNET_BANDWIDTH_tracker_init (&plugin->tracker, | ||
1836 | GNUNET_BANDWIDTH_value_init (100 * 1024 * | ||
1837 | 1024 / 8), 100); | ||
1838 | plugin->fragment_data_tokenizer = GNUNET_SERVER_mst_create (&process_data, plugin); | ||
1839 | plugin->wlan_header_payload_tokenizer = GNUNET_SERVER_mst_create (&process_data, plugin); | ||
1840 | plugin->helper_payload_tokenizer = GNUNET_SERVER_mst_create (&process_data, plugin); | ||
1841 | plugin->beacon_task = GNUNET_SCHEDULER_add_now (&send_hello_beacon, | ||
1842 | plugin); | ||
1843 | |||
1844 | plugin->options = 0; | ||
1845 | |||
1846 | /* some compilers do not like switch on 'long long'... */ | ||
1847 | switch ((unsigned int) testmode) | ||
1848 | { | ||
1849 | case 0: /* normal */ | ||
1850 | plugin->helper_argv[0] = (char *) "gnunet-helper-transport-bluetooth"; | ||
1851 | plugin->helper_argv[1] = interface; | ||
1852 | plugin->helper_argv[2] = NULL; | ||
1853 | plugin->suid_helper = GNUNET_HELPER_start (GNUNET_NO, | ||
1854 | "gnunet-helper-transport-bluetooth", | ||
1855 | plugin->helper_argv, | ||
1856 | &handle_helper_message, | ||
1857 | NULL, | ||
1858 | plugin); | ||
1859 | break; | ||
1860 | default: | ||
1861 | GNUNET_assert (0); | ||
1862 | } | ||
1863 | |||
1864 | api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); | ||
1865 | api->cls = plugin; | ||
1866 | api->send = &bluetooth_plugin_send; | ||
1867 | api->get_session = &bluetooth_plugin_get_session; | ||
1868 | api->disconnect = &bluetooth_plugin_disconnect; | ||
1869 | api->address_pretty_printer = &bluetooth_plugin_address_pretty_printer; | ||
1870 | api->check_address = &bluetooth_plugin_address_suggested; | ||
1871 | api->address_to_string = &bluetooth_plugin_address_to_string;; | ||
1872 | api->string_to_address = &bluetooth_string_to_address; | ||
1873 | api->get_network = &bluetooth_get_network; | ||
1874 | |||
1875 | return api; | ||
1876 | } | ||
1877 | |||
1878 | |||
1879 | /* end of plugin_transport_bluetooth.c */ | ||