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