call GNUNET_SERVER_receive_done() also on internal error paths
[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., 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  * 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 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 Session *next;
237
238   /**
239    * We keep all sessions in a DLL at their respective
240    * `struct MACEndpoint *`.
241    */
242   struct 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 Session *sessions_head;
368
369   /**
370    * Tail of sessions that use this MAC.
371    */
372   struct 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 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 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 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 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 Session *
864 lookup_session (struct MacEndpoint *endpoint,
865                 const struct GNUNET_PeerIdentity *peer)
866 {
867   struct 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 Session *
884 create_session (struct MacEndpoint *endpoint,
885                 const struct GNUNET_PeerIdentity *peer)
886 {
887   struct Session *session;
888
889   GNUNET_STATISTICS_update (endpoint->plugin->env->stats,
890                             _("# Sessions allocated"),
891                             1,
892                             GNUNET_NO);
893   session = GNUNET_new (struct 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 Session *
932 get_session (struct MacEndpoint *endpoint,
933              const struct GNUNET_PeerIdentity *peer)
934 {
935   struct 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 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 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  * Creates a new outbound session the transport service will use to
1296  * send data to the peer
1297  *
1298  * @param cls the `struct Plugin *`
1299  * @param address the address
1300  * @return the session or NULL of max connections exceeded
1301  */
1302 static struct Session *
1303 wlan_plugin_get_session (void *cls,
1304                          const struct GNUNET_HELLO_Address *address)
1305 {
1306   struct Plugin *plugin = cls;
1307   struct MacEndpoint *endpoint;
1308
1309   if (NULL == address)
1310     return NULL;
1311   if (sizeof (struct WlanAddress) != address->address_length)
1312   {
1313     GNUNET_break (0);
1314     return NULL;
1315   }
1316   LOG (GNUNET_ERROR_TYPE_DEBUG,
1317        "Service asked to create session for peer `%s' with MAC `%s'\n",
1318        GNUNET_i2s (&address->peer),
1319        wlan_plugin_address_to_string (NULL,
1320                                       address->address,
1321                                       address->address_length));
1322   endpoint = create_macendpoint (plugin,
1323                                  (struct WlanAddress *) address->address);
1324   return get_session (endpoint, &address->peer);
1325 }
1326
1327
1328 /**
1329  * Function that can be used to force the plugin to disconnect
1330  * from the given peer and cancel all previous transmissions
1331  * (and their continuation).
1332  *
1333  * @param cls closure
1334  * @param target peer from which to disconnect
1335  */
1336 static void
1337 wlan_plugin_disconnect_peer (void *cls,
1338                              const struct GNUNET_PeerIdentity *target)
1339 {
1340   struct Plugin *plugin = cls;
1341   struct Session *session;
1342   struct MacEndpoint *endpoint;
1343
1344   for (endpoint = plugin->mac_head; NULL != endpoint; endpoint = endpoint->next)
1345     for (session = endpoint->sessions_head; NULL != session; session = session->next)
1346       if (0 == memcmp (target, &session->target,
1347                        sizeof (struct GNUNET_PeerIdentity)))
1348       {
1349         wlan_plugin_disconnect_session (plugin, session);
1350         break; /* inner-loop only (in case peer has another MAC as well!) */
1351       }
1352 }
1353
1354
1355 /**
1356  * Function that can be used by the transport service to transmit
1357  * a message using the plugin.   Note that in the case of a
1358  * peer disconnecting, the continuation MUST be called
1359  * prior to the disconnect notification itself.  This function
1360  * will be called with this peer's HELLO message to initiate
1361  * a fresh connection to another peer.
1362  *
1363  * @param cls closure
1364  * @param session which session must be used
1365  * @param msgbuf the message to transmit
1366  * @param msgbuf_size number of bytes in @a msgbuf
1367  * @param priority how important is the message (most plugins will
1368  *                 ignore message priority and just FIFO)
1369  * @param to how long to wait at most for the transmission (does not
1370  *                require plugins to discard the message after the timeout,
1371  *                just advisory for the desired delay; most plugins will ignore
1372  *                this as well)
1373  * @param cont continuation to call once the message has
1374  *        been transmitted (or if the transport is ready
1375  *        for the next transmission call; or if the
1376  *        peer disconnected...); can be NULL
1377  * @param cont_cls closure for @a cont
1378  * @return number of bytes used (on the physical network, with overheads);
1379  *         -1 on hard errors (i.e. address invalid); 0 is a legal value
1380  *         and does NOT mean that the message was not transmitted (DV)
1381  */
1382 static ssize_t
1383 wlan_plugin_send (void *cls,
1384                   struct Session *session,
1385                   const char *msgbuf, size_t msgbuf_size,
1386                   unsigned int priority,
1387                   struct GNUNET_TIME_Relative to,
1388                   GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
1389 {
1390   struct Plugin *plugin = cls;
1391   struct WlanHeader *wlanheader;
1392   size_t size = msgbuf_size + sizeof (struct WlanHeader);
1393   char buf[size] GNUNET_ALIGN;
1394
1395   LOG (GNUNET_ERROR_TYPE_DEBUG,
1396        "Transmitting %u bytes of payload to peer `%s' (starting with %u byte message of type %u)\n",
1397        msgbuf_size,
1398        GNUNET_i2s (&session->target),
1399        (unsigned int) ntohs (((struct GNUNET_MessageHeader*)msgbuf)->size),
1400        (unsigned int) ntohs (((struct GNUNET_MessageHeader*)msgbuf)->type));
1401   wlanheader = (struct WlanHeader *) buf;
1402   wlanheader->header.size = htons (msgbuf_size + sizeof (struct WlanHeader));
1403   wlanheader->header.type = htons (GNUNET_MESSAGE_TYPE_WLAN_DATA);
1404   wlanheader->sender = *plugin->env->my_identity;
1405   wlanheader->target = session->target;
1406   wlanheader->crc = htonl (GNUNET_CRYPTO_crc32_n (msgbuf, msgbuf_size));
1407   memcpy (&wlanheader[1],
1408           msgbuf,
1409           msgbuf_size);
1410   GNUNET_STATISTICS_update (plugin->env->stats,
1411                             "# bytes currently in buffers",
1412                             msgbuf_size,
1413                             GNUNET_NO);
1414   send_with_fragmentation (session->mac,
1415                            to,
1416                            &session->target,
1417                            &wlanheader->header,
1418                            msgbuf_size,
1419                            cont, cont_cls);
1420   return size;
1421 }
1422
1423
1424 /**
1425  * We have received data from the WLAN via some session.  Process depending
1426  * on the message type (HELLO, DATA, FRAGMENTATION or FRAGMENTATION-ACK).
1427  *
1428  * @param cls pointer to the plugin
1429  * @param client pointer to the session this message belongs to
1430  * @param hdr start of the message
1431  */
1432 static int
1433 process_data (void *cls,
1434               void *client,
1435               const struct GNUNET_MessageHeader *hdr)
1436 {
1437   struct Plugin *plugin = cls;
1438   struct GNUNET_HELLO_Address *address;
1439   struct MacAndSession *mas = client;
1440   struct FragmentMessage *fm;
1441   struct GNUNET_PeerIdentity tmpsource;
1442   const struct WlanHeader *wlanheader;
1443   int ret;
1444   uint16_t msize;
1445
1446   msize = ntohs (hdr->size);
1447
1448   GNUNET_STATISTICS_update (plugin->env->stats,
1449                             "# bytes received",
1450                             msize, GNUNET_NO);
1451
1452   switch (ntohs (hdr->type))
1453   {
1454   case GNUNET_MESSAGE_TYPE_HELLO:
1455
1456     if (GNUNET_OK !=
1457         GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) hdr,
1458                              &tmpsource))
1459     {
1460       GNUNET_break_op (0);
1461       break;
1462     }
1463     if (NULL == mas->endpoint)
1464     {
1465       GNUNET_break (0);
1466       break;
1467     }
1468
1469     LOG (GNUNET_ERROR_TYPE_DEBUG,
1470          "Processing %u bytes of HELLO from peer `%s' at MAC %s\n",
1471          (unsigned int) msize,
1472          GNUNET_i2s (&tmpsource),
1473          wlan_plugin_address_to_string (NULL,
1474                                         &mas->endpoint->wlan_addr,
1475                                         sizeof (mas->endpoint->wlan_addr)));
1476
1477     GNUNET_STATISTICS_update (plugin->env->stats,
1478                               _("# HELLO messages received"), 1,
1479                               GNUNET_NO);
1480     address = GNUNET_HELLO_address_allocate (&tmpsource,
1481                                              PLUGIN_NAME,
1482                                              &mas->endpoint->wlan_addr,
1483                                              sizeof (mas->endpoint->wlan_addr),
1484                                              GNUNET_HELLO_ADDRESS_INFO_NONE);
1485     mas->session = lookup_session (mas->endpoint,
1486                                    &tmpsource);
1487     if (NULL == mas->session)
1488     {
1489       mas->session = create_session (mas->endpoint,
1490                                      &tmpsource);
1491       plugin->env->session_start (plugin->env->cls,
1492                                   address,
1493                                   mas->session,
1494                                   scope);
1495     }
1496     plugin->env->receive (plugin->env->cls,
1497                           address,
1498                           mas->session,
1499                           hdr);
1500     GNUNET_HELLO_address_free (address);
1501     break;
1502   case GNUNET_MESSAGE_TYPE_FRAGMENT:
1503     if (NULL == mas->endpoint)
1504     {
1505       GNUNET_break (0);
1506       break;
1507     }
1508     LOG (GNUNET_ERROR_TYPE_DEBUG,
1509          "Processing %u bytes of FRAGMENT from MAC %s\n",
1510          (unsigned int) msize,
1511          wlan_plugin_address_to_string (NULL,
1512                                         &mas->endpoint->wlan_addr,
1513                                         sizeof (mas->endpoint->wlan_addr)));
1514     GNUNET_STATISTICS_update (plugin->env->stats,
1515                               _("# fragments received"),
1516                               1,
1517                               GNUNET_NO);
1518     (void) GNUNET_DEFRAGMENT_process_fragment (mas->endpoint->defrag,
1519                                               hdr);
1520     break;
1521   case GNUNET_MESSAGE_TYPE_FRAGMENT_ACK:
1522     if (NULL == mas->endpoint)
1523     {
1524       GNUNET_break (0);
1525       break;
1526     }
1527     GNUNET_STATISTICS_update (plugin->env->stats,
1528                               _("# ACKs received"),
1529                               1, GNUNET_NO);
1530     for (fm = mas->endpoint->sending_messages_head; NULL != fm; fm = fm->next)
1531     {
1532       ret = GNUNET_FRAGMENT_process_ack (fm->fragcontext, hdr);
1533       if (GNUNET_OK == ret)
1534       {
1535         LOG (GNUNET_ERROR_TYPE_DEBUG,
1536              "Got last ACK, finished message transmission to `%s' (%p)\n",
1537              wlan_plugin_address_to_string (NULL,
1538                                             &mas->endpoint->wlan_addr,
1539                                             sizeof (mas->endpoint->wlan_addr)),
1540              fm);
1541         mas->endpoint->timeout = GNUNET_TIME_relative_to_absolute (MACENDPOINT_TIMEOUT);
1542         if (NULL != fm->cont)
1543         {
1544           fm->cont (fm->cont_cls,
1545                     &fm->target,
1546                     GNUNET_OK,
1547                     fm->size_payload,
1548                     fm->size_on_wire);
1549           fm->cont = NULL;
1550         }
1551         free_fragment_message (fm);
1552         break;
1553       }
1554       if (GNUNET_NO == ret)
1555       {
1556         LOG (GNUNET_ERROR_TYPE_DEBUG,
1557              "Got an ACK, message transmission to `%s' not yet finished\n",
1558              wlan_plugin_address_to_string (NULL,
1559                                             &mas->endpoint->wlan_addr,
1560                                             sizeof (mas->endpoint->wlan_addr)));
1561         break;
1562       }
1563     }
1564     if (NULL == fm)
1565       LOG (GNUNET_ERROR_TYPE_DEBUG,
1566            "ACK not matched against any active fragmentation with MAC `%s'\n",
1567            wlan_plugin_address_to_string (NULL,
1568                                           &mas->endpoint->wlan_addr,
1569                                           sizeof (mas->endpoint->wlan_addr)));
1570     break;
1571   case GNUNET_MESSAGE_TYPE_WLAN_DATA:
1572     if (NULL == mas->endpoint)
1573     {
1574       GNUNET_break (0);
1575       break;
1576     }
1577     if (msize < sizeof (struct WlanHeader))
1578     {
1579       GNUNET_break (0);
1580       break;
1581     }
1582     wlanheader = (const struct WlanHeader *) hdr;
1583     if (0 != memcmp (&wlanheader->target,
1584                      plugin->env->my_identity,
1585                      sizeof (struct GNUNET_PeerIdentity)))
1586     {
1587       LOG (GNUNET_ERROR_TYPE_DEBUG,
1588            "Data for `%s', not for me, ignoring\n",
1589            GNUNET_i2s (&wlanheader->target));
1590       break;
1591     }
1592     if (ntohl (wlanheader->crc) !=
1593         GNUNET_CRYPTO_crc32_n (&wlanheader[1],
1594                                msize - sizeof (struct WlanHeader)))
1595     {
1596       GNUNET_STATISTICS_update (plugin->env->stats,
1597                                 _("# DATA messages discarded due to CRC32 error"),
1598                                 1,
1599                                 GNUNET_NO);
1600       break;
1601     }
1602     mas->session = lookup_session (mas->endpoint,
1603                                    &wlanheader->sender);
1604     if (NULL == mas->session)
1605     {
1606       mas->session = create_session (mas->endpoint,
1607                                      &wlanheader->sender);
1608       address = GNUNET_HELLO_address_allocate (&wlanheader->sender,
1609                                                PLUGIN_NAME,
1610                                                &mas->endpoint->wlan_addr,
1611                                                sizeof (struct WlanAddress),
1612                                                GNUNET_HELLO_ADDRESS_INFO_NONE);
1613       plugin->env->session_start (plugin->env->cls,
1614                                   address,
1615                                   mas->session,
1616                                   scope);
1617       LOG (GNUNET_ERROR_TYPE_DEBUG,
1618            "Notifying transport about peer `%s''s new session %p \n",
1619            GNUNET_i2s (&wlanheader->sender),
1620            mas->session);
1621       GNUNET_HELLO_address_free (address);
1622     }
1623     LOG (GNUNET_ERROR_TYPE_DEBUG,
1624          "Processing %u bytes of DATA from peer `%s'\n",
1625          (unsigned int) msize,
1626          GNUNET_i2s (&wlanheader->sender));
1627     mas->session->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1628     (void) GNUNET_SERVER_mst_receive (plugin->wlan_header_payload_tokenizer,
1629                                       mas,
1630                                       (const char *) &wlanheader[1],
1631                                       msize - sizeof (struct WlanHeader),
1632                                       GNUNET_YES,
1633                                       GNUNET_NO);
1634     break;
1635   default:
1636     if (NULL == mas->endpoint)
1637     {
1638       GNUNET_break (0);
1639       break;
1640     }
1641     if (NULL == mas->session)
1642     {
1643       GNUNET_break (0);
1644       break;
1645     }
1646     LOG (GNUNET_ERROR_TYPE_DEBUG,
1647          "Received packet with %u bytes of type %u from peer %s\n",
1648          (unsigned int) msize,
1649          (unsigned int) ntohs (hdr->type),
1650          GNUNET_i2s (&mas->session->target));
1651     plugin->env->receive (plugin->env->cls,
1652                           mas->session->address,
1653                           mas->session,
1654                           hdr);
1655     break;
1656   }
1657   return GNUNET_OK;
1658 }
1659
1660
1661 /**
1662  * Task to (periodically) send a HELLO beacon
1663  *
1664  * @param cls pointer to the plugin struct
1665  * @param tc scheduler context
1666  */
1667 static void
1668 send_hello_beacon (void *cls,
1669                    const struct GNUNET_SCHEDULER_TaskContext *tc)
1670 {
1671   struct Plugin *plugin = cls;
1672   uint16_t size;
1673   uint16_t hello_size;
1674   struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *radioHeader;
1675   const struct GNUNET_MessageHeader *hello;
1676
1677   hello = plugin->env->get_our_hello ();
1678   if (NULL != hello)
1679   {
1680     hello_size = GNUNET_HELLO_size ((struct GNUNET_HELLO_Message *) hello);
1681     GNUNET_assert (sizeof (struct WlanHeader) + hello_size <= WLAN_MTU);
1682     size = sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage) + hello_size;
1683   {
1684     char buf[size] GNUNET_ALIGN;
1685
1686     LOG (GNUNET_ERROR_TYPE_DEBUG,
1687          "Sending %u byte HELLO beacon\n",
1688          (unsigned int) size);
1689     radioHeader = (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage*) buf;
1690     get_radiotap_header (NULL, radioHeader, size);
1691     LOG (GNUNET_ERROR_TYPE_DEBUG,
1692          "Broadcasting %u bytes of data to MAC `%s'\n",
1693          (unsigned int) size,
1694          mac_to_string (&bc_all_mac));
1695     get_wlan_header (plugin, &radioHeader->frame, &bc_all_mac, size);
1696     memcpy (&radioHeader[1], hello, hello_size);
1697     if (NULL !=
1698         GNUNET_HELPER_send (plugin->suid_helper,
1699                             &radioHeader->header,
1700                             GNUNET_YES /* can drop */,
1701                             NULL, NULL))
1702       GNUNET_STATISTICS_update (plugin->env->stats,
1703                                 _("# HELLO beacons sent"),
1704                                 1, GNUNET_NO);
1705   } }
1706   plugin->beacon_task =
1707     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
1708                                   (HELLO_BEACON_SCALING_FACTOR,
1709                                    plugin->mac_count + 1),
1710                                   &send_hello_beacon,
1711                                   plugin);
1712
1713 }
1714
1715
1716 /**
1717  * Function used for to process the data from the suid process
1718  *
1719  * @param cls the plugin handle
1720  * @param client client that send the data (not used)
1721  * @param hdr header of the GNUNET_MessageHeader
1722  */
1723 static int
1724 handle_helper_message (void *cls, void *client,
1725                        const struct GNUNET_MessageHeader *hdr)
1726 {
1727   struct Plugin *plugin = cls;
1728   struct GNUNET_HELLO_Address *my_address;
1729   const struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *rxinfo;
1730   const struct GNUNET_TRANSPORT_WLAN_HelperControlMessage *cm;
1731   struct WlanAddress wa;
1732   struct MacAndSession mas;
1733   uint16_t msize;
1734   struct FragmentMessage *fm;
1735   struct MacEndpoint *endpoint;
1736
1737   msize = ntohs (hdr->size);
1738   switch (ntohs (hdr->type))
1739   {
1740   case GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL:
1741     if (msize != sizeof (struct GNUNET_TRANSPORT_WLAN_HelperControlMessage))
1742     {
1743       GNUNET_break (0);
1744       break;
1745     }
1746     cm = (const struct GNUNET_TRANSPORT_WLAN_HelperControlMessage *) hdr;
1747     if (GNUNET_YES == plugin->have_mac)
1748     {
1749       if (0 == memcmp (&plugin->mac_address,
1750                        &cm->mac,
1751                        sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)))
1752         break; /* no change */
1753       /* remove old address */
1754       memset (&wa, 0, sizeof (struct WlanAddress));
1755       wa.mac = plugin->mac_address;
1756       wa.options = htonl(plugin->options);
1757       my_address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
1758                                                   PLUGIN_NAME,
1759                                                   &wa, sizeof (wa),
1760                                                   GNUNET_HELLO_ADDRESS_INFO_NONE);
1761       plugin->env->notify_address (plugin->env->cls,
1762                                    GNUNET_NO,
1763                                    my_address);
1764       GNUNET_HELLO_address_free (my_address);
1765       plugin->mac_address = cm->mac;
1766     }
1767     else
1768     {
1769       plugin->mac_address = cm->mac;
1770       plugin->have_mac = GNUNET_YES;
1771       for (endpoint = plugin->mac_head; NULL != endpoint; endpoint = endpoint->next)
1772       {
1773         for (fm = endpoint->sending_messages_head; NULL != fm; fm = fm->next)
1774         {
1775           if (NULL != fm->fragcontext)
1776           {
1777             GNUNET_break (0); /* should not happen */
1778             continue;
1779           }
1780           fm->fragcontext =
1781             GNUNET_FRAGMENT_context_create (plugin->env->stats,
1782                                             WLAN_MTU,
1783                                             &plugin->tracker,
1784                                             fm->macendpoint->msg_delay,
1785                                             fm->macendpoint->ack_delay,
1786                                             fm->msg,
1787                                             &transmit_fragment, fm);
1788           GNUNET_free (fm->msg);
1789           fm->msg = NULL;
1790         }
1791       }
1792       GNUNET_break (NULL == plugin->beacon_task);
1793       plugin->beacon_task = GNUNET_SCHEDULER_add_now (&send_hello_beacon,
1794                                                       plugin);
1795
1796     }
1797
1798     memset (&wa, 0, sizeof (struct WlanAddress));
1799     wa.mac = plugin->mac_address;
1800     wa.options = htonl(plugin->options);
1801     my_address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
1802                                                 PLUGIN_NAME,
1803                                                 &wa, sizeof (wa),
1804                                                 GNUNET_HELLO_ADDRESS_INFO_NONE);
1805
1806     LOG (GNUNET_ERROR_TYPE_DEBUG,
1807          "Received WLAN_HELPER_CONTROL message with MAC address `%s' for peer `%s'\n",
1808          mac_to_string (&cm->mac),
1809          GNUNET_i2s (plugin->env->my_identity));
1810     plugin->env->notify_address (plugin->env->cls,
1811                                  GNUNET_YES,
1812                                  my_address);
1813     GNUNET_HELLO_address_free (my_address);
1814     break;
1815   case GNUNET_MESSAGE_TYPE_WLAN_DATA_FROM_HELPER:
1816     LOG (GNUNET_ERROR_TYPE_DEBUG,
1817          "Got data message from helper with %u bytes\n",
1818          msize);
1819     GNUNET_STATISTICS_update (plugin->env->stats,
1820                               _("# DATA messages received"), 1,
1821                               GNUNET_NO);
1822     if (msize < sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage))
1823     {
1824       LOG (GNUNET_ERROR_TYPE_DEBUG,
1825            "Size of packet is too small (%u bytes < %u)\n",
1826            msize,  sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage));
1827       break;
1828     }
1829     rxinfo = (const struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *) hdr;
1830
1831     /* check if message is actually for us */
1832     if (0 != memcmp (&rxinfo->frame.addr3, &mac_bssid_gnunet,
1833                      sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)))
1834     {
1835       /* Not the GNUnet BSSID */
1836       break;
1837     }
1838     if ( (0 != memcmp (&rxinfo->frame.addr1, &bc_all_mac,
1839                        sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress))) &&
1840          (0 != memcmp (&rxinfo->frame.addr1, &plugin->mac_address,
1841                        sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress))) )
1842     {
1843       /* Neither broadcast nor specifically for us */
1844       break;
1845     }
1846     if (0 == memcmp (&rxinfo->frame.addr2, &plugin->mac_address,
1847                      sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)))
1848     {
1849       /* packet is FROM us, thus not FOR us */
1850       break;
1851     }
1852
1853     GNUNET_STATISTICS_update (plugin->env->stats,
1854                               _("# DATA messages processed"),
1855                               1, GNUNET_NO);
1856     LOG (GNUNET_ERROR_TYPE_DEBUG,
1857          "Receiving %u bytes of data from MAC `%s'\n",
1858          (unsigned int) (msize - sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)),
1859          mac_to_string (&rxinfo->frame.addr2));
1860     LOG (GNUNET_ERROR_TYPE_DEBUG,
1861          "Receiving %u bytes of data to MAC `%s'\n",
1862          (unsigned int) (msize - sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)),
1863          mac_to_string (&rxinfo->frame.addr1));
1864     LOG (GNUNET_ERROR_TYPE_DEBUG,
1865          "Receiving %u bytes of data with BSSID MAC `%s'\n",
1866          (unsigned int) (msize - sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)),
1867          mac_to_string (&rxinfo->frame.addr3));
1868     wa.mac = rxinfo->frame.addr2;
1869     wa.options = htonl (0);
1870     mas.endpoint = create_macendpoint (plugin, &wa);
1871     mas.session = NULL;
1872     (void) GNUNET_SERVER_mst_receive (plugin->helper_payload_tokenizer,
1873                                       &mas,
1874                                       (const char*) &rxinfo[1],
1875                                       msize - sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage),
1876                                       GNUNET_YES, GNUNET_NO);
1877     break;
1878   default:
1879     GNUNET_break (0);
1880     LOG (GNUNET_ERROR_TYPE_DEBUG,
1881          "Unexpected message of type %u (%u bytes)",
1882          ntohs (hdr->type), ntohs (hdr->size));
1883     break;
1884   }
1885   return GNUNET_OK;
1886 }
1887
1888
1889 /**
1890  * Another peer has suggested an address for this
1891  * peer and transport plugin.  Check that this could be a valid
1892  * address.  If so, consider adding it to the list
1893  * of addresses.
1894  *
1895  * @param cls closure
1896  * @param addr pointer to the address
1897  * @param addrlen length of @a addr
1898  * @return #GNUNET_OK if this is a plausible address for this peer
1899  *         and transport
1900  */
1901 static int
1902 wlan_plugin_address_suggested (void *cls,
1903                                const void *addr,
1904                                size_t addrlen)
1905 {
1906   struct Plugin *plugin = cls;
1907   struct WlanAddress *wa = (struct WlanAddress *) addr;
1908
1909   if (addrlen != sizeof (struct WlanAddress))
1910   {
1911     GNUNET_break_op (0);
1912     return GNUNET_SYSERR;
1913   }
1914   if (GNUNET_YES != plugin->have_mac)
1915   {
1916     LOG (GNUNET_ERROR_TYPE_DEBUG,
1917          "Rejecting MAC `%s': I don't know my MAC!\n",
1918          mac_to_string (addr));
1919     return GNUNET_NO; /* don't know my MAC */
1920   }
1921   if (0 != memcmp (&wa->mac,
1922                    &plugin->mac_address,
1923                    sizeof (wa->mac)))
1924   {
1925     LOG (GNUNET_ERROR_TYPE_DEBUG,
1926          "Rejecting MAC `%s': not my MAC!\n",
1927          mac_to_string (addr));
1928     return GNUNET_NO; /* not my MAC */
1929   }
1930   return GNUNET_OK;
1931 }
1932
1933
1934 /**
1935  * Convert the transports address to a nice, human-readable format.
1936  *
1937  * @param cls closure
1938  * @param type name of the transport that generated the address
1939  * @param addr one of the addresses of the host, NULL for the last address
1940  *        the specific address format depends on the transport
1941  * @param addrlen length of the address
1942  * @param numeric should (IP) addresses be displayed in numeric form?
1943  * @param timeout after how long should we give up?
1944  * @param asc function to call on each string
1945  * @param asc_cls closure for @a asc
1946  */
1947 static void
1948 wlan_plugin_address_pretty_printer (void *cls,
1949                                     const char *type,
1950                                     const void *addr,
1951                                     size_t addrlen,
1952                                     int numeric,
1953                                     struct GNUNET_TIME_Relative timeout,
1954                                     GNUNET_TRANSPORT_AddressStringCallback asc,
1955                                     void *asc_cls)
1956 {
1957   const char *ret;
1958
1959   if (sizeof (struct WlanAddress) == addrlen)
1960     ret = wlan_plugin_address_to_string (NULL,
1961                                          addr,
1962                                          addrlen);
1963   else
1964     ret = NULL;
1965   asc (asc_cls,
1966        ret,
1967        (NULL == ret) ? GNUNET_SYSERR : GNUNET_OK);
1968   asc (asc_cls, NULL, GNUNET_OK);
1969 }
1970
1971
1972 /**
1973  * Exit point from the plugin.
1974  *
1975  * @param cls pointer to the api struct
1976  */
1977 void *
1978 LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls)
1979 {
1980   struct WlanAddress wa;
1981   struct GNUNET_HELLO_Address *address;
1982   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
1983   struct Plugin *plugin = api->cls;
1984   struct MacEndpoint *endpoint;
1985   struct MacEndpoint *endpoint_next;
1986
1987   if (NULL == plugin)
1988   {
1989     GNUNET_free (api);
1990     return NULL;
1991   }
1992   if (GNUNET_YES == plugin->have_mac)
1993   {
1994     memset (&wa, 0, sizeof(wa));
1995     wa.options = htonl (plugin->options);
1996     wa.mac = plugin->mac_address;
1997     address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
1998                                              PLUGIN_NAME,
1999                                              &wa, sizeof (struct WlanAddress),
2000                                              GNUNET_HELLO_ADDRESS_INFO_NONE);
2001
2002     plugin->env->notify_address (plugin->env->cls,
2003                                  GNUNET_NO,
2004                                  address);
2005     plugin->have_mac = GNUNET_NO;
2006     GNUNET_HELLO_address_free (address);
2007   }
2008
2009   if (NULL != plugin->beacon_task)
2010   {
2011     GNUNET_SCHEDULER_cancel (plugin->beacon_task);
2012     plugin->beacon_task = NULL;
2013   }
2014   if (NULL != plugin->suid_helper)
2015   {
2016     GNUNET_HELPER_stop (plugin->suid_helper,
2017                         GNUNET_NO);
2018     plugin->suid_helper = NULL;
2019   }
2020   endpoint_next = plugin->mac_head;
2021   while (NULL != (endpoint = endpoint_next))
2022   {
2023     endpoint_next = endpoint->next;
2024     free_macendpoint (endpoint);
2025   }
2026   if (NULL != plugin->fragment_data_tokenizer)
2027   {
2028     GNUNET_SERVER_mst_destroy (plugin->fragment_data_tokenizer);
2029     plugin->fragment_data_tokenizer = NULL;
2030   }
2031   if (NULL != plugin->wlan_header_payload_tokenizer)
2032   {
2033     GNUNET_SERVER_mst_destroy (plugin->wlan_header_payload_tokenizer);
2034     plugin->wlan_header_payload_tokenizer = NULL;
2035   }
2036   if (NULL != plugin->helper_payload_tokenizer)
2037   {
2038     GNUNET_SERVER_mst_destroy (plugin->helper_payload_tokenizer);
2039     plugin->helper_payload_tokenizer = NULL;
2040   }
2041   GNUNET_free_non_null (plugin->wlan_interface);
2042   GNUNET_free (plugin);
2043   GNUNET_free (api);
2044   return NULL;
2045 }
2046
2047
2048 /**
2049  * Function called to convert a string address to
2050  * a binary address.
2051  *
2052  * @param cls closure (`struct Plugin *`)
2053  * @param addr string address
2054  * @param addrlen length of the address
2055  * @param buf location to store the buffer
2056  * @param added location to store the number of bytes in the buffer.
2057  *        If the function returns #GNUNET_SYSERR, its contents are undefined.
2058  * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
2059  */
2060 static int
2061 wlan_plugin_string_to_address (void *cls,
2062                                const char *addr,
2063                                uint16_t addrlen,
2064                                void **buf,
2065                                size_t *added)
2066 {
2067   struct WlanAddress *wa;
2068   unsigned int a[6];
2069   unsigned int i;
2070   char plugin[5];
2071   uint32_t options;
2072
2073   if ((NULL == addr) || (0 == addrlen))
2074   {
2075     GNUNET_break (0);
2076     return GNUNET_SYSERR;
2077   }
2078   if ('\0' != addr[addrlen - 1])
2079   {
2080     GNUNET_break (0);
2081     return GNUNET_SYSERR;
2082   }
2083   if (strlen (addr) != addrlen - 1)
2084   {
2085     GNUNET_break (0);
2086     return GNUNET_SYSERR;
2087   }
2088
2089   if (8 != SSCANF (addr,
2090                    "%4s.%u.%X:%X:%X:%X:%X:%X",
2091                    plugin, &options,
2092                    &a[0], &a[1], &a[2],
2093                    &a[3], &a[4], &a[5]))
2094   {
2095     GNUNET_break (0);
2096     return GNUNET_SYSERR;
2097   }
2098   wa = GNUNET_new (struct WlanAddress);
2099   for (i=0;i<6;i++)
2100     wa->mac.mac[i] = a[i];
2101   wa->options = htonl (0);
2102   *buf = wa;
2103   *added = sizeof (struct WlanAddress);
2104   return GNUNET_OK;
2105 }
2106
2107
2108 /**
2109  * Begin monitoring sessions of a plugin.  There can only
2110  * be one active monitor per plugin (i.e. if there are
2111  * multiple monitors, the transport service needs to
2112  * multiplex the generated events over all of them).
2113  *
2114  * @param cls closure of the plugin
2115  * @param sic callback to invoke, NULL to disable monitor;
2116  *            plugin will being by iterating over all active
2117  *            sessions immediately and then enter monitor mode
2118  * @param sic_cls closure for @a sic
2119  */
2120 static void
2121 wlan_plugin_setup_monitor (void *cls,
2122                            GNUNET_TRANSPORT_SessionInfoCallback sic,
2123                            void *sic_cls)
2124 {
2125   struct Plugin *plugin = cls;
2126   struct MacEndpoint *mac;
2127   struct Session *session;
2128
2129   plugin->sic = sic;
2130   plugin->sic_cls = sic_cls;
2131   if (NULL != sic)
2132   {
2133     for (mac = plugin->mac_head; NULL != mac; mac = mac->next)
2134       for (session = mac->sessions_head; NULL != session; session = session->next)
2135       {
2136         notify_session_monitor (plugin,
2137                                 session,
2138                                 GNUNET_TRANSPORT_SS_INIT);
2139         notify_session_monitor (plugin,
2140                                 session,
2141                                 GNUNET_TRANSPORT_SS_UP);
2142       }
2143     sic (sic_cls, NULL, NULL);
2144   }
2145 }
2146
2147
2148
2149 /**
2150  * Function that will be called whenever the transport service wants to
2151  * notify the plugin that a session is still active and in use and
2152  * therefore the session timeout for this session has to be updated
2153  *
2154  * @param cls closure
2155  * @param peer which peer was the session for
2156  * @param session which session is being updated
2157  */
2158 static void
2159 wlan_plugin_update_session_timeout (void *cls,
2160                                     const struct GNUNET_PeerIdentity *peer,
2161                                     struct Session *session)
2162 {
2163   GNUNET_assert (NULL != session->timeout_task);
2164   session->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2165 }
2166
2167
2168 /**
2169  * Function that will be called whenever the transport service wants to
2170  * notify the plugin that the inbound quota changed and that the plugin
2171  * should update it's delay for the next receive value
2172  *
2173  * @param cls closure
2174  * @param peer which peer was the session for
2175  * @param session which session is being updated
2176  * @param delay new delay to use for receiving
2177  */
2178 static void
2179 wlan_plugin_update_inbound_delay (void *cls,
2180                                   const struct GNUNET_PeerIdentity *peer,
2181                                   struct Session *session,
2182                                   struct GNUNET_TIME_Relative delay)
2183 {
2184   /* does nothing, as inbound delay is not supported by WLAN */
2185 }
2186
2187
2188 /**
2189  * Entry point for the plugin.
2190  *
2191  * @param cls closure, the `struct GNUNET_TRANSPORT_PluginEnvironment *`
2192  * @return the `struct GNUNET_TRANSPORT_PluginFunctions *` or NULL on error
2193  */
2194 void *
2195 LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls)
2196 {
2197   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
2198   struct GNUNET_TRANSPORT_PluginFunctions *api;
2199   struct Plugin *plugin;
2200   char *wlan_interface;
2201   unsigned long long testmode;
2202   char *binary;
2203
2204   /* check for 'special' mode */
2205   if (NULL == env->receive)
2206   {
2207     /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
2208        initialze the plugin or the API */
2209     api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
2210     api->cls = NULL;
2211     api->address_pretty_printer = &wlan_plugin_address_pretty_printer;
2212     api->address_to_string = &wlan_plugin_address_to_string;
2213     api->string_to_address = &wlan_plugin_string_to_address;
2214     return api;
2215   }
2216
2217   testmode = 0;
2218   /* check configuration */
2219   if ( (GNUNET_YES ==
2220         GNUNET_CONFIGURATION_have_value (env->cfg,
2221                                          CONFIG_NAME,
2222                                          "TESTMODE")) &&
2223        ( (GNUNET_SYSERR ==
2224           GNUNET_CONFIGURATION_get_value_number (env->cfg,
2225                                                  CONFIG_NAME,
2226                                                  "TESTMODE",
2227                                                  &testmode)) ||
2228          (testmode > 2) ) )
2229   {
2230     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
2231                                CONFIG_NAME,
2232                                "TESTMODE");
2233     return NULL;
2234   }
2235   binary = GNUNET_OS_get_libexec_binary_path (HELPER_NAME);
2236   if ( (0 == testmode) &&
2237        (GNUNET_YES !=
2238         GNUNET_OS_check_helper_binary (binary,
2239                                        GNUNET_YES,
2240                                        NULL)) )
2241   {
2242     LOG (GNUNET_ERROR_TYPE_ERROR,
2243          _("Helper binary `%s' not SUID, cannot run WLAN transport\n"),
2244          HELPER_NAME);
2245     GNUNET_free (binary);
2246     return NULL;
2247   }
2248     GNUNET_free (binary);
2249   if (GNUNET_YES !=
2250       GNUNET_CONFIGURATION_get_value_string (env->cfg,
2251                                              CONFIG_NAME,
2252                                              "INTERFACE",
2253                                              &wlan_interface))
2254   {
2255     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
2256                                CONFIG_NAME,
2257                                "INTERFACE");
2258     return NULL;
2259   }
2260
2261   plugin = GNUNET_new (struct Plugin);
2262   plugin->wlan_interface = wlan_interface;
2263   plugin->env = env;
2264   GNUNET_STATISTICS_set (plugin->env->stats,
2265                          _("# sessions allocated"),
2266                          0, GNUNET_NO);
2267   GNUNET_STATISTICS_set (plugin->env->stats,
2268                          _("# MAC endpoints allocated"),
2269                          0, 0);
2270   GNUNET_BANDWIDTH_tracker_init (&plugin->tracker, NULL, NULL,
2271                                  GNUNET_BANDWIDTH_value_init (100 * 1024 *
2272                                                               1024 / 8),
2273                                  100);
2274   plugin->fragment_data_tokenizer = GNUNET_SERVER_mst_create (&process_data,
2275                                                               plugin);
2276   plugin->wlan_header_payload_tokenizer = GNUNET_SERVER_mst_create (&process_data,
2277                                                                     plugin);
2278   plugin->helper_payload_tokenizer = GNUNET_SERVER_mst_create (&process_data,
2279                                                                plugin);
2280
2281   plugin->options = 0;
2282
2283   /* some compilers do not like switch on 'long long'... */
2284   switch ((unsigned int) testmode)
2285   {
2286   case 0: /* normal */
2287     plugin->helper_argv[0] = (char *) HELPER_NAME;
2288     plugin->helper_argv[1] = wlan_interface;
2289     plugin->helper_argv[2] = NULL;
2290     plugin->suid_helper = GNUNET_HELPER_start (GNUNET_NO,
2291                                                HELPER_NAME,
2292                                                plugin->helper_argv,
2293                                                &handle_helper_message,
2294                                                NULL,
2295                                                plugin);
2296     break;
2297   case 1: /* testmode, peer 1 */
2298     plugin->helper_argv[0] = (char *) DUMMY_HELPER_NAME;
2299     plugin->helper_argv[1] = (char *) "1";
2300     plugin->helper_argv[2] = NULL;
2301     plugin->suid_helper = GNUNET_HELPER_start (GNUNET_NO,
2302                                                DUMMY_HELPER_NAME,
2303                                                plugin->helper_argv,
2304                                                &handle_helper_message,
2305                                                NULL,
2306                                                plugin);
2307     break;
2308   case 2: /* testmode, peer 2 */
2309     plugin->helper_argv[0] = (char *) DUMMY_HELPER_NAME;
2310     plugin->helper_argv[1] = (char *) "2";
2311     plugin->helper_argv[2] = NULL;
2312     plugin->suid_helper = GNUNET_HELPER_start (GNUNET_NO,
2313                                                DUMMY_HELPER_NAME,
2314                                                plugin->helper_argv,
2315                                                &handle_helper_message,
2316                                                NULL,
2317                                                plugin);
2318     break;
2319   default:
2320     GNUNET_assert (0);
2321   }
2322
2323   api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
2324   api->cls = plugin;
2325   api->send = &wlan_plugin_send;
2326   api->get_session = &wlan_plugin_get_session;
2327   api->disconnect_peer = &wlan_plugin_disconnect_peer;
2328   api->disconnect_session = &wlan_plugin_disconnect_session;
2329   api->query_keepalive_factor = &wlan_plugin_query_keepalive_factor;
2330   api->address_pretty_printer = &wlan_plugin_address_pretty_printer;
2331   api->check_address = &wlan_plugin_address_suggested;
2332   api->address_to_string = &wlan_plugin_address_to_string;
2333   api->string_to_address = &wlan_plugin_string_to_address;
2334   api->get_network = &wlan_plugin_get_network;
2335   api->update_session_timeout = &wlan_plugin_update_session_timeout;
2336   api->update_inbound_delay = &wlan_plugin_update_inbound_delay;
2337   api->setup_monitor = &wlan_plugin_setup_monitor;
2338   return api;
2339 }
2340
2341
2342 /* end of plugin_transport_wlan.c */