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