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