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