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