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