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