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