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