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