-add missing calls to monitor
[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   notify_session_monitor (plugin,
735                           session,
736                           GNUNET_TRANSPORT_SS_DOWN);
737   GNUNET_CONTAINER_DLL_remove (endpoint->sessions_head,
738                                endpoint->sessions_tail,
739                                session);
740   if (session->timeout_task != GNUNET_SCHEDULER_NO_TASK)
741   {
742     GNUNET_SCHEDULER_cancel (session->timeout_task);
743     session->timeout_task = GNUNET_SCHEDULER_NO_TASK;
744   }
745   GNUNET_STATISTICS_update (plugin->env->stats,
746                             _("# WLAN sessions allocated"),
747                             -1,
748                             GNUNET_NO);
749   GNUNET_HELLO_address_free (session->address);
750   GNUNET_free (session);
751   return GNUNET_OK;
752 }
753
754
755 /**
756  * Function that is called to get the keepalive factor.
757  * #GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT is divided by this number to
758  * calculate the interval between keepalive packets.
759  *
760  * @param cls closure with the `struct Plugin`
761  * @return keepalive factor
762  */
763 static unsigned int
764 wlan_plugin_query_keepalive_factor (void *cls)
765 {
766   return 3;
767 }
768
769
770 /**
771  * A session is timing out.  Clean up.
772  *
773  * @param cls pointer to the Session
774  * @param tc pointer to the GNUNET_SCHEDULER_TaskContext
775  */
776 static void
777 session_timeout (void *cls,
778                  const struct GNUNET_SCHEDULER_TaskContext *tc)
779 {
780   struct Session *session = cls;
781   struct GNUNET_TIME_Relative left;
782
783   session->timeout_task = GNUNET_SCHEDULER_NO_TASK;
784   left = GNUNET_TIME_absolute_get_remaining (session->timeout);
785   if (0 != left.rel_value_us)
786   {
787     session->timeout_task =
788       GNUNET_SCHEDULER_add_delayed (left,
789                                     &session_timeout,
790                                     session);
791     return;
792   }
793   wlan_plugin_disconnect_session (session->mac->plugin,
794                                   session);
795 }
796
797
798
799 /**
800  * Lookup a new session
801  *
802  * @param endpoint pointer to the mac endpoint of the peer
803  * @param peer peer identity to use for this session
804  * @return returns the session or NULL
805  */
806 static struct Session *
807 lookup_session (struct MacEndpoint *endpoint,
808                 const struct GNUNET_PeerIdentity *peer)
809 {
810   struct Session *session;
811
812   for (session = endpoint->sessions_head; NULL != session; session = session->next)
813     if (0 == memcmp (peer, &session->target, sizeof (struct GNUNET_PeerIdentity)))
814       return session;
815   return NULL;
816 }
817
818
819 /**
820  * Create a new session
821  *
822  * @param endpoint pointer to the mac endpoint of the peer
823  * @param peer peer identity to use for this session
824  * @return returns the session or NULL
825  */
826 static struct Session *
827 create_session (struct MacEndpoint *endpoint,
828                 const struct GNUNET_PeerIdentity *peer)
829 {
830   struct Session *session;
831
832   GNUNET_STATISTICS_update (endpoint->plugin->env->stats,
833                             _("# WLAN sessions allocated"),
834                             1,
835                             GNUNET_NO);
836   session = GNUNET_new (struct Session);
837   GNUNET_CONTAINER_DLL_insert_tail (endpoint->sessions_head,
838                                     endpoint->sessions_tail,
839                                     session);
840   session->address = GNUNET_HELLO_address_allocate (peer,
841                                                     PLUGIN_NAME,
842                                                     &endpoint->wlan_addr,
843                                                     sizeof (endpoint->wlan_addr),
844                                                     GNUNET_HELLO_ADDRESS_INFO_NONE);
845   session->mac = endpoint;
846   session->target = *peer;
847   session->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
848   session->timeout_task =
849       GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, &session_timeout,
850                                     session);
851   notify_session_monitor (plugin,
852                           session,
853                           GNUNET_TRANSPORT_SS_UP);
854   LOG (GNUNET_ERROR_TYPE_DEBUG,
855        "Created new session %p for peer `%s' with endpoint %s\n",
856        session,
857        GNUNET_i2s (peer),
858        mac_to_string (&endpoint->wlan_addr.mac));
859
860   return session;
861 }
862
863
864 /**
865  * Look up a session for a peer and create a new session if none is found
866  *
867  * @param endpoint pointer to the mac endpoint of the peer
868  * @param peer peer identity to use for this session
869  * @return returns the session
870  */
871 static struct Session *
872 get_session (struct MacEndpoint *endpoint,
873              const struct GNUNET_PeerIdentity *peer)
874 {
875   struct Session *session;
876
877   if (NULL != (session = lookup_session (endpoint, peer)))
878     return session;
879   return create_session (endpoint, peer);
880 }
881
882
883 /**
884  * Function called once we have successfully given the fragment
885  * message to the SUID helper process and we are thus ready for
886  * the next fragment.
887  *
888  * @param cls the `struct FragmentMessage *`
889  * @param result result of the operation (#GNUNET_OK on success,
890  *        #GNUNET_NO if the helper died, #GNUNET_SYSERR
891  *        if the helper was stopped)
892  */
893 static void
894 fragment_transmission_done (void *cls,
895                             int result)
896 {
897   struct FragmentMessage *fm = cls;
898
899
900   fm->sh = NULL;
901   GNUNET_FRAGMENT_context_transmission_done (fm->fragcontext);
902 }
903
904
905 /**
906  * Transmit a fragment of a message.
907  *
908  * @param cls `struct FragmentMessage *` this fragment message belongs to
909  * @param hdr pointer to the start of the fragment message
910  */
911 static void
912 transmit_fragment (void *cls,
913                    const struct GNUNET_MessageHeader *hdr)
914 {
915   struct FragmentMessage *fm = cls;
916   struct MacEndpoint *endpoint = fm->macendpoint;
917   size_t size;
918   uint16_t msize;
919
920   if (NULL == endpoint)
921   {
922         GNUNET_break (0);
923         return;
924   }
925
926   msize = ntohs (hdr->size);
927   size = sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage) + msize;
928   {
929     char buf[size];
930     struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *radio_header;
931
932     radio_header = (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *) buf;
933     get_radiotap_header (endpoint, radio_header, size);
934     get_wlan_header (endpoint->plugin,
935                      &radio_header->frame,
936                      &endpoint->wlan_addr.mac,
937                      sizeof (endpoint->wlan_addr.mac));
938     memcpy (&radio_header[1], hdr, msize);
939     GNUNET_assert (NULL == fm->sh);
940     fm->sh = GNUNET_HELPER_send (endpoint->plugin->suid_helper,
941                                  &radio_header->header,
942                                  GNUNET_NO,
943                                  &fragment_transmission_done, fm);
944     fm->size_on_wire += size;
945     if (NULL != fm->sh)
946       GNUNET_STATISTICS_update (endpoint->plugin->env->stats,
947                                 _("# WLAN message fragments sent"),
948                                 1,
949                                 GNUNET_NO);
950     else
951       GNUNET_FRAGMENT_context_transmission_done (fm->fragcontext);
952     GNUNET_STATISTICS_update (endpoint->plugin->env->stats,
953                               "# bytes currently in WLAN buffers",
954                               -msize, GNUNET_NO);
955     GNUNET_STATISTICS_update (endpoint->plugin->env->stats,
956                               "# bytes transmitted via WLAN",
957                               msize, GNUNET_NO);
958   }
959 }
960
961
962 /**
963  * Frees the space of a message in the fragment queue (send queue)
964  *
965  * @param fm message to free
966  */
967 static void
968 free_fragment_message (struct FragmentMessage *fm)
969 {
970   struct MacEndpoint *endpoint = fm->macendpoint;
971
972   GNUNET_STATISTICS_update (endpoint->plugin->env->stats,
973                             _("# WLAN messages pending (with fragmentation)"),
974                             -1, GNUNET_NO);
975   GNUNET_CONTAINER_DLL_remove (endpoint->sending_messages_head,
976                                endpoint->sending_messages_tail,
977                                fm);
978   if (NULL != fm->sh)
979   {
980     GNUNET_HELPER_send_cancel (fm->sh);
981     fm->sh = NULL;
982   }
983   GNUNET_FRAGMENT_context_destroy (fm->fragcontext,
984                                    &endpoint->msg_delay,
985                                    &endpoint->ack_delay);
986   if (fm->timeout_task != GNUNET_SCHEDULER_NO_TASK)
987   {
988     GNUNET_SCHEDULER_cancel (fm->timeout_task);
989     fm->timeout_task = GNUNET_SCHEDULER_NO_TASK;
990   }
991   GNUNET_free (fm);
992 }
993
994
995 /**
996  * A FragmentMessage has timed out.  Remove it.
997  *
998  * @param cls pointer to the 'struct FragmentMessage'
999  * @param tc unused
1000  */
1001 static void
1002 fragmentmessage_timeout (void *cls,
1003                          const struct GNUNET_SCHEDULER_TaskContext *tc)
1004 {
1005   struct FragmentMessage *fm = cls;
1006
1007   fm->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1008   if (NULL != fm->cont)
1009   {
1010     fm->cont (fm->cont_cls,
1011               &fm->target,
1012               GNUNET_SYSERR,
1013               fm->size_payload,
1014               fm->size_on_wire);
1015     fm->cont = NULL;
1016   }
1017   free_fragment_message (fm);
1018 }
1019
1020
1021 /**
1022  * Transmit a message to the given destination with fragmentation.
1023  *
1024  * @param endpoint desired destination
1025  * @param timeout how long can the message wait?
1026  * @param target peer that should receive the message
1027  * @param msg message to transmit
1028  * @param payload_size bytes of payload
1029  * @param cont continuation to call once the message has
1030  *        been transmitted (or if the transport is ready
1031  *        for the next transmission call; or if the
1032  *        peer disconnected...); can be NULL
1033  * @param cont_cls closure for @a cont
1034  */
1035 static void
1036 send_with_fragmentation (struct MacEndpoint *endpoint,
1037                          struct GNUNET_TIME_Relative timeout,
1038                          const struct GNUNET_PeerIdentity *target,
1039                          const struct GNUNET_MessageHeader *msg,
1040                          size_t payload_size,
1041                          GNUNET_TRANSPORT_TransmitContinuation cont,
1042                          void *cont_cls)
1043
1044 {
1045   struct FragmentMessage *fm;
1046   struct Plugin *plugin;
1047
1048   plugin = endpoint->plugin;
1049   fm = GNUNET_new (struct FragmentMessage);
1050   fm->macendpoint = endpoint;
1051   fm->target = *target;
1052   fm->size_payload = payload_size;
1053   fm->size_on_wire = 0;
1054   fm->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1055   fm->cont = cont;
1056   fm->cont_cls = cont_cls;
1057   /* 1 MBit/s typical data rate, 1430 byte fragments => ~100 ms per message */
1058   fm->fragcontext =
1059     GNUNET_FRAGMENT_context_create (plugin->env->stats,
1060                                     WLAN_MTU,
1061                                     &plugin->tracker,
1062                                     endpoint->msg_delay,
1063                                     endpoint->ack_delay,
1064                                     msg,
1065                                     &transmit_fragment, fm);
1066   fm->timeout_task =
1067     GNUNET_SCHEDULER_add_delayed (timeout,
1068                                   &fragmentmessage_timeout, fm);
1069   GNUNET_CONTAINER_DLL_insert_tail (endpoint->sending_messages_head,
1070                                     endpoint->sending_messages_tail,
1071                                     fm);
1072 }
1073
1074
1075 /**
1076  * Free a MAC endpoint.
1077  *
1078  * @param endpoint pointer to the MacEndpoint to free
1079  */
1080 static void
1081 free_macendpoint (struct MacEndpoint *endpoint)
1082 {
1083   struct Plugin *plugin = endpoint->plugin;
1084   struct FragmentMessage *fm;
1085   struct Session *session;
1086
1087   GNUNET_STATISTICS_update (plugin->env->stats,
1088                             _("# WLAN MAC endpoints allocated"),
1089                             -1,
1090                             GNUNET_NO);
1091   while (NULL != (session = endpoint->sessions_head))
1092     wlan_plugin_disconnect_session (plugin,
1093                                     session);
1094   while (NULL != (fm = endpoint->sending_messages_head))
1095     free_fragment_message (fm);
1096   GNUNET_CONTAINER_DLL_remove (plugin->mac_head,
1097                                plugin->mac_tail,
1098                                endpoint);
1099
1100   if (NULL != endpoint->defrag)
1101   {
1102     GNUNET_DEFRAGMENT_context_destroy(endpoint->defrag);
1103     endpoint->defrag = NULL;
1104   }
1105
1106   plugin->mac_count--;
1107   if (GNUNET_SCHEDULER_NO_TASK != endpoint->timeout_task)
1108   {
1109     GNUNET_SCHEDULER_cancel (endpoint->timeout_task);
1110     endpoint->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1111   }
1112   GNUNET_free (endpoint);
1113 }
1114
1115
1116 /**
1117  * A MAC endpoint is timing out.  Clean up.
1118  *
1119  * @param cls pointer to the `struct MacEndpoint *`
1120  * @param tc pointer to the GNUNET_SCHEDULER_TaskContext
1121  */
1122 static void
1123 macendpoint_timeout (void *cls,
1124                      const struct GNUNET_SCHEDULER_TaskContext *tc)
1125 {
1126   struct MacEndpoint *endpoint = cls;
1127   struct GNUNET_TIME_Relative timeout;
1128
1129   endpoint->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1130   timeout = GNUNET_TIME_absolute_get_remaining (endpoint->timeout);
1131   if (0 == timeout.rel_value_us)
1132   {
1133     free_macendpoint (endpoint);
1134     return;
1135   }
1136   endpoint->timeout_task =
1137     GNUNET_SCHEDULER_add_delayed (timeout,
1138                                   &macendpoint_timeout,
1139                                   endpoint);
1140 }
1141
1142
1143 /**
1144  * Find (or create) a MacEndpoint with a specific MAC address
1145  *
1146  * @param plugin pointer to the plugin struct
1147  * @param mac the MAC address of the endpoint
1148  * @return handle to our data structure for this MAC
1149  */
1150 static struct MacEndpoint *
1151 create_macendpoint (struct Plugin *plugin,
1152                     struct WlanAddress *mac)
1153 {
1154   struct MacEndpoint *pos;
1155
1156   for (pos = plugin->mac_head; NULL != pos; pos = pos->next)
1157   {
1158     if (0 == memcmp (mac, &pos->wlan_addr, sizeof (pos->wlan_addr)))
1159     {
1160       LOG (GNUNET_ERROR_TYPE_DEBUG, "Found existing MAC endpoint `%s'\n",
1161         wlan_plugin_address_to_string (NULL,
1162                                        &pos->wlan_addr.mac,
1163                                        sizeof (pos->wlan_addr)));
1164       return pos;
1165     }
1166   }
1167   pos = GNUNET_new (struct MacEndpoint);
1168   pos->wlan_addr = (*mac);
1169   pos->plugin = plugin;
1170   pos->defrag =
1171     GNUNET_DEFRAGMENT_context_create (plugin->env->stats,
1172                                       WLAN_MTU,
1173                                       MESSAGES_IN_DEFRAG_QUEUE_PER_MAC,
1174                                       pos,
1175                                       &wlan_data_message_handler,
1176                                       &send_ack);
1177
1178   pos->msg_delay = GNUNET_TIME_UNIT_MILLISECONDS;
1179   pos->ack_delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100);
1180   pos->timeout = GNUNET_TIME_relative_to_absolute (MACENDPOINT_TIMEOUT);
1181   pos->timeout_task =
1182       GNUNET_SCHEDULER_add_delayed (MACENDPOINT_TIMEOUT, &macendpoint_timeout,
1183                                     pos);
1184   GNUNET_CONTAINER_DLL_insert (plugin->mac_head,
1185                                plugin->mac_tail,
1186                                pos);
1187   plugin->mac_count++;
1188   GNUNET_STATISTICS_update (plugin->env->stats,
1189                             _("# WLAN MAC endpoints allocated"),
1190                             1, GNUNET_NO);
1191   LOG (GNUNET_ERROR_TYPE_DEBUG,
1192        "New MAC endpoint `%s'\n",
1193        wlan_plugin_address_to_string (NULL,
1194                                       &pos->wlan_addr,
1195                                       sizeof (struct WlanAddress)));
1196   return pos;
1197 }
1198
1199
1200 /**
1201  * Function obtain the network type for a session
1202  *
1203  * @param cls closure (`struct Plugin*`)
1204  * @param session the session
1205  * @return the network type in HBO or #GNUNET_SYSERR
1206  */
1207 static enum GNUNET_ATS_Network_Type
1208 wlan_plugin_get_network (void *cls,
1209                          struct Session *session)
1210 {
1211   return GNUNET_ATS_NET_WLAN;
1212 }
1213
1214
1215 /**
1216  * Creates a new outbound session the transport service will use to
1217  * send data to the peer
1218  *
1219  * @param cls the `struct Plugin *`
1220  * @param address the address
1221  * @return the session or NULL of max connections exceeded
1222  */
1223 static struct Session *
1224 wlan_plugin_get_session (void *cls,
1225                          const struct GNUNET_HELLO_Address *address)
1226 {
1227   struct Plugin *plugin = cls;
1228   struct MacEndpoint *endpoint;
1229
1230   if (NULL == address)
1231     return NULL;
1232   if (sizeof (struct WlanAddress) != address->address_length)
1233   {
1234     GNUNET_break (0);
1235     return NULL;
1236   }
1237   LOG (GNUNET_ERROR_TYPE_DEBUG,
1238        "Service asked to create session for peer `%s' with MAC `%s'\n",
1239        GNUNET_i2s (&address->peer),
1240        wlan_plugin_address_to_string (NULL,
1241                                       address->address,
1242                                       address->address_length));
1243   endpoint = create_macendpoint (plugin, (struct WlanAddress *) address->address);
1244   return get_session (endpoint, &address->peer);
1245 }
1246
1247
1248 /**
1249  * Function that can be used to force the plugin to disconnect
1250  * from the given peer and cancel all previous transmissions
1251  * (and their continuation).
1252  *
1253  * @param cls closure
1254  * @param target peer from which to disconnect
1255  */
1256 static void
1257 wlan_plugin_disconnect_peer (void *cls,
1258                              const struct GNUNET_PeerIdentity *target)
1259 {
1260   struct Plugin *plugin = cls;
1261   struct Session *session;
1262   struct MacEndpoint *endpoint;
1263
1264   for (endpoint = plugin->mac_head; NULL != endpoint; endpoint = endpoint->next)
1265     for (session = endpoint->sessions_head; NULL != session; session = session->next)
1266       if (0 == memcmp (target, &session->target,
1267                        sizeof (struct GNUNET_PeerIdentity)))
1268       {
1269         wlan_plugin_disconnect_session (plugin, session);
1270         break; /* inner-loop only (in case peer has another MAC as well!) */
1271       }
1272 }
1273
1274
1275 /**
1276  * Function that can be used by the transport service to transmit
1277  * a message using the plugin.   Note that in the case of a
1278  * peer disconnecting, the continuation MUST be called
1279  * prior to the disconnect notification itself.  This function
1280  * will be called with this peer's HELLO message to initiate
1281  * a fresh connection to another peer.
1282  *
1283  * @param cls closure
1284  * @param session which session must be used
1285  * @param msgbuf the message to transmit
1286  * @param msgbuf_size number of bytes in @a msgbuf
1287  * @param priority how important is the message (most plugins will
1288  *                 ignore message priority and just FIFO)
1289  * @param to how long to wait at most for the transmission (does not
1290  *                require plugins to discard the message after the timeout,
1291  *                just advisory for the desired delay; most plugins will ignore
1292  *                this as well)
1293  * @param cont continuation to call once the message has
1294  *        been transmitted (or if the transport is ready
1295  *        for the next transmission call; or if the
1296  *        peer disconnected...); can be NULL
1297  * @param cont_cls closure for @a cont
1298  * @return number of bytes used (on the physical network, with overheads);
1299  *         -1 on hard errors (i.e. address invalid); 0 is a legal value
1300  *         and does NOT mean that the message was not transmitted (DV)
1301  */
1302 static ssize_t
1303 wlan_plugin_send (void *cls,
1304                   struct Session *session,
1305                   const char *msgbuf, size_t msgbuf_size,
1306                   unsigned int priority,
1307                   struct GNUNET_TIME_Relative to,
1308                   GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
1309 {
1310   struct Plugin *plugin = cls;
1311   struct WlanHeader *wlanheader;
1312   size_t size = msgbuf_size + sizeof (struct WlanHeader);
1313   char buf[size] GNUNET_ALIGN;
1314
1315   LOG (GNUNET_ERROR_TYPE_DEBUG,
1316        "Transmitting %u bytes of payload to peer `%s' (starting with %u byte message of type %u)\n",
1317        msgbuf_size,
1318        GNUNET_i2s (&session->target),
1319        (unsigned int) ntohs (((struct GNUNET_MessageHeader*)msgbuf)->size),
1320        (unsigned int) ntohs (((struct GNUNET_MessageHeader*)msgbuf)->type));
1321   wlanheader = (struct WlanHeader *) buf;
1322   wlanheader->header.size = htons (msgbuf_size + sizeof (struct WlanHeader));
1323   wlanheader->header.type = htons (GNUNET_MESSAGE_TYPE_WLAN_DATA);
1324   wlanheader->sender = *plugin->env->my_identity;
1325   wlanheader->target = session->target;
1326   wlanheader->crc = htonl (GNUNET_CRYPTO_crc32_n (msgbuf, msgbuf_size));
1327   memcpy (&wlanheader[1], msgbuf, msgbuf_size);
1328
1329   GNUNET_STATISTICS_update (plugin->env->stats,
1330                             "# bytes currently in WLAN buffers",
1331                             msgbuf_size, GNUNET_NO);
1332
1333   send_with_fragmentation (session->mac,
1334                            to,
1335                            &session->target,
1336                            &wlanheader->header,
1337                            msgbuf_size,
1338                            cont, cont_cls);
1339   return size;
1340 }
1341
1342
1343 /**
1344  * We have received data from the WLAN via some session.  Process depending
1345  * on the message type (HELLO, DATA, FRAGMENTATION or FRAGMENTATION-ACK).
1346  *
1347  * @param cls pointer to the plugin
1348  * @param client pointer to the session this message belongs to
1349  * @param hdr start of the message
1350  */
1351 static int
1352 process_data (void *cls,
1353               void *client,
1354               const struct GNUNET_MessageHeader *hdr)
1355 {
1356   struct Plugin *plugin = cls;
1357   struct GNUNET_HELLO_Address *address;
1358   struct MacAndSession *mas = client;
1359   struct MacAndSession xmas;
1360   struct GNUNET_ATS_Information ats;
1361   struct FragmentMessage *fm;
1362   struct GNUNET_PeerIdentity tmpsource;
1363   const struct WlanHeader *wlanheader;
1364   int ret;
1365   uint16_t msize;
1366
1367   ats.type = htonl (GNUNET_ATS_NETWORK_TYPE);
1368   ats.value = htonl (GNUNET_ATS_NET_WLAN);
1369   msize = ntohs (hdr->size);
1370
1371   GNUNET_STATISTICS_update (plugin->env->stats,
1372                             "# bytes received via WLAN",
1373                             msize, GNUNET_NO);
1374
1375   switch (ntohs (hdr->type))
1376   {
1377   case GNUNET_MESSAGE_TYPE_HELLO:
1378
1379     if (GNUNET_OK !=
1380         GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) hdr,
1381                              &tmpsource))
1382     {
1383       GNUNET_break_op (0);
1384       break;
1385     }
1386     if (NULL == mas->endpoint)
1387     {
1388       GNUNET_break (0);
1389       break;
1390     }
1391
1392     LOG (GNUNET_ERROR_TYPE_DEBUG,
1393          "Processing %u bytes of HELLO from peer `%s' at MAC %s\n",
1394          (unsigned int) msize,
1395          GNUNET_i2s (&tmpsource),
1396          wlan_plugin_address_to_string (NULL,
1397                                         &mas->endpoint->wlan_addr,
1398                                         sizeof (mas->endpoint->wlan_addr)));
1399
1400     GNUNET_STATISTICS_update (plugin->env->stats,
1401                               _("# HELLO messages received via WLAN"), 1,
1402                               GNUNET_NO);
1403     address = GNUNET_HELLO_address_allocate (&tmpsource,
1404                                              PLUGIN_NAME,
1405                                              &mas->endpoint->wlan_addr,
1406                                              sizeof (mas->endpoint->wlan_addr),
1407                                              GNUNET_HELLO_ADDRESS_INFO_INBOUND);
1408     plugin->env->receive (plugin->env->cls,
1409                           address,
1410                           mas->session,
1411                           hdr);
1412     plugin->env->update_address_metrics (plugin->env->cls,
1413                                          address,
1414                                          mas->session,
1415                                          &ats, 1);
1416     GNUNET_HELLO_address_free (address);
1417     break;
1418   case GNUNET_MESSAGE_TYPE_FRAGMENT:
1419     if (NULL == mas->endpoint)
1420     {
1421       GNUNET_break (0);
1422       break;
1423     }
1424     LOG (GNUNET_ERROR_TYPE_DEBUG,
1425          "Processing %u bytes of FRAGMENT from MAC %s\n",
1426          (unsigned int) msize,
1427          wlan_plugin_address_to_string (NULL,
1428                                         &mas->endpoint->wlan_addr,
1429                                         sizeof (mas->endpoint->wlan_addr)));
1430     GNUNET_STATISTICS_update (plugin->env->stats,
1431                               _("# fragments received via WLAN"),
1432                               1,
1433                               GNUNET_NO);
1434     (void) GNUNET_DEFRAGMENT_process_fragment (mas->endpoint->defrag,
1435                                               hdr);
1436     break;
1437   case GNUNET_MESSAGE_TYPE_FRAGMENT_ACK:
1438     if (NULL == mas->endpoint)
1439     {
1440       GNUNET_break (0);
1441       break;
1442     }
1443     GNUNET_STATISTICS_update (plugin->env->stats,
1444                               _("# ACKs received via WLAN"),
1445                               1, GNUNET_NO);
1446     for (fm = mas->endpoint->sending_messages_head; NULL != fm; fm = fm->next)
1447     {
1448       ret = GNUNET_FRAGMENT_process_ack (fm->fragcontext, hdr);
1449       if (GNUNET_OK == ret)
1450       {
1451         LOG (GNUNET_ERROR_TYPE_DEBUG,
1452              "Got last ACK, finished message transmission to `%s' (%p)\n",
1453              wlan_plugin_address_to_string (NULL,
1454                                             &mas->endpoint->wlan_addr,
1455                                             sizeof (mas->endpoint->wlan_addr)),
1456              fm);
1457         mas->endpoint->timeout = GNUNET_TIME_relative_to_absolute (MACENDPOINT_TIMEOUT);
1458         if (NULL != fm->cont)
1459         {
1460           fm->cont (fm->cont_cls,
1461                     &fm->target,
1462                     GNUNET_OK,
1463                     fm->size_payload,
1464                     fm->size_on_wire);
1465           fm->cont = NULL;
1466         }
1467         free_fragment_message (fm);
1468         break;
1469       }
1470       if (GNUNET_NO == ret)
1471       {
1472         LOG (GNUNET_ERROR_TYPE_DEBUG,
1473              "Got an ACK, message transmission to `%s' not yet finished\n",
1474              wlan_plugin_address_to_string (NULL,
1475                                             &mas->endpoint->wlan_addr,
1476                                             sizeof (mas->endpoint->wlan_addr)));
1477         break;
1478       }
1479     }
1480     LOG (GNUNET_ERROR_TYPE_DEBUG,
1481          "ACK not matched against any active fragmentation with MAC `%s'\n",
1482          wlan_plugin_address_to_string (NULL,
1483                                         &mas->endpoint->wlan_addr,
1484                                         sizeof (mas->endpoint->wlan_addr)));
1485     break;
1486   case GNUNET_MESSAGE_TYPE_WLAN_DATA:
1487     if (NULL == mas->endpoint)
1488     {
1489       GNUNET_break (0);
1490       break;
1491     }
1492     if (msize < sizeof (struct WlanHeader))
1493     {
1494       GNUNET_break (0);
1495       break;
1496     }
1497     wlanheader = (const struct WlanHeader *) hdr;
1498     if (0 != memcmp (&wlanheader->target,
1499                      plugin->env->my_identity,
1500                      sizeof (struct GNUNET_PeerIdentity)))
1501     {
1502       LOG (GNUNET_ERROR_TYPE_DEBUG,
1503            "WLAN data for `%s', not for me, ignoring\n",
1504            GNUNET_i2s (&wlanheader->target));
1505       break;
1506     }
1507     if (ntohl (wlanheader->crc) !=
1508         GNUNET_CRYPTO_crc32_n (&wlanheader[1],
1509                                msize - sizeof (struct WlanHeader)))
1510     {
1511       GNUNET_STATISTICS_update (plugin->env->stats,
1512                                 _("# WLAN DATA messages discarded due to CRC32 error"),
1513                                 1,
1514                                 GNUNET_NO);
1515       break;
1516     }
1517     xmas.endpoint = mas->endpoint;
1518     if (NULL == (xmas.session = lookup_session (mas->endpoint,
1519                                                 &wlanheader->sender)))
1520     {
1521       xmas.session = create_session (mas->endpoint,
1522                                      &wlanheader->sender);
1523       address = GNUNET_HELLO_address_allocate (&wlanheader->sender,
1524                                                PLUGIN_NAME,
1525                                                &mas->endpoint->wlan_addr,
1526                                                sizeof (struct WlanAddress),
1527                                                GNUNET_HELLO_ADDRESS_INFO_NONE);
1528       plugin->env->session_start (NULL,
1529                                   address,
1530                                   xmas.session,
1531                                   NULL, 0);
1532       LOG (GNUNET_ERROR_TYPE_DEBUG,
1533           "Notifying transport about peer `%s''s new session %p \n",
1534            GNUNET_i2s (&wlanheader->sender),
1535            xmas.session);
1536       GNUNET_HELLO_address_free (address);
1537     }
1538     LOG (GNUNET_ERROR_TYPE_DEBUG,
1539          "Processing %u bytes of WLAN DATA from peer `%s'\n",
1540          (unsigned int) msize,
1541          GNUNET_i2s (&wlanheader->sender));
1542     xmas.session->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1543     (void) GNUNET_SERVER_mst_receive (plugin->wlan_header_payload_tokenizer,
1544                                       &xmas,
1545                                       (const char *) &wlanheader[1],
1546                                       msize - sizeof (struct WlanHeader),
1547                                       GNUNET_YES,
1548                                       GNUNET_NO);
1549     break;
1550   default:
1551     if (NULL == mas->endpoint)
1552     {
1553       GNUNET_break (0);
1554       break;
1555     }
1556     if (NULL == mas->session)
1557     {
1558       GNUNET_break (0);
1559       break;
1560     }
1561     LOG (GNUNET_ERROR_TYPE_DEBUG,
1562          "Received packet with %u bytes of type %u from peer %s\n",
1563          (unsigned int) msize,
1564          (unsigned int) ntohs (hdr->type),
1565          GNUNET_i2s (&mas->session->target));
1566     plugin->env->receive (plugin->env->cls,
1567                           mas->session->address,
1568                           mas->session,
1569                           hdr);
1570     plugin->env->update_address_metrics (plugin->env->cls,
1571                                          mas->session->address,
1572                                          mas->session,
1573                                          &ats, 1);
1574     break;
1575   }
1576   return GNUNET_OK;
1577 }
1578
1579
1580 /**
1581  * Function used for to process the data from the suid process
1582  *
1583  * @param cls the plugin handle
1584  * @param client client that send the data (not used)
1585  * @param hdr header of the GNUNET_MessageHeader
1586  */
1587 static int
1588 handle_helper_message (void *cls, void *client,
1589                        const struct GNUNET_MessageHeader *hdr)
1590 {
1591   struct Plugin *plugin = cls;
1592   struct GNUNET_HELLO_Address *my_address;
1593   const struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *rxinfo;
1594   const struct GNUNET_TRANSPORT_WLAN_HelperControlMessage *cm;
1595   struct WlanAddress wa;
1596   struct MacAndSession mas;
1597   uint16_t msize;
1598
1599   msize = ntohs (hdr->size);
1600   switch (ntohs (hdr->type))
1601   {
1602   case GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL:
1603     if (msize != sizeof (struct GNUNET_TRANSPORT_WLAN_HelperControlMessage))
1604     {
1605       GNUNET_break (0);
1606       break;
1607     }
1608     cm = (const struct GNUNET_TRANSPORT_WLAN_HelperControlMessage *) hdr;
1609     if (GNUNET_YES == plugin->have_mac)
1610     {
1611       if (0 == memcmp (&plugin->mac_address,
1612                        &cm->mac,
1613                        sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)))
1614         break; /* no change */
1615       /* remove old address */
1616       memset (&wa, 0, sizeof (struct WlanAddress));
1617       wa.mac = plugin->mac_address;
1618       wa.options = htonl(plugin->options);
1619       my_address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
1620                                                   PLUGIN_NAME,
1621                                                   &wa, sizeof (wa),
1622                                                   GNUNET_HELLO_ADDRESS_INFO_NONE);
1623       plugin->env->notify_address (plugin->env->cls,
1624                                    GNUNET_NO,
1625                                    my_address);
1626       GNUNET_HELLO_address_free (my_address);
1627     }
1628     plugin->mac_address = cm->mac;
1629     plugin->have_mac = GNUNET_YES;
1630
1631     memset (&wa, 0, sizeof (struct WlanAddress));
1632     wa.mac = plugin->mac_address;
1633     wa.options = htonl(plugin->options);
1634     my_address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
1635                                                 PLUGIN_NAME,
1636                                                 &wa, sizeof (wa),
1637                                                 GNUNET_HELLO_ADDRESS_INFO_NONE);
1638
1639     LOG (GNUNET_ERROR_TYPE_DEBUG,
1640          "Received WLAN_HELPER_CONTROL message with MAC address `%s' for peer `%s'\n",
1641          mac_to_string (&cm->mac),
1642          GNUNET_i2s (plugin->env->my_identity));
1643     plugin->env->notify_address (plugin->env->cls,
1644                                  GNUNET_YES,
1645                                  my_address);
1646     GNUNET_HELLO_address_free (my_address);
1647     break;
1648   case GNUNET_MESSAGE_TYPE_WLAN_DATA_FROM_HELPER:
1649     LOG (GNUNET_ERROR_TYPE_DEBUG,
1650          "Got data message from helper with %u bytes\n",
1651          msize);
1652     GNUNET_STATISTICS_update (plugin->env->stats,
1653                               _("# DATA messages received via WLAN"), 1,
1654                               GNUNET_NO);
1655     if (msize < sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage))
1656     {
1657       GNUNET_break (0);
1658       LOG (GNUNET_ERROR_TYPE_DEBUG,
1659            "Size of packet is too small (%u bytes)\n",
1660            msize);
1661       break;
1662     }
1663     rxinfo = (const struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *) hdr;
1664
1665     /* check if message is actually for us */
1666     if (0 != memcmp (&rxinfo->frame.addr3, &mac_bssid_gnunet,
1667                      sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)))
1668     {
1669       /* Not the GNUnet BSSID */
1670       break;
1671     }
1672     if ( (0 != memcmp (&rxinfo->frame.addr1, &bc_all_mac,
1673                        sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress))) &&
1674          (0 != memcmp (&rxinfo->frame.addr1, &plugin->mac_address,
1675                        sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress))) )
1676     {
1677       /* Neither broadcast nor specifically for us */
1678       break;
1679     }
1680     if (0 == memcmp (&rxinfo->frame.addr2, &plugin->mac_address,
1681                      sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)))
1682     {
1683       /* packet is FROM us, thus not FOR us */
1684       break;
1685     }
1686
1687     GNUNET_STATISTICS_update (plugin->env->stats,
1688                               _("# WLAN DATA messages processed"),
1689                               1, GNUNET_NO);
1690     LOG (GNUNET_ERROR_TYPE_DEBUG,
1691          "Receiving %u bytes of data from MAC `%s'\n",
1692          (unsigned int) (msize - sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)),
1693          mac_to_string (&rxinfo->frame.addr2));
1694     wa.mac = rxinfo->frame.addr2;
1695     wa.options = htonl (0);
1696     mas.endpoint = create_macendpoint (plugin, &wa);
1697     mas.session = NULL;
1698     (void) GNUNET_SERVER_mst_receive (plugin->helper_payload_tokenizer,
1699                                       &mas,
1700                                       (const char*) &rxinfo[1],
1701                                       msize - sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage),
1702                                       GNUNET_YES, GNUNET_NO);
1703     break;
1704   default:
1705     GNUNET_break (0);
1706     LOG (GNUNET_ERROR_TYPE_DEBUG,
1707          "Unexpected message of type %u (%u bytes)",
1708          ntohs (hdr->type), ntohs (hdr->size));
1709     break;
1710   }
1711   return GNUNET_OK;
1712 }
1713
1714
1715 /**
1716  * Task to (periodically) send a HELLO beacon
1717  *
1718  * @param cls pointer to the plugin struct
1719  * @param tc scheduler context
1720  */
1721 static void
1722 send_hello_beacon (void *cls,
1723                    const struct GNUNET_SCHEDULER_TaskContext *tc)
1724 {
1725   struct Plugin *plugin = cls;
1726   uint16_t size;
1727   uint16_t hello_size;
1728   struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *radioHeader;
1729   const struct GNUNET_MessageHeader *hello;
1730
1731   hello = plugin->env->get_our_hello ();
1732   hello_size = GNUNET_HELLO_size ((struct GNUNET_HELLO_Message *) hello);
1733   GNUNET_assert (sizeof (struct WlanHeader) + hello_size <= WLAN_MTU);
1734   size = sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage) + hello_size;
1735   {
1736     char buf[size] GNUNET_ALIGN;
1737
1738     LOG (GNUNET_ERROR_TYPE_DEBUG,
1739          "Sending %u byte HELLO beacon\n",
1740          (unsigned int) size);
1741     radioHeader = (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage*) buf;
1742     get_radiotap_header (NULL, radioHeader, size);
1743     get_wlan_header (plugin, &radioHeader->frame, &bc_all_mac, size);
1744     memcpy (&radioHeader[1], hello, hello_size);
1745     if (NULL !=
1746         GNUNET_HELPER_send (plugin->suid_helper,
1747                             &radioHeader->header,
1748                             GNUNET_YES /* can drop */,
1749                             NULL, NULL))
1750       GNUNET_STATISTICS_update (plugin->env->stats,
1751                                 _("# HELLO beacons sent via WLAN"),
1752                                 1, GNUNET_NO);
1753   }
1754   plugin->beacon_task =
1755     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
1756                                   (HELLO_BEACON_SCALING_FACTOR,
1757                                    plugin->mac_count + 1),
1758                                   &send_hello_beacon,
1759                                   plugin);
1760
1761 }
1762
1763
1764 /**
1765  * Another peer has suggested an address for this
1766  * peer and transport plugin.  Check that this could be a valid
1767  * address.  If so, consider adding it to the list
1768  * of addresses.
1769  *
1770  * @param cls closure
1771  * @param addr pointer to the address
1772  * @param addrlen length of @a addr
1773  * @return #GNUNET_OK if this is a plausible address for this peer
1774  *         and transport
1775  */
1776 static int
1777 wlan_plugin_address_suggested (void *cls,
1778                                const void *addr,
1779                                size_t addrlen)
1780 {
1781   struct Plugin *plugin = cls;
1782   struct WlanAddress *wa = (struct WlanAddress *) addr;
1783
1784   if (addrlen != sizeof (struct WlanAddress))
1785   {
1786     GNUNET_break_op (0);
1787     return GNUNET_SYSERR;
1788   }
1789   if (GNUNET_YES != plugin->have_mac)
1790   {
1791     LOG (GNUNET_ERROR_TYPE_DEBUG,
1792          "Rejecting MAC `%s': I don't know my MAC!\n",
1793          mac_to_string (addr));
1794     return GNUNET_NO; /* don't know my MAC */
1795   }
1796   if (0 != memcmp (&wa->mac,
1797                    &plugin->mac_address,
1798                    sizeof (wa->mac)))
1799   {
1800     LOG (GNUNET_ERROR_TYPE_DEBUG,
1801          "Rejecting MAC `%s': not my MAC!\n",
1802          mac_to_string (addr));
1803     return GNUNET_NO; /* not my MAC */
1804   }
1805   return GNUNET_OK;
1806 }
1807
1808
1809 /**
1810  * Convert the transports address to a nice, human-readable format.
1811  *
1812  * @param cls closure
1813  * @param type name of the transport that generated the address
1814  * @param addr one of the addresses of the host, NULL for the last address
1815  *        the specific address format depends on the transport
1816  * @param addrlen length of the address
1817  * @param numeric should (IP) addresses be displayed in numeric form?
1818  * @param timeout after how long should we give up?
1819  * @param asc function to call on each string
1820  * @param asc_cls closure for @a asc
1821  */
1822 static void
1823 wlan_plugin_address_pretty_printer (void *cls,
1824                                     const char *type,
1825                                     const void *addr,
1826                                     size_t addrlen,
1827                                     int numeric,
1828                                     struct GNUNET_TIME_Relative timeout,
1829                                     GNUNET_TRANSPORT_AddressStringCallback asc,
1830                                     void *asc_cls)
1831 {
1832   const char *ret;
1833
1834   if (sizeof (struct WlanAddress) == addrlen)
1835     ret = wlan_plugin_address_to_string (NULL,
1836                                          addr,
1837                                          addrlen);
1838   else
1839     ret = NULL;
1840   asc (asc_cls,
1841        ret,
1842        (NULL == ret) ? GNUNET_SYSERR : GNUNET_OK);
1843   asc (asc_cls, NULL, GNUNET_OK);
1844 }
1845
1846
1847 /**
1848  * Exit point from the plugin.
1849  *
1850  * @param cls pointer to the api struct
1851  */
1852 void *
1853 libgnunet_plugin_transport_wlan_done (void *cls)
1854 {
1855   struct WlanAddress wa;
1856   struct GNUNET_HELLO_Address *address;
1857   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
1858   struct Plugin *plugin = api->cls;
1859   struct MacEndpoint *endpoint;
1860   struct MacEndpoint *endpoint_next;
1861
1862   if (NULL == plugin)
1863   {
1864     GNUNET_free (api);
1865     return NULL;
1866   }
1867
1868   if (GNUNET_YES == plugin->have_mac)
1869   {
1870     memset (&wa, 0, sizeof(wa));
1871     wa.options = htonl (plugin->options);
1872     wa.mac = plugin->mac_address;
1873     address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
1874                                              PLUGIN_NAME,
1875                                              &wa, sizeof (struct WlanAddress),
1876                                              GNUNET_HELLO_ADDRESS_INFO_NONE);
1877
1878     plugin->env->notify_address (plugin->env->cls,
1879                                  GNUNET_NO,
1880                                  address);
1881     plugin->have_mac = GNUNET_NO;
1882     GNUNET_HELLO_address_free (address);
1883   }
1884
1885   if (GNUNET_SCHEDULER_NO_TASK != plugin->beacon_task)
1886   {
1887     GNUNET_SCHEDULER_cancel (plugin->beacon_task);
1888     plugin->beacon_task = GNUNET_SCHEDULER_NO_TASK;
1889   }
1890   if (NULL != plugin->suid_helper)
1891   {
1892     GNUNET_HELPER_stop (plugin->suid_helper,
1893                         GNUNET_NO);
1894     plugin->suid_helper = NULL;
1895   }
1896   endpoint_next = plugin->mac_head;
1897   while (NULL != (endpoint = endpoint_next))
1898   {
1899     endpoint_next = endpoint->next;
1900     free_macendpoint (endpoint);
1901   }
1902   if (NULL != plugin->fragment_data_tokenizer)
1903   {
1904     GNUNET_SERVER_mst_destroy (plugin->fragment_data_tokenizer);
1905     plugin->fragment_data_tokenizer = NULL;
1906   }
1907   if (NULL != plugin->wlan_header_payload_tokenizer)
1908   {
1909     GNUNET_SERVER_mst_destroy (plugin->wlan_header_payload_tokenizer);
1910     plugin->wlan_header_payload_tokenizer = NULL;
1911   }
1912   if (NULL != plugin->helper_payload_tokenizer)
1913   {
1914     GNUNET_SERVER_mst_destroy (plugin->helper_payload_tokenizer);
1915     plugin->helper_payload_tokenizer = NULL;
1916   }
1917   GNUNET_free_non_null (plugin->interface);
1918   GNUNET_free (plugin);
1919   GNUNET_free (api);
1920   return NULL;
1921 }
1922
1923
1924 /**
1925  * Function called to convert a string address to
1926  * a binary address.
1927  *
1928  * @param cls closure (`struct Plugin *`)
1929  * @param addr string address
1930  * @param addrlen length of the address
1931  * @param buf location to store the buffer
1932  * @param added location to store the number of bytes in the buffer.
1933  *        If the function returns #GNUNET_SYSERR, its contents are undefined.
1934  * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
1935  */
1936 static int
1937 wlan_plugin_string_to_address (void *cls,
1938                                const char *addr,
1939                                uint16_t addrlen,
1940                                void **buf,
1941                                size_t *added)
1942 {
1943   struct WlanAddress *wa;
1944   unsigned int a[6];
1945   unsigned int i;
1946   char plugin[5];
1947   uint32_t options;
1948
1949   if ((NULL == addr) || (0 == addrlen))
1950   {
1951     GNUNET_break (0);
1952     return GNUNET_SYSERR;
1953   }
1954   if ('\0' != addr[addrlen - 1])
1955   {
1956     GNUNET_break (0);
1957     return GNUNET_SYSERR;
1958   }
1959   if (strlen (addr) != addrlen - 1)
1960   {
1961     GNUNET_break (0);
1962     return GNUNET_SYSERR;
1963   }
1964
1965   if (8 != SSCANF (addr,
1966                    "%4s.%u.%X:%X:%X:%X:%X:%X",
1967                    plugin, &options,
1968                    &a[0], &a[1], &a[2],
1969                    &a[3], &a[4], &a[5]))
1970   {
1971     GNUNET_break (0);
1972     return GNUNET_SYSERR;
1973   }
1974   wa = GNUNET_new (struct WlanAddress);
1975   for (i=0;i<6;i++)
1976     wa->mac.mac[i] = a[i];
1977   wa->options = htonl (0);
1978   *buf = wa;
1979   *added = sizeof (struct WlanAddress);
1980   return GNUNET_OK;
1981 }
1982
1983
1984 /**
1985  * Begin monitoring sessions of a plugin.  There can only
1986  * be one active monitor per plugin (i.e. if there are
1987  * multiple monitors, the transport service needs to
1988  * multiplex the generated events over all of them).
1989  *
1990  * @param cls closure of the plugin
1991  * @param sic callback to invoke, NULL to disable monitor;
1992  *            plugin will being by iterating over all active
1993  *            sessions immediately and then enter monitor mode
1994  * @param sic_cls closure for @a sic
1995  */
1996 static void
1997 wlan_plugin_setup_monitor (void *cls,
1998                            GNUNET_TRANSPORT_SessionInfoCallback sic,
1999                            void *sic_cls)
2000 {
2001   struct Plugin *plugin = cls;
2002   struct MacEndpoint *mac;
2003   struct Session *session;
2004
2005   plugin->sic = sic;
2006   plugin->sic_cls = sic_cls;
2007   if (NULL != sic)
2008   {
2009     for (mac = plugin->mac_head; NULL != mac; mac = mac->next)
2010       for (session = mac->sessions_head; NULL != session; session = session->next)
2011         notify_session_monitor (plugin,
2012                                 session,
2013                                 GNUNET_TRANSPORT_SS_UP);
2014     sic (sic_cls, NULL, NULL);
2015   }
2016 }
2017
2018
2019
2020 /**
2021  * Function that will be called whenever the transport service wants to
2022  * notify the plugin that a session is still active and in use and
2023  * therefore the session timeout for this session has to be updated
2024  *
2025  * @param cls closure
2026  * @param peer which peer was the session for
2027  * @param session which session is being updated
2028  */
2029 static void
2030 wlan_plugin_update_session_timeout (void *cls,
2031                                     const struct GNUNET_PeerIdentity *peer,
2032                                     struct Session *session)
2033 {
2034   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != session->timeout_task);
2035   session->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2036 }
2037
2038
2039 /**
2040  * Function that will be called whenever the transport service wants to
2041  * notify the plugin that the inbound quota changed and that the plugin
2042  * should update it's delay for the next receive value
2043  *
2044  * @param cls closure
2045  * @param peer which peer was the session for
2046  * @param session which session is being updated
2047  * @param delay new delay to use for receiving
2048  */
2049 static void
2050 wlan_plugin_update_inbound_delay (void *cls,
2051                                   const struct GNUNET_PeerIdentity *peer,
2052                                   struct Session *session,
2053                                   struct GNUNET_TIME_Relative delay)
2054 {
2055   /* does nothing, as inbound delay is not supported by WLAN */
2056 }
2057
2058
2059 /**
2060  * Entry point for the plugin.
2061  *
2062  * @param cls closure, the `struct GNUNET_TRANSPORT_PluginEnvironment *`
2063  * @return the `struct GNUNET_TRANSPORT_PluginFunctions *` or NULL on error
2064  */
2065 void *
2066 libgnunet_plugin_transport_wlan_init (void *cls)
2067 {
2068   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
2069   struct GNUNET_TRANSPORT_PluginFunctions *api;
2070   struct Plugin *plugin;
2071   char *interface;
2072   unsigned long long testmode;
2073   char *binary;
2074
2075   /* check for 'special' mode */
2076   if (NULL == env->receive)
2077   {
2078     /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
2079        initialze the plugin or the API */
2080     api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
2081     api->cls = NULL;
2082     api->address_pretty_printer = &wlan_plugin_address_pretty_printer;
2083     api->address_to_string = &wlan_plugin_address_to_string;
2084     api->string_to_address = &wlan_plugin_string_to_address;
2085     return api;
2086   }
2087
2088   testmode = 0;
2089   /* check configuration */
2090   if ( (GNUNET_YES ==
2091         GNUNET_CONFIGURATION_have_value (env->cfg, "transport-wlan", "TESTMODE")) &&
2092        ( (GNUNET_SYSERR ==
2093           GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-wlan",
2094                                                  "TESTMODE", &testmode)) ||
2095          (testmode > 2) ) )
2096   {
2097     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
2098                                "transport-wlan", "TESTMODE");
2099     return NULL;
2100   }
2101   binary = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-transport-wlan");
2102   if ( (0 == testmode) &&
2103        (GNUNET_YES !=
2104         GNUNET_OS_check_helper_binary (binary, GNUNET_YES, NULL)) )
2105   {
2106     LOG (GNUNET_ERROR_TYPE_ERROR,
2107          _("Helper binary `%s' not SUID, cannot run WLAN transport\n"),
2108          "gnunet-helper-transport-wlan");
2109     GNUNET_free (binary);
2110     return NULL;
2111   }
2112     GNUNET_free (binary);
2113   if (GNUNET_YES !=
2114       GNUNET_CONFIGURATION_get_value_string (env->cfg,
2115                                              "transport-wlan",
2116                                              "INTERFACE",
2117                                              &interface))
2118   {
2119     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
2120                                "transport-wlan", "INTERFACE");
2121     return NULL;
2122   }
2123
2124   plugin = GNUNET_new (struct Plugin);
2125   plugin->interface = interface;
2126   plugin->env = env;
2127   GNUNET_STATISTICS_set (plugin->env->stats,
2128                          _("# WLAN sessions allocated"),
2129                          0, GNUNET_NO);
2130   GNUNET_STATISTICS_set (plugin->env->stats,
2131                          _("# WLAN MAC endpoints allocated"),
2132                          0, 0);
2133   GNUNET_BANDWIDTH_tracker_init (&plugin->tracker, NULL, NULL,
2134                                  GNUNET_BANDWIDTH_value_init (100 * 1024 *
2135                                                               1024 / 8),
2136                                  100);
2137   plugin->fragment_data_tokenizer = GNUNET_SERVER_mst_create (&process_data, plugin);
2138   plugin->wlan_header_payload_tokenizer = GNUNET_SERVER_mst_create (&process_data, plugin);
2139   plugin->helper_payload_tokenizer = GNUNET_SERVER_mst_create (&process_data, plugin);
2140   plugin->beacon_task = GNUNET_SCHEDULER_add_now (&send_hello_beacon,
2141                                                   plugin);
2142
2143   plugin->options = 0;
2144
2145   /* some compilers do not like switch on 'long long'... */
2146   switch ((unsigned int) testmode)
2147   {
2148   case 0: /* normal */
2149     plugin->helper_argv[0] = (char *) "gnunet-helper-transport-wlan";
2150     plugin->helper_argv[1] = interface;
2151     plugin->helper_argv[2] = NULL;
2152     plugin->suid_helper = GNUNET_HELPER_start (GNUNET_NO,
2153                                                "gnunet-helper-transport-wlan",
2154                                                plugin->helper_argv,
2155                                                &handle_helper_message,
2156                                                NULL,
2157                                                plugin);
2158     break;
2159   case 1: /* testmode, peer 1 */
2160     plugin->helper_argv[0] = (char *) "gnunet-helper-transport-wlan-dummy";
2161     plugin->helper_argv[1] = (char *) "1";
2162     plugin->helper_argv[2] = NULL;
2163     plugin->suid_helper = GNUNET_HELPER_start (GNUNET_NO,
2164                                                "gnunet-helper-transport-wlan-dummy",
2165                                                plugin->helper_argv,
2166                                                &handle_helper_message,
2167                                                NULL,
2168                                                plugin);
2169     break;
2170   case 2: /* testmode, peer 2 */
2171     plugin->helper_argv[0] = (char *) "gnunet-helper-transport-wlan-dummy";
2172     plugin->helper_argv[1] = (char *) "2";
2173     plugin->helper_argv[2] = NULL;
2174     plugin->suid_helper = GNUNET_HELPER_start (GNUNET_NO,
2175                                                "gnunet-helper-transport-wlan-dummy",
2176                                                plugin->helper_argv,
2177                                                &handle_helper_message,
2178                                                NULL,
2179                                                plugin);
2180     break;
2181   default:
2182     GNUNET_assert (0);
2183   }
2184
2185   api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
2186   api->cls = plugin;
2187   api->send = &wlan_plugin_send;
2188   api->get_session = &wlan_plugin_get_session;
2189   api->disconnect_peer = &wlan_plugin_disconnect_peer;
2190   api->disconnect_session = &wlan_plugin_disconnect_session;
2191   api->query_keepalive_factor = &wlan_plugin_query_keepalive_factor;
2192   api->address_pretty_printer = &wlan_plugin_address_pretty_printer;
2193   api->check_address = &wlan_plugin_address_suggested;
2194   api->address_to_string = &wlan_plugin_address_to_string;
2195   api->string_to_address = &wlan_plugin_string_to_address;
2196   api->get_network = &wlan_plugin_get_network;
2197   api->update_session_timeout = &wlan_plugin_update_session_timeout;
2198   api->update_inbound_delay = &wlan_plugin_update_inbound_delay;
2199   api->setup_monitor = &wlan_plugin_setup_monitor;
2200   return api;
2201 }
2202
2203
2204 /* end of plugin_transport_wlan.c */