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