73d80c65590e173de258e464e44772093f30b14d
[oweals/gnunet.git] / src / transport / plugin_transport_wlan.c
1 /*
2   This file is part of GNUnet
3   (C) 2010, 2011, 2012 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
24  * @author David Brodski
25  * @author Christian Grothoff
26  */
27 #include "platform.h"
28 #include "gnunet_hello_lib.h"
29 #include "gnunet_protocols.h"
30 #include "gnunet_util_lib.h"
31 #include "gnunet_statistics_service.h"
32 #include "gnunet_transport_service.h"
33 #include "gnunet_transport_plugin.h"
34 #include "plugin_transport_wlan.h"
35 #include "gnunet_common.h"
36 #include "gnunet_crypto_lib.h"
37 #include "gnunet_fragmentation_lib.h"
38 #include "gnunet_constants.h"
39
40 #define LOG(kind,...) GNUNET_log_from (kind, "transport-wlan",__VA_ARGS__)
41
42 #define PLUGIN_NAME "wlan"
43
44 /**
45  * Max size of packet (that we give to the WLAN driver for transmission)
46  */
47 #define WLAN_MTU 1430
48
49 /**
50  * time out of a mac endpoint
51  */
52 #define MACENDPOINT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, 2)
53
54 /**
55  * We reduce the frequence of HELLO beacons in relation to
56  * the number of MAC addresses currently visible to us.
57  * This is the multiplication factor.
58  */
59 #define HELLO_BEACON_SCALING_FACTOR GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2)
60
61 /**
62  * Maximum number of messages in defragmentation queue per MAC
63  */
64 #define MESSAGES_IN_DEFRAG_QUEUE_PER_MAC 2
65
66 /**
67  * Link layer control fields for better compatibility
68  * (i.e. GNUnet over WLAN is not IP-over-WLAN).
69  */
70 #define WLAN_LLC_DSAP_FIELD 0x1f
71 #define WLAN_LLC_SSAP_FIELD 0x1f
72
73
74 GNUNET_NETWORK_STRUCT_BEGIN
75 /**
76  * Header for messages which need fragmentation.  This is the format of
77  * a message we obtain AFTER defragmentation.  We then need to check
78  * the CRC and then tokenize the payload and pass it to the 
79  * 'receive' callback.
80  */
81 struct WlanHeader
82 {
83
84   /**
85    * Message type is GNUNET_MESSAGE_TYPE_WLAN_DATA.
86    */
87   struct GNUNET_MessageHeader header;
88
89   /**
90    * CRC32 checksum (only over the payload), in NBO.
91    */
92   uint32_t crc GNUNET_PACKED;
93
94   /**
95    * Sender of the message.
96    */
97   struct GNUNET_PeerIdentity sender;
98
99   /**
100    * Target of the message.
101    */
102   struct GNUNET_PeerIdentity target;
103
104   /* followed by payload, possibly including
105      multiple messages! */
106
107 };
108
109
110 struct WlanAddress
111 {
112   uint32_t options GNUNET_PACKED;
113
114   struct GNUNET_TRANSPORT_WLAN_MacAddress mac;
115 };
116
117
118 GNUNET_NETWORK_STRUCT_END
119
120
121 /**
122  * Information kept for each message that is yet to be fragmented and
123  * transmitted.
124  */
125 struct PendingMessage
126 {
127   /**
128    * next entry in the DLL
129    */
130   struct PendingMessage *next;
131
132   /**
133    * previous entry in the DLL
134    */
135   struct PendingMessage *prev;
136
137   /**
138    * The pending message
139    */
140   struct WlanHeader *msg;
141
142   /**
143    * Continuation function to call once the message
144    * has been sent.  Can be NULL if there is no
145    * continuation to call.
146    */
147   GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
148
149   /**
150    * Cls for transmit_cont
151    */
152   void *transmit_cont_cls;
153
154   /**
155    * Timeout task (for this message).
156    */
157   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
158
159 };
160
161
162 /**
163  * Session handle for connections with other peers.
164  */
165 struct Session
166 {
167   /**
168    * To whom are we talking to (set to our identity
169    * if we are still waiting for the welcome message)
170    */
171   struct GNUNET_PeerIdentity target;
172
173   /**
174    * API requirement (must be first).
175    */
176   struct SessionHeader header;
177
178   /**
179    * We keep all sessions in a DLL at their respective
180    * 'struct MACEndpoint'.
181    */
182   struct Session *next;
183
184   /**
185    * We keep all sessions in a DLL at their respective
186    * 'struct MACEndpoint'.
187    */
188   struct Session *prev;
189
190   /**
191    * MAC endpoint with the address of this peer.
192    */
193   struct MacEndpoint *mac;
194
195   /**
196    * Head of messages currently pending for transmission to this peer.
197    */
198   struct PendingMessage *pending_message_head;
199
200   /**
201    * Tail of messages currently pending for transmission to this peer.
202    */
203   struct PendingMessage *pending_message_tail;
204
205   /**
206    * When should this session time out?
207    */
208   struct GNUNET_TIME_Absolute timeout;
209
210   /**
211    * Timeout task (for the session).
212    */
213   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
214
215 };
216
217
218 /**
219  * Struct for messages that are being fragmented in a MAC's transmission queue.
220  */
221 struct FragmentMessage
222 {
223
224   /**
225    * This is a doubly-linked list.
226    */
227   struct FragmentMessage *next;
228
229   /**
230    * This is a doubly-linked list.
231    */
232   struct FragmentMessage *prev;
233
234   /**
235    * MAC endpoint this message belongs to
236    */
237   struct MacEndpoint *macendpoint;
238
239   /**
240    * Fragmentation context
241    */
242   struct GNUNET_FRAGMENT_Context *fragcontext;
243
244   /**
245    * Transmission handle to helper (to cancel if the frag context
246    * is destroyed early for some reason).
247    */
248   struct GNUNET_HELPER_SendHandle *sh;
249
250   /**
251    * Intended recipient.
252    */
253   struct GNUNET_PeerIdentity target;
254
255   /**
256    * Timeout value for the message.
257    */
258   struct GNUNET_TIME_Absolute timeout;
259
260   /**
261    * Timeout task.
262    */
263   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
264
265   /**
266    * Continuation to call when we're done with this message.
267    */
268   GNUNET_TRANSPORT_TransmitContinuation cont;
269
270   /**
271    * Closure for 'cont'
272    */
273   void *cont_cls;
274
275   /**
276    * Size of original message
277    */
278   size_t size_payload;
279
280   /**
281    * Number of bytes used to transmit message
282    */
283   size_t size_on_wire;
284
285 };
286
287
288 /**
289  * Struct to represent one network card connection
290  */
291 struct MacEndpoint
292 {
293
294   /**
295    * We keep all MACs in a DLL in the plugin.
296    */
297   struct MacEndpoint *next;
298
299   /**
300    * We keep all MACs in a DLL in the plugin.
301    */
302   struct MacEndpoint *prev;
303
304   /**
305    * Pointer to the global plugin struct.
306    */
307   struct Plugin *plugin;
308
309   /**
310    * Head of sessions that use this MAC.
311    */
312   struct Session *sessions_head;
313
314   /**
315    * Tail of sessions that use this MAC.
316    */
317   struct Session *sessions_tail;
318
319   /**
320    * Head of messages we are currently sending to this MAC.
321    */
322   struct FragmentMessage *sending_messages_head;
323
324   /**
325    * Tail of messages we are currently sending to this MAC.
326    */
327   struct FragmentMessage *sending_messages_tail;
328
329   /**
330    * Defrag context for this MAC
331    */
332   struct GNUNET_DEFRAGMENT_Context *defrag;
333
334   /**
335    * When should this endpoint time out?
336    */
337   struct GNUNET_TIME_Absolute timeout;
338
339   /**
340    * Timeout task.
341    */
342   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
343
344   /**
345    * count of messages in the fragment out queue for this mac endpoint
346    */
347   unsigned int fragment_messages_out_count;
348
349   /**
350    * peer mac address
351    */
352   struct WlanAddress addr;
353
354   /**
355    * Message delay for fragmentation context
356    */
357   struct GNUNET_TIME_Relative msg_delay;
358
359   /**
360    * ACK delay for fragmentation context
361    */
362   struct GNUNET_TIME_Relative ack_delay;
363
364   /**
365    * Desired transmission power for this MAC
366    */
367   uint16_t tx_power;
368
369   /**
370    * Desired transmission rate for this MAC
371    */
372   uint8_t rate;
373
374   /**
375    * Antenna we should use for this MAC
376    */
377   uint8_t antenna;
378
379 };
380
381
382 /**
383  * Encapsulation of all of the state of the plugin.
384  */
385 struct Plugin
386 {
387   /**
388    * Our environment.
389    */
390   struct GNUNET_TRANSPORT_PluginEnvironment *env;
391
392   /**
393    * Handle to helper process for priviledged operations.
394    */ 
395   struct GNUNET_HELPER_Handle *suid_helper;
396
397   /**
398    * ARGV-vector for the helper (all helpers take only the binary
399    * name, one actual argument, plus the NULL terminator for 'argv').
400    */
401   char * helper_argv[3];
402
403   /**
404    * The interface of the wlan card given to us by the user.
405    */
406   char *interface;
407
408   /**
409    * Tokenizer for demultiplexing of data packets resulting from defragmentation.
410    */
411   struct GNUNET_SERVER_MessageStreamTokenizer *fragment_data_tokenizer;
412
413   /**
414    * Tokenizer for demultiplexing of data packets received from the suid helper
415    */
416   struct GNUNET_SERVER_MessageStreamTokenizer *helper_payload_tokenizer;
417
418   /**
419    * Tokenizer for demultiplexing of data packets that follow the WLAN Header
420    */
421   struct GNUNET_SERVER_MessageStreamTokenizer *wlan_header_payload_tokenizer;
422
423   /**
424    * Head of list of open connections.
425    */
426   struct MacEndpoint *mac_head;
427
428   /**
429    * Tail of list of open connections.
430    */
431   struct MacEndpoint *mac_tail;
432
433   /**
434    * Number of connections
435    */
436   unsigned int mac_count;
437
438   /**
439    * Task that periodically sends a HELLO beacon via the helper.
440    */
441   GNUNET_SCHEDULER_TaskIdentifier beacon_task;
442
443   /**
444    * Tracker for bandwidth limit
445    */
446   struct GNUNET_BANDWIDTH_Tracker tracker;
447
448   /**
449    * The mac_address of the wlan card given to us by the helper.
450    */
451   struct GNUNET_TRANSPORT_WLAN_MacAddress mac_address;
452
453   /**
454    * Have we received a control message with our MAC address yet?
455    */
456   int have_mac;
457
458   /**
459    * Options for addresses
460    */
461   uint32_t options;
462
463 };
464
465
466 /**
467  * Information associated with a message.  Can contain
468  * the session or the MAC endpoint associated with the
469  * message (or both).
470  */
471 struct MacAndSession
472 {
473   /**
474    * NULL if the identity of the other peer is not known.
475    */
476   struct Session *session;
477
478   /**
479    * MAC address of the other peer, NULL if not known.
480    */
481   struct MacEndpoint *endpoint;
482 };
483
484 /**
485  * Function called for a quick conversion of the binary address to
486  * a numeric address.  Note that the caller must not free the
487  * address and that the next call to this function is allowed
488  * to override the address again.
489  *
490  * @param cls closure
491  * @param addr binary address
492  * @param addrlen length of the address
493  * @return string representing the same address
494  */
495 static const char *
496 wlan_plugin_address_to_string (void *cls, const void *addr, size_t addrlen);
497
498 /**
499  * Print MAC addresses nicely.
500  *
501  * @param mac the mac address
502  * @return string to a static buffer with the human-readable mac, will be overwritten during the next call to this function
503  */
504 static const char *
505 mac_to_string (const struct GNUNET_TRANSPORT_WLAN_MacAddress * mac)
506 {
507   static char macstr[20];
508
509   GNUNET_snprintf (macstr, sizeof (macstr), "%.2X:%.2X:%.2X:%.2X:%.2X:%.2X",
510                                                                  mac->mac[0], mac->mac[1],
511                    mac->mac[2], mac->mac[3], mac->mac[4], mac->mac[5]);
512   return macstr;
513 }
514
515
516 /**
517  * Fill the radiotap header
518  *
519  * @param endpoint pointer to the endpoint, can be NULL
520  * @param header pointer to the radiotap header
521  * @param size total message size
522  */
523 static void
524 get_radiotap_header (struct MacEndpoint *endpoint,
525                      struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *header,
526                      uint16_t size)
527 {
528   header->header.type = ntohs (GNUNET_MESSAGE_TYPE_WLAN_DATA_TO_HELPER);
529   header->header.size = ntohs (size);
530   if (NULL != endpoint)
531   {
532     header->rate = endpoint->rate;
533     header->tx_power = endpoint->tx_power;
534     header->antenna = endpoint->antenna;
535   }
536   else
537   {
538     header->rate = 255;
539     header->tx_power = 0;
540     header->antenna = 0;
541   }
542 }
543
544
545 /**
546  * Generate the WLAN hardware header for one packet
547  *
548  * @param plugin the plugin handle
549  * @param header address to write the header to
550  * @param to_mac_addr address of the recipient
551  * @param size size of the whole packet, needed to calculate the time to send the packet
552  */
553 static void
554 get_wlan_header (struct Plugin *plugin,
555                  struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *header,
556                  const struct GNUNET_TRANSPORT_WLAN_MacAddress *to_mac_addr, 
557                  unsigned int size)
558 {
559   const int rate = 11000000;
560
561   header->frame_control = htons (IEEE80211_FC0_TYPE_DATA);
562   header->addr1 = *to_mac_addr;
563   header->addr2 = plugin->mac_address;
564   header->addr3 = mac_bssid_gnunet;
565   header->duration = GNUNET_htole16 ((size * 1000000) / rate + 290);
566   header->sequence_control = 0; // FIXME?
567   header->llc[0] = WLAN_LLC_DSAP_FIELD;
568   header->llc[1] = WLAN_LLC_SSAP_FIELD;
569   header->llc[2] = 0;  // FIXME?
570   header->llc[3] = 0;  // FIXME?
571 }
572
573
574 /**
575  * Send an ACK for a fragment we received.
576  *
577  * @param cls the 'struct MacEndpoint' the ACK must be sent to
578  * @param msg_id id of the message
579  * @param hdr pointer to the hdr where the ack is stored
580  */
581 static void
582 send_ack (void *cls, uint32_t msg_id,
583           const struct GNUNET_MessageHeader *hdr)
584 {
585   struct MacEndpoint *endpoint = cls;
586   struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage* radio_header;
587   uint16_t msize = ntohs (hdr->size);
588   size_t size = sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage) + msize;
589   char buf[size];
590
591   if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
592   {
593     GNUNET_break (0);
594     return;
595   }
596   LOG (GNUNET_ERROR_TYPE_DEBUG, 
597        "Sending ACK to helper\n");
598   radio_header = (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *) buf;
599   get_radiotap_header (endpoint, radio_header, size);
600   get_wlan_header (endpoint->plugin,
601                    &radio_header->frame, 
602                    &endpoint->addr.mac,
603                    size);
604   memcpy (&radio_header[1], hdr, msize);
605   if (NULL !=
606       GNUNET_HELPER_send (endpoint->plugin->suid_helper,
607                           &radio_header->header,
608                           GNUNET_NO /* dropping ACKs is bad */,
609                           NULL, NULL))    
610     GNUNET_STATISTICS_update (endpoint->plugin->env->stats, _("# WLAN ACKs sent"),
611                               1, GNUNET_NO);
612 }
613
614
615 /**
616  * Handles the data after all fragments are put together
617  *
618  * @param cls macendpoint this messages belongs to
619  * @param hdr pointer to the data
620  */
621 static void
622 wlan_data_message_handler (void *cls, const struct GNUNET_MessageHeader *hdr)
623 {
624   struct MacEndpoint *endpoint = cls;
625   struct Plugin *plugin = endpoint->plugin;
626   struct MacAndSession mas;
627
628   GNUNET_STATISTICS_update (plugin->env->stats,
629                             _("# WLAN messages defragmented"), 1,
630                             GNUNET_NO);
631   mas.session = NULL;
632   mas.endpoint = endpoint;
633   (void) GNUNET_SERVER_mst_receive (plugin->fragment_data_tokenizer, 
634                                     &mas,
635                                     (const char *) hdr,
636                                     ntohs (hdr->size),
637                                     GNUNET_YES, GNUNET_NO);
638 }
639
640
641 /**
642  * Free a session
643  *
644  * @param session the session free
645  */
646 static void
647 free_session (struct Session *session)
648 {
649   struct MacEndpoint *endpoint = session->mac;
650   struct PendingMessage *pm;
651   
652   endpoint->plugin->env->session_end (endpoint->plugin->env->cls,
653                                       &session->target,
654                                       session);
655   while (NULL != (pm = session->pending_message_head))
656   {
657     GNUNET_CONTAINER_DLL_remove (session->pending_message_head,
658                                  session->pending_message_tail, pm);
659     if (GNUNET_SCHEDULER_NO_TASK != pm->timeout_task)
660     {
661       GNUNET_SCHEDULER_cancel (pm->timeout_task);
662       pm->timeout_task = GNUNET_SCHEDULER_NO_TASK;
663     }
664     GNUNET_free (pm->msg);
665     GNUNET_free (pm);
666   }
667   GNUNET_CONTAINER_DLL_remove (endpoint->sessions_head, 
668                                endpoint->sessions_tail,
669                                session);
670   if (session->timeout_task != GNUNET_SCHEDULER_NO_TASK)
671   {
672     GNUNET_SCHEDULER_cancel (session->timeout_task);
673     session->timeout_task = GNUNET_SCHEDULER_NO_TASK;
674   }
675   GNUNET_STATISTICS_update (endpoint->plugin->env->stats, _("# WLAN sessions allocated"), -1,
676                             GNUNET_NO);
677   GNUNET_free (session);
678 }
679
680
681 /**
682  * A session is timing out.  Clean up.
683  *
684  * @param cls pointer to the Session
685  * @param tc pointer to the GNUNET_SCHEDULER_TaskContext
686  */
687 static void
688 session_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
689 {
690   struct Session * session = cls;
691   struct GNUNET_TIME_Relative timeout;
692
693   session->timeout_task = GNUNET_SCHEDULER_NO_TASK;
694   timeout = GNUNET_TIME_absolute_get_remaining (session->timeout);
695   if (0 == timeout.rel_value) 
696   {
697     free_session (session);
698     return;
699   }
700   session->timeout_task =
701     GNUNET_SCHEDULER_add_delayed (timeout, &session_timeout, session);
702 }
703
704
705 /**
706  * Create a new session
707  *
708  * @param endpoint pointer to the mac endpoint of the peer
709  * @param peer peer identity to use for this session
710  * @return returns the session
711  */
712 static struct Session *
713 create_session (struct MacEndpoint *endpoint,
714                 const struct GNUNET_PeerIdentity *peer)
715 {
716   struct Session *session;
717
718   for (session = endpoint->sessions_head; NULL != session; session = session->next)
719     if (0 == memcmp (peer, &session->target,
720                      sizeof (struct GNUNET_PeerIdentity)))
721     {
722       session->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
723       return session;
724     }
725   GNUNET_STATISTICS_update (endpoint->plugin->env->stats, _("# WLAN sessions allocated"), 1,
726                             GNUNET_NO);
727   session = GNUNET_malloc (sizeof (struct Session));
728   GNUNET_CONTAINER_DLL_insert_tail (endpoint->sessions_head,
729                                     endpoint->sessions_tail,
730                                     session);
731   session->mac = endpoint;
732   session->target = *peer;
733   session->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
734   session->timeout_task =
735       GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, &session_timeout, session);
736   LOG (GNUNET_ERROR_TYPE_DEBUG, 
737        "Created new session for peer `%s' with endpoint %s\n",
738        GNUNET_i2s (peer),
739        mac_to_string (&endpoint->addr));
740   return session;
741 }
742
743
744 /**
745  * Function called once we have successfully given the fragment
746  * message to the SUID helper process and we are thus ready for
747  * the next fragment.
748  *
749  * @param cls the 'struct FragmentMessage' 
750  * @param result result of the operation (GNUNET_OK on success, GNUNET_NO if the helper died, GNUNET_SYSERR
751  *        if the helper was stopped)
752  */
753 static void
754 fragment_transmission_done (void *cls,
755                             int result)
756 {
757   struct FragmentMessage *fm = cls;
758
759
760   fm->sh = NULL;
761   GNUNET_FRAGMENT_context_transmission_done (fm->fragcontext);
762 }
763
764
765 /**
766  * Transmit a fragment of a message.
767  *
768  * @param cls 'struct FragmentMessage' this fragment message belongs to
769  * @param hdr pointer to the start of the fragment message 
770  */
771 static void
772 transmit_fragment (void *cls,
773                    const struct GNUNET_MessageHeader *hdr)
774 {
775   struct FragmentMessage *fm = cls;
776   struct MacEndpoint *endpoint = fm->macendpoint;
777   size_t size;
778   uint16_t msize;
779
780   msize = ntohs (hdr->size);
781   size = sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage) + msize;
782   {
783     char buf[size];
784     struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *radio_header;
785
786     radio_header = (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *) buf;
787     get_radiotap_header (endpoint, radio_header, size);
788     get_wlan_header (endpoint->plugin,
789                      &radio_header->frame, 
790                      &endpoint->addr.mac,
791                      size);
792     memcpy (&radio_header[1], hdr, msize);
793     GNUNET_assert (NULL == fm->sh);
794     fm->sh = GNUNET_HELPER_send (endpoint->plugin->suid_helper,
795                                  &radio_header->header,
796                                  GNUNET_NO,
797                                  &fragment_transmission_done, fm);
798     fm->size_on_wire += size;
799     if (NULL != fm->sh)
800       GNUNET_STATISTICS_update (endpoint->plugin->env->stats, _("# WLAN message fragments sent"),
801                                 1, GNUNET_NO);
802     else
803       GNUNET_FRAGMENT_context_transmission_done (fm->fragcontext);
804     GNUNET_STATISTICS_update (endpoint->plugin->env->stats,
805                               "# bytes currently in WLAN buffers",
806                               -msize, GNUNET_NO);
807     GNUNET_STATISTICS_update (endpoint->plugin->env->stats,
808                               "# bytes transmitted via WLAN",
809                               msize, GNUNET_NO);
810   }
811 }
812
813
814 /**
815  * Frees the space of a message in the fragment queue (send queue)
816  *
817  * @param fm message to free
818  */
819 static void
820 free_fragment_message (struct FragmentMessage *fm)
821 {
822   struct MacEndpoint *endpoint = fm->macendpoint;
823
824   GNUNET_STATISTICS_update (endpoint->plugin->env->stats, _("# WLAN messages pending (with fragmentation)"), 
825                             -1, GNUNET_NO);
826   GNUNET_CONTAINER_DLL_remove (endpoint->sending_messages_head,
827                                endpoint->sending_messages_tail, fm);
828   if (NULL != fm->sh)
829   {
830     GNUNET_HELPER_send_cancel (fm->sh);
831     fm->sh = NULL;
832   }
833   GNUNET_FRAGMENT_context_destroy (fm->fragcontext,
834                                                                    &endpoint->msg_delay,
835                                                                    &endpoint->ack_delay);
836   if (fm->timeout_task != GNUNET_SCHEDULER_NO_TASK)
837   {
838     GNUNET_SCHEDULER_cancel (fm->timeout_task);
839     fm->timeout_task = GNUNET_SCHEDULER_NO_TASK;
840   }
841   GNUNET_free (fm);
842 }
843
844
845 /**
846  * A FragmentMessage has timed out.  Remove it.
847  *
848  * @param cls pointer to the 'struct FragmentMessage'
849  * @param tc pointer to the GNUNET_SCHEDULER_TaskContext
850  */
851 static void
852 fragmentmessage_timeout (void *cls,
853                          const struct GNUNET_SCHEDULER_TaskContext *tc)
854 {
855   struct FragmentMessage *fm = cls;
856
857   fm->timeout_task = GNUNET_SCHEDULER_NO_TASK;
858   if (NULL != fm->cont)
859   {
860     fm->cont (fm->cont_cls, &fm->target, GNUNET_SYSERR, fm->size_payload, fm->size_on_wire);
861     fm->cont = NULL;
862   }
863   free_fragment_message (fm);
864 }
865
866
867 /**
868  * Transmit a message to the given destination with fragmentation.
869  *
870  * @param endpoint desired destination
871  * @param timeout how long can the message wait?
872  * @param target peer that should receive the message
873  * @param msg message to transmit
874  * @param payload_size bytes of payload
875  * @param cont continuation to call once the message has
876  *        been transmitted (or if the transport is ready
877  *        for the next transmission call; or if the
878  *        peer disconnected...); can be NULL
879  * @param cont_cls closure for cont
880  */
881 static void
882 send_with_fragmentation (struct MacEndpoint *endpoint,
883                          struct GNUNET_TIME_Relative timeout,
884                          const struct GNUNET_PeerIdentity *target,                       
885                          const struct GNUNET_MessageHeader *msg,
886                          size_t payload_size,
887                          GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
888
889 {
890   struct FragmentMessage *fm;
891   struct Plugin *plugin;
892
893   plugin = endpoint->plugin;
894   fm = GNUNET_malloc (sizeof (struct FragmentMessage));
895   fm->macendpoint = endpoint;
896   fm->target = *target;
897   fm->size_payload = payload_size;
898   fm->size_on_wire = 0;
899   fm->timeout = GNUNET_TIME_relative_to_absolute (timeout);
900   fm->cont = cont;
901   fm->cont_cls = cont_cls;
902   /* 1 MBit/s typical data rate, 1430 byte fragments => ~100 ms per message */
903   fm->fragcontext =
904     GNUNET_FRAGMENT_context_create (plugin->env->stats, WLAN_MTU,
905                                     &plugin->tracker,
906                                     endpoint->msg_delay,
907                                     endpoint->ack_delay,
908                                     msg,
909                                     &transmit_fragment, fm);
910   fm->timeout_task =
911     GNUNET_SCHEDULER_add_delayed (timeout, 
912                                   &fragmentmessage_timeout, fm);
913   GNUNET_CONTAINER_DLL_insert_tail (endpoint->sending_messages_head,
914                                     endpoint->sending_messages_tail,
915                                     fm);
916 }
917
918
919 /**
920  * Free a MAC endpoint.
921  * 
922  * @param endpoint pointer to the MacEndpoint to free
923  */
924 static void
925 free_macendpoint (struct MacEndpoint *endpoint)
926 {
927   struct Plugin *plugin = endpoint->plugin;
928   struct FragmentMessage *fm;
929   struct Session *session;
930
931   GNUNET_STATISTICS_update (plugin->env->stats,
932                             _("# WLAN MAC endpoints allocated"), -1, GNUNET_NO);
933   while (NULL != (session = endpoint->sessions_head))
934     free_session (session);
935   while (NULL != (fm = endpoint->sending_messages_head))
936     free_fragment_message (fm);
937   GNUNET_CONTAINER_DLL_remove (plugin->mac_head, 
938                                plugin->mac_tail, 
939                                endpoint);
940
941   if (NULL != endpoint->defrag)
942   {
943     GNUNET_DEFRAGMENT_context_destroy(endpoint->defrag);
944     endpoint->defrag = NULL;
945   }
946
947   plugin->mac_count--;
948   if (GNUNET_SCHEDULER_NO_TASK != endpoint->timeout_task)
949   {
950     GNUNET_SCHEDULER_cancel (endpoint->timeout_task);
951     endpoint->timeout_task = GNUNET_SCHEDULER_NO_TASK;
952   }
953   GNUNET_free (endpoint);
954 }
955
956
957 /**
958  * A MAC endpoint is timing out.  Clean up.
959  *
960  * @param cls pointer to the MacEndpoint
961  * @param tc pointer to the GNUNET_SCHEDULER_TaskContext
962  */
963 static void
964 macendpoint_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
965 {
966   struct MacEndpoint *endpoint = cls;
967   struct GNUNET_TIME_Relative timeout;
968
969   endpoint->timeout_task = GNUNET_SCHEDULER_NO_TASK;
970   timeout = GNUNET_TIME_absolute_get_remaining (endpoint->timeout);
971   if (0 == timeout.rel_value) 
972   {
973     free_macendpoint (endpoint);
974     return;
975   }
976   endpoint->timeout_task =
977     GNUNET_SCHEDULER_add_delayed (timeout, &macendpoint_timeout,
978                                   endpoint);
979 }
980
981
982 /**
983  * Find (or create) a MacEndpoint with a specific MAC address
984  *
985  * @param plugin pointer to the plugin struct
986  * @param addr the MAC address of the endpoint
987  * @return handle to our data structure for this MAC
988  */
989 static struct MacEndpoint *
990 create_macendpoint (struct Plugin *plugin,
991                     const struct WlanAddress *addr)
992 {
993   struct MacEndpoint *pos;
994
995   for (pos = plugin->mac_head; NULL != pos; pos = pos->next)
996     if (0 == memcmp (addr, &pos->addr, sizeof (struct WlanAddress)))
997       return pos; 
998   pos = GNUNET_malloc (sizeof (struct MacEndpoint));
999   pos->addr = *addr;
1000   pos->plugin = plugin;
1001   pos->defrag =
1002     GNUNET_DEFRAGMENT_context_create (plugin->env->stats, WLAN_MTU,
1003                                       MESSAGES_IN_DEFRAG_QUEUE_PER_MAC,
1004                                       pos, 
1005                                       &wlan_data_message_handler,
1006                                       &send_ack);
1007
1008   pos->msg_delay = GNUNET_TIME_UNIT_MILLISECONDS;
1009   pos->ack_delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
1010                                                                                                   100);
1011   pos->timeout = GNUNET_TIME_relative_to_absolute (MACENDPOINT_TIMEOUT);
1012   pos->timeout_task =
1013       GNUNET_SCHEDULER_add_delayed (MACENDPOINT_TIMEOUT, &macendpoint_timeout,
1014                                     pos);
1015   GNUNET_CONTAINER_DLL_insert (plugin->mac_head, plugin->mac_tail, pos);
1016   plugin->mac_count++;
1017   GNUNET_STATISTICS_update (plugin->env->stats, _("# WLAN MAC endpoints allocated"),
1018                             1, GNUNET_NO);
1019   LOG (GNUNET_ERROR_TYPE_DEBUG, 
1020        "New MAC endpoint `%s'\n",
1021        wlan_plugin_address_to_string(NULL, addr, sizeof (struct WlanAddress)));
1022   return pos;
1023 }
1024
1025
1026 /**
1027  * Creates a new outbound session the transport service will use to send data to the
1028  * peer
1029  *
1030  * @param cls the plugin
1031  * @param address the address
1032  * @return the session or NULL of max connections exceeded
1033  */
1034 static struct Session *
1035 wlan_plugin_get_session (void *cls,
1036                          const struct GNUNET_HELLO_Address *address)
1037 {
1038   struct Plugin *plugin = cls;
1039   struct MacEndpoint *endpoint;
1040
1041   if (NULL == address)
1042     return NULL;
1043   if (sizeof (struct WlanAddress) != address->address_length)
1044   {
1045     GNUNET_break (0);
1046     return NULL;
1047   }
1048   LOG (GNUNET_ERROR_TYPE_DEBUG,
1049        "Service asked to create session for peer `%s' with MAC `%s'\n",
1050        GNUNET_i2s (&address->peer),
1051        wlan_plugin_address_to_string(NULL, address->address, address->address_length));
1052   endpoint = create_macendpoint (plugin, address->address);
1053   return create_session (endpoint, &address->peer);
1054 }
1055
1056
1057 /**
1058  * Function that can be used to force the plugin to disconnect
1059  * from the given peer and cancel all previous transmissions
1060  * (and their continuation).
1061  *
1062  * @param cls closure
1063  * @param target peer from which to disconnect
1064  */
1065 static void
1066 wlan_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target)
1067 {
1068   struct Plugin *plugin = cls;
1069   struct Session *session;
1070   struct MacEndpoint *endpoint;
1071
1072   for (endpoint = plugin->mac_head; NULL != endpoint; endpoint = endpoint->next)
1073     for (session = endpoint->sessions_head; NULL != session; session = session->next)
1074       if (0 == memcmp (target, &session->target,
1075                        sizeof (struct GNUNET_PeerIdentity)))
1076       {
1077         free_session (session);
1078         break; /* inner-loop only (in case peer has another MAC as well!) */
1079       }
1080 }
1081
1082
1083 /**
1084  * Function that can be used by the transport service to transmit
1085  * a message using the plugin.   Note that in the case of a
1086  * peer disconnecting, the continuation MUST be called
1087  * prior to the disconnect notification itself.  This function
1088  * will be called with this peer's HELLO message to initiate
1089  * a fresh connection to another peer.
1090  *
1091  * @param cls closure
1092  * @param session which session must be used
1093  * @param msgbuf the message to transmit
1094  * @param msgbuf_size number of bytes in 'msgbuf'
1095  * @param priority how important is the message (most plugins will
1096  *                 ignore message priority and just FIFO)
1097  * @param to how long to wait at most for the transmission (does not
1098  *                require plugins to discard the message after the timeout,
1099  *                just advisory for the desired delay; most plugins will ignore
1100  *                this as well)
1101  * @param cont continuation to call once the message has
1102  *        been transmitted (or if the transport is ready
1103  *        for the next transmission call; or if the
1104  *        peer disconnected...); can be NULL
1105  * @param cont_cls closure for cont
1106  * @return number of bytes used (on the physical network, with overheads);
1107  *         -1 on hard errors (i.e. address invalid); 0 is a legal value
1108  *         and does NOT mean that the message was not transmitted (DV)
1109  */
1110 static ssize_t
1111 wlan_plugin_send (void *cls,
1112                   struct Session *session,
1113                   const char *msgbuf, size_t msgbuf_size,
1114                   unsigned int priority,
1115                   struct GNUNET_TIME_Relative to,
1116                   GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
1117 {
1118   struct Plugin *plugin = cls;
1119   struct WlanHeader *wlanheader;
1120   size_t size = msgbuf_size + sizeof (struct WlanHeader);
1121   char buf[size] GNUNET_ALIGN;
1122
1123   LOG (GNUNET_ERROR_TYPE_DEBUG, 
1124        "Transmitting %u bytes of payload to peer `%s' (starting with %u byte message of type %u)\n",
1125        msgbuf_size,
1126        GNUNET_i2s (&session->target),
1127        (unsigned int) ntohs (((struct GNUNET_MessageHeader*)msgbuf)->size),
1128        (unsigned int) ntohs (((struct GNUNET_MessageHeader*)msgbuf)->type));
1129   wlanheader = (struct WlanHeader *) buf;
1130   wlanheader->header.size = htons (msgbuf_size + sizeof (struct WlanHeader));
1131   wlanheader->header.type = htons (GNUNET_MESSAGE_TYPE_WLAN_DATA);
1132   wlanheader->sender = *plugin->env->my_identity;
1133   wlanheader->target = session->target;
1134   wlanheader->crc = htonl (GNUNET_CRYPTO_crc32_n (msgbuf, msgbuf_size));
1135   memcpy (&wlanheader[1], msgbuf, msgbuf_size);
1136
1137   GNUNET_STATISTICS_update (plugin->env->stats,
1138                             "# bytes currently in WLAN buffers",
1139                             msgbuf_size, GNUNET_NO);
1140
1141   send_with_fragmentation (session->mac,
1142                            to,
1143                            &session->target,
1144                            &wlanheader->header,
1145                            msgbuf_size,
1146                            cont, cont_cls);
1147   return size;
1148 }
1149
1150
1151 /**
1152  * We have received data from the WLAN via some session.  Process depending
1153  * on the message type (HELLO, DATA, FRAGMENTATION or FRAGMENTATION-ACK).
1154  *
1155  * @param cls pointer to the plugin
1156  * @param client pointer to the session this message belongs to
1157  * @param hdr start of the message
1158  */
1159 static int
1160 process_data (void *cls, void *client, const struct GNUNET_MessageHeader *hdr)
1161 {
1162   struct Plugin *plugin = cls;
1163   struct MacAndSession *mas = client;
1164   struct MacAndSession xmas;
1165   struct GNUNET_ATS_Information ats;
1166   struct FragmentMessage *fm;
1167   struct GNUNET_PeerIdentity tmpsource;
1168   const struct WlanHeader *wlanheader;
1169   int ret;
1170   uint16_t msize;
1171
1172   ats.type = htonl (GNUNET_ATS_NETWORK_TYPE);
1173   ats.value = htonl (GNUNET_ATS_NET_WLAN);
1174   msize = ntohs (hdr->size);
1175
1176   GNUNET_STATISTICS_update (plugin->env->stats,
1177                             "# bytes received via WLAN",
1178                             msize, GNUNET_NO);
1179
1180   switch (ntohs (hdr->type))
1181   {
1182   case GNUNET_MESSAGE_TYPE_HELLO:
1183     if (GNUNET_OK != 
1184         GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) hdr, &tmpsource))
1185     {
1186       GNUNET_break_op (0);
1187       break;
1188     }
1189     LOG (GNUNET_ERROR_TYPE_DEBUG, 
1190          "Processing %u bytes of HELLO from peer `%s' at MAC %s\n",
1191          (unsigned int) msize,
1192          GNUNET_i2s (&tmpsource),
1193          wlan_plugin_address_to_string (NULL, &mas->endpoint->addr, sizeof (struct WlanAddress)));
1194
1195     GNUNET_STATISTICS_update (plugin->env->stats,
1196                               _("# HELLO messages received via WLAN"), 1,
1197                               GNUNET_NO);
1198     plugin->env->receive (plugin->env->cls, 
1199                           &tmpsource,
1200                           hdr, 
1201                           mas->session,
1202                           (mas->endpoint == NULL) ? NULL : (const char *) &mas->endpoint->addr,
1203                           (mas->endpoint == NULL) ? 0 : sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress));
1204     plugin->env->update_address_metrics (plugin->env->cls,
1205                                          &tmpsource,
1206                                          (mas->endpoint == NULL) ? NULL : (const char *) &mas->endpoint->addr,
1207                                          (mas->endpoint == NULL) ? 0 : sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress),
1208                                          mas->session,
1209                                          &ats, 1);
1210     break;
1211   case GNUNET_MESSAGE_TYPE_FRAGMENT:
1212     if (NULL == mas->endpoint)
1213     {
1214       GNUNET_break (0);
1215       break;
1216     }
1217     LOG (GNUNET_ERROR_TYPE_DEBUG, 
1218          "Processing %u bytes of FRAGMENT from MAC %s\n",
1219          (unsigned int) msize,
1220          wlan_plugin_address_to_string (NULL, &mas->endpoint->addr, sizeof (struct WlanAddress)));
1221     GNUNET_STATISTICS_update (plugin->env->stats,
1222                               _("# fragments received via WLAN"), 1, GNUNET_NO);
1223     (void) GNUNET_DEFRAGMENT_process_fragment (mas->endpoint->defrag,
1224                                               hdr);
1225     break;
1226   case GNUNET_MESSAGE_TYPE_FRAGMENT_ACK:
1227     if (NULL == mas->endpoint)
1228     {
1229       GNUNET_break (0);
1230       break;
1231     }
1232     GNUNET_STATISTICS_update (plugin->env->stats, _("# ACKs received via WLAN"),
1233                               1, GNUNET_NO);
1234     for (fm = mas->endpoint->sending_messages_head; NULL != fm; fm = fm->next)
1235     {
1236       ret = GNUNET_FRAGMENT_process_ack (fm->fragcontext, hdr);
1237       if (GNUNET_OK == ret)
1238       {
1239         LOG (GNUNET_ERROR_TYPE_DEBUG, 
1240              "Got last ACK, finished message transmission to `%s' (%p)\n",
1241                  wlan_plugin_address_to_string (NULL, &mas->endpoint->addr, sizeof (struct WlanAddress)),
1242              fm);
1243         mas->endpoint->timeout = GNUNET_TIME_relative_to_absolute (MACENDPOINT_TIMEOUT);
1244         if (NULL != fm->cont)
1245         {
1246           fm->cont (fm->cont_cls, &fm->target, GNUNET_OK, fm->size_payload, fm->size_on_wire);
1247           fm->cont = NULL;
1248         }
1249         free_fragment_message (fm);
1250         break;
1251       }
1252       if (GNUNET_NO == ret)
1253       {
1254         LOG (GNUNET_ERROR_TYPE_DEBUG, 
1255              "Got an ACK, message transmission to `%s' not yet finished\n",
1256                   wlan_plugin_address_to_string (NULL, &mas->endpoint->addr, sizeof (struct WlanAddress)));
1257         break;
1258       }
1259     }
1260     LOG (GNUNET_ERROR_TYPE_DEBUG, 
1261          "ACK not matched against any active fragmentation with MAC `%s'\n",
1262          wlan_plugin_address_to_string (NULL, &mas->endpoint->addr, sizeof (struct WlanAddress)));
1263     break;
1264   case GNUNET_MESSAGE_TYPE_WLAN_DATA:
1265     if (NULL == mas->endpoint)
1266     {
1267       GNUNET_break (0);
1268       break;
1269     }
1270     if (msize < sizeof (struct WlanHeader))
1271     {
1272       GNUNET_break (0);
1273       break;
1274     }    
1275     wlanheader = (const struct WlanHeader *) hdr;
1276     if (0 != memcmp (&wlanheader->target,
1277                      plugin->env->my_identity,
1278                      sizeof (struct GNUNET_PeerIdentity)))
1279     {
1280       LOG (GNUNET_ERROR_TYPE_DEBUG, 
1281            "WLAN data for `%s', not for me, ignoring\n",
1282            GNUNET_i2s (&wlanheader->target));
1283       break;
1284     }
1285     if (ntohl (wlanheader->crc) !=
1286         GNUNET_CRYPTO_crc32_n (&wlanheader[1], msize - sizeof (struct WlanHeader)))
1287     {
1288       GNUNET_STATISTICS_update (plugin->env->stats,
1289                                 _("# WLAN DATA messages discarded due to CRC32 error"), 1,
1290                                 GNUNET_NO);
1291       break;
1292     }
1293     xmas.endpoint = mas->endpoint;
1294     xmas.session = create_session (mas->endpoint, &wlanheader->sender);
1295     LOG (GNUNET_ERROR_TYPE_DEBUG, 
1296          "Processing %u bytes of WLAN DATA from peer `%s'\n",
1297          (unsigned int) msize,
1298          GNUNET_i2s (&wlanheader->sender));
1299     (void) GNUNET_SERVER_mst_receive (plugin->wlan_header_payload_tokenizer, 
1300                                       &xmas,
1301                                       (const char *) &wlanheader[1],
1302                                       msize - sizeof (struct WlanHeader),
1303                                       GNUNET_YES, GNUNET_NO); 
1304     break;
1305   default:
1306     if (NULL == mas->endpoint)
1307     {
1308       GNUNET_break (0);
1309       break;
1310     }
1311     if (NULL == mas->session)
1312     {
1313       GNUNET_break (0);
1314       break;
1315     }
1316     LOG (GNUNET_ERROR_TYPE_DEBUG,
1317          "Received packet with %u bytes of type %u from peer %s\n",
1318          (unsigned int) msize,
1319          (unsigned int) ntohs (hdr->type),
1320          GNUNET_i2s (&mas->session->target));
1321     plugin->env->receive (plugin->env->cls, 
1322                           &mas->session->target,
1323                           hdr, 
1324                           mas->session,
1325                           (mas->endpoint == NULL) ? NULL : (const char *) &mas->endpoint->addr,
1326                           (mas->endpoint == NULL) ? 0 : sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress));
1327     plugin->env->update_address_metrics (plugin->env->cls,
1328                                          &mas->session->target,
1329                                          (mas->endpoint == NULL) ? NULL : (const char *) &mas->endpoint->addr,
1330                                          (mas->endpoint == NULL) ? 0 : sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress),
1331                                          mas->session,
1332                                          &ats, 1);
1333     break;
1334   }
1335   return GNUNET_OK;
1336 }
1337
1338
1339 /**
1340  * Function used for to process the data from the suid process
1341  *
1342  * @param cls the plugin handle
1343  * @param client client that send the data (not used)
1344  * @param hdr header of the GNUNET_MessageHeader
1345  */
1346 static int
1347 handle_helper_message (void *cls, void *client,
1348                        const struct GNUNET_MessageHeader *hdr)
1349 {
1350   struct Plugin *plugin = cls;
1351   const struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *rxinfo;
1352   const struct GNUNET_TRANSPORT_WLAN_HelperControlMessage *cm;
1353   struct WlanAddress wa;
1354   struct MacAndSession mas;
1355   uint16_t msize;
1356
1357   msize = ntohs (hdr->size);
1358   switch (ntohs (hdr->type))
1359   {
1360   case GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL:
1361     if (msize != sizeof (struct GNUNET_TRANSPORT_WLAN_HelperControlMessage))
1362     {
1363       GNUNET_break (0);
1364       break;
1365     }
1366     cm = (const struct GNUNET_TRANSPORT_WLAN_HelperControlMessage *) hdr;
1367     if (GNUNET_YES == plugin->have_mac)
1368     {
1369       if (0 == memcmp (&plugin->mac_address,
1370                        &cm->mac,
1371                        sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)))
1372         break; /* no change */
1373       /* remove old address */
1374       memset (&wa, 0, sizeof (struct WlanAddress));
1375       wa.mac = plugin->mac_address;
1376       wa.options = htonl(plugin->options);
1377       plugin->env->notify_address (plugin->env->cls, GNUNET_NO,
1378                                    &wa,
1379                                    sizeof (wa),
1380                                    "wlan");
1381     }
1382     plugin->mac_address = cm->mac;
1383     plugin->have_mac = GNUNET_YES;
1384     memset (&wa, 0, sizeof (struct WlanAddress));
1385     wa.mac = plugin->mac_address;
1386     wa.options = htonl(plugin->options);
1387     LOG (GNUNET_ERROR_TYPE_DEBUG,
1388          "Received WLAN_HELPER_CONTROL message with MAC address `%s' for peer `%s'\n",
1389          mac_to_string (&cm->mac),
1390          GNUNET_i2s (plugin->env->my_identity));
1391     plugin->env->notify_address (plugin->env->cls, GNUNET_YES,
1392                                  &wa,
1393                                  sizeof (struct WlanAddress),
1394                                  "wlan");
1395     break;
1396   case GNUNET_MESSAGE_TYPE_WLAN_DATA_FROM_HELPER:
1397     LOG (GNUNET_ERROR_TYPE_DEBUG, 
1398          "Got data message from helper with %u bytes\n",
1399          msize);
1400     GNUNET_STATISTICS_update (plugin->env->stats,
1401                               _("# DATA messages received via WLAN"), 1,
1402                               GNUNET_NO);
1403     if (msize < sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage))
1404     {
1405       GNUNET_break (0);
1406       LOG (GNUNET_ERROR_TYPE_DEBUG,
1407            "Size of packet is too small (%u bytes)\n",
1408            msize);
1409       break;
1410     }
1411     rxinfo = (const struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *) hdr;
1412
1413     /* check if message is actually for us */
1414     if (0 != memcmp (&rxinfo->frame.addr3, &mac_bssid_gnunet,
1415                      sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)))
1416     {
1417       /* Not the GNUnet BSSID */
1418       break;
1419     }
1420     if ( (0 != memcmp (&rxinfo->frame.addr1, &bc_all_mac,
1421                        sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress))) &&
1422          (0 != memcmp (&rxinfo->frame.addr1, &plugin->mac_address,
1423                        sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress))) )
1424     {
1425       /* Neither broadcast nor specifically for us */
1426       break;
1427     }
1428     if (0 == memcmp (&rxinfo->frame.addr2, &plugin->mac_address,
1429                      sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)))
1430     {
1431       /* packet is FROM us, thus not FOR us */
1432       break;
1433     }
1434     
1435     GNUNET_STATISTICS_update (plugin->env->stats,
1436                               _("# WLAN DATA messages processed"),
1437                               1, GNUNET_NO);
1438     LOG (GNUNET_ERROR_TYPE_DEBUG,
1439          "Receiving %u bytes of data from MAC `%s'\n",
1440          (unsigned int) (msize - sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)),
1441          mac_to_string (&rxinfo->frame.addr2));
1442     wa.mac = rxinfo->frame.addr2;
1443     wa.options = htonl (0);
1444     mas.endpoint = create_macendpoint (plugin, &wa);
1445     mas.session = NULL;
1446     (void) GNUNET_SERVER_mst_receive (plugin->helper_payload_tokenizer, 
1447                                       &mas,
1448                                       (const char*) &rxinfo[1],
1449                                       msize - sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage),
1450                                       GNUNET_YES, GNUNET_NO);
1451     break;
1452   default:
1453     GNUNET_break (0);
1454     LOG (GNUNET_ERROR_TYPE_DEBUG, 
1455          "Unexpected message of type %u (%u bytes)",
1456          ntohs (hdr->type), ntohs (hdr->size));
1457     break;
1458   }
1459   return GNUNET_OK;
1460 }
1461
1462
1463
1464 /**
1465  * Task to (periodically) send a HELLO beacon
1466  *
1467  * @param cls pointer to the plugin struct
1468  * @param tc scheduler context
1469  */
1470 static void
1471 send_hello_beacon (void *cls,
1472                    const struct GNUNET_SCHEDULER_TaskContext *tc)
1473 {
1474   struct Plugin *plugin = cls;
1475   uint16_t size;
1476   uint16_t hello_size;
1477   struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *radioHeader;
1478   const struct GNUNET_MessageHeader *hello;
1479
1480   hello = plugin->env->get_our_hello ();
1481   hello_size = GNUNET_HELLO_size ((struct GNUNET_HELLO_Message *) hello);
1482   GNUNET_assert (sizeof (struct WlanHeader) + hello_size <= WLAN_MTU);
1483   size = sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage) + hello_size;
1484   {
1485     char buf[size] GNUNET_ALIGN;
1486
1487     LOG (GNUNET_ERROR_TYPE_DEBUG, 
1488          "Sending %u byte HELLO beacon\n",
1489          (unsigned int) size);
1490     radioHeader = (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage*) buf;
1491     get_radiotap_header (NULL, radioHeader, size);
1492     get_wlan_header (plugin, &radioHeader->frame, &bc_all_mac, size);
1493     memcpy (&radioHeader[1], hello, hello_size);
1494     if (NULL !=
1495         GNUNET_HELPER_send (plugin->suid_helper,
1496                             &radioHeader->header,
1497                             GNUNET_YES /* can drop */,
1498                             NULL, NULL))
1499       GNUNET_STATISTICS_update (plugin->env->stats, _("# HELLO beacons sent via WLAN"),
1500                                 1, GNUNET_NO);
1501   }
1502   plugin->beacon_task =
1503     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
1504                                   (HELLO_BEACON_SCALING_FACTOR,
1505                                    plugin->mac_count + 1),
1506                                   &send_hello_beacon,
1507                                   plugin);
1508
1509 }
1510
1511
1512 /**
1513  * Another peer has suggested an address for this
1514  * peer and transport plugin.  Check that this could be a valid
1515  * address.  If so, consider adding it to the list
1516  * of addresses.
1517  *
1518  * @param cls closure
1519  * @param addr pointer to the address
1520  * @param addrlen length of addr
1521  * @return GNUNET_OK if this is a plausible address for this peer
1522  *         and transport
1523  */
1524 static int
1525 wlan_plugin_address_suggested (void *cls, const void *addr, size_t addrlen)
1526 {
1527   struct Plugin *plugin = cls;
1528   struct WlanAddress *wa = (struct WlanAddress *) addr;
1529
1530   if (addrlen != sizeof (struct WlanAddress))
1531   {    
1532     GNUNET_break_op (0);
1533     return GNUNET_SYSERR;
1534   }
1535   if (GNUNET_YES != plugin->have_mac)
1536   {
1537     LOG (GNUNET_ERROR_TYPE_DEBUG, 
1538          "Rejecting MAC `%s': I don't know my MAC!\n",
1539          mac_to_string (addr));
1540     return GNUNET_NO; /* don't know my MAC */
1541   }
1542   if (0 != memcmp (&wa->mac,
1543                    &plugin->mac_address,
1544                    sizeof (wa->mac)))
1545   {
1546     LOG (GNUNET_ERROR_TYPE_DEBUG, 
1547          "Rejecting MAC `%s': not my MAC!\n",
1548          mac_to_string (addr));
1549     return GNUNET_NO; /* not my MAC */
1550   }
1551   return GNUNET_OK;
1552 }
1553
1554
1555 /**
1556  * Function called for a quick conversion of the binary address to
1557  * a numeric address.  Note that the caller must not free the
1558  * address and that the next call to this function is allowed
1559  * to override the address again.
1560  *
1561  * @param cls closure
1562  * @param addr binary address
1563  * @param addrlen length of the address
1564  * @return string representing the same address
1565  */
1566 static const char *
1567 wlan_plugin_address_to_string (void *cls, const void *addr, size_t addrlen)
1568 {
1569   const struct GNUNET_TRANSPORT_WLAN_MacAddress *mac;
1570   static char macstr[36];
1571
1572   if (sizeof (struct WlanAddress) != addrlen)
1573   {
1574     GNUNET_break (0);
1575     return NULL;
1576   }
1577   mac = &((struct WlanAddress *) addr)->mac;
1578   GNUNET_snprintf (macstr, sizeof (macstr), "%s.%u.%s",
1579                 PLUGIN_NAME, ntohl (((struct WlanAddress *) addr)->options),
1580                 mac_to_string (mac));
1581
1582   return macstr;
1583 }
1584
1585
1586 /**
1587  * Convert the transports address to a nice, human-readable format.
1588  *
1589  * @param cls closure
1590  * @param type name of the transport that generated the address
1591  * @param addr one of the addresses of the host, NULL for the last address
1592  *        the specific address format depends on the transport
1593  * @param addrlen length of the address
1594  * @param numeric should (IP) addresses be displayed in numeric form?
1595  * @param timeout after how long should we give up?
1596  * @param asc function to call on each string
1597  * @param asc_cls closure for asc
1598  */
1599 static void
1600 wlan_plugin_address_pretty_printer (void *cls, const char *type,
1601                                     const void *addr, size_t addrlen,
1602                                     int numeric,
1603                                     struct GNUNET_TIME_Relative timeout,
1604                                     GNUNET_TRANSPORT_AddressStringCallback asc,
1605                                     void *asc_cls)
1606 {
1607   char *ret;
1608
1609   if (sizeof (struct WlanAddress) != addrlen)
1610   {
1611     /* invalid address  */
1612     LOG (GNUNET_ERROR_TYPE_WARNING,
1613          _("WLAN address with invalid size encountered\n"));
1614     asc (asc_cls, NULL);
1615     return;
1616   }
1617   ret = GNUNET_strdup (wlan_plugin_address_to_string(NULL, addr, addrlen));
1618   asc (asc_cls, ret);
1619   GNUNET_free (ret);
1620   asc (asc_cls, NULL);
1621 }
1622
1623
1624 /**
1625  * Exit point from the plugin. 
1626  *
1627  * @param cls pointer to the api struct
1628  */
1629 void *
1630 libgnunet_plugin_transport_wlan_done (void *cls)
1631 {
1632         struct WlanAddress wa;
1633   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
1634   struct Plugin *plugin = api->cls;
1635   struct MacEndpoint *endpoint;
1636   struct MacEndpoint *endpoint_next;
1637
1638   if (NULL == plugin)
1639   {
1640     GNUNET_free (api);
1641     return NULL;
1642   }
1643
1644   if (GNUNET_YES == plugin->have_mac)
1645   {
1646                 memset (&wa, 0, sizeof (wa));
1647                 wa.options = htonl (plugin->options);
1648                 wa.mac = plugin->mac_address;
1649       plugin->env->notify_address (plugin->env->cls, GNUNET_NO,
1650                                &wa,
1651                                sizeof (struct WlanAddress),
1652                                "wlan");
1653       plugin->have_mac = GNUNET_NO;
1654   }
1655
1656   if (GNUNET_SCHEDULER_NO_TASK != plugin->beacon_task)
1657   {
1658     GNUNET_SCHEDULER_cancel (plugin->beacon_task);
1659     plugin->beacon_task = GNUNET_SCHEDULER_NO_TASK;
1660   }
1661   if (NULL != plugin->suid_helper)
1662   {
1663     GNUNET_HELPER_stop (plugin->suid_helper, GNUNET_NO);
1664     plugin->suid_helper = NULL;
1665   }
1666   endpoint_next = plugin->mac_head;
1667   while (NULL != (endpoint = endpoint_next))
1668   {
1669     endpoint_next = endpoint->next;
1670     free_macendpoint (endpoint);
1671   }
1672   if (NULL != plugin->fragment_data_tokenizer)
1673   {
1674     GNUNET_SERVER_mst_destroy (plugin->fragment_data_tokenizer);
1675     plugin->fragment_data_tokenizer = NULL;
1676   }
1677   if (NULL != plugin->wlan_header_payload_tokenizer)
1678   {
1679     GNUNET_SERVER_mst_destroy (plugin->wlan_header_payload_tokenizer);
1680     plugin->wlan_header_payload_tokenizer = NULL;
1681   }
1682   if (NULL != plugin->helper_payload_tokenizer)
1683   {
1684     GNUNET_SERVER_mst_destroy (plugin->helper_payload_tokenizer);
1685     plugin->helper_payload_tokenizer = NULL;
1686   }
1687   GNUNET_free_non_null (plugin->interface);
1688   GNUNET_free (plugin);
1689   GNUNET_free (api);
1690   return NULL;
1691 }
1692
1693
1694 /**
1695  * Function called to convert a string address to
1696  * a binary address.
1697  *
1698  * @param cls closure ('struct Plugin*')
1699  * @param addr string address
1700  * @param addrlen length of the address
1701  * @param buf location to store the buffer
1702  * @param added location to store the number of bytes in the buffer.
1703  *        If the function returns GNUNET_SYSERR, its contents are undefined.
1704  * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1705  */
1706 static int
1707 wlan_string_to_address (void *cls, const char *addr, uint16_t addrlen,
1708                         void **buf, size_t *added)
1709 {
1710   struct WlanAddress *wa;
1711   unsigned int a[6];
1712   unsigned int i;
1713   char plugin[4];
1714   uint32_t options;
1715
1716   if ((NULL == addr) || (addrlen == 0))
1717   {
1718     GNUNET_break (0);
1719     return GNUNET_SYSERR;
1720   }
1721   if ('\0' != addr[addrlen - 1])
1722   {
1723     GNUNET_break (0);
1724     return GNUNET_SYSERR;
1725   }
1726   if (strlen (addr) != addrlen - 1)
1727   {
1728     GNUNET_break (0);
1729     return GNUNET_SYSERR;
1730   }
1731
1732   if (8 != SSCANF (addr,
1733                    "%4s.%u.%X:%X:%X:%X:%X:%X",
1734                    plugin, &options,
1735                    &a[0], &a[1], &a[2], &a[3], &a[4], &a[5]))
1736   {
1737     GNUNET_break (0);
1738     return GNUNET_SYSERR;
1739   }
1740   wa = GNUNET_malloc (sizeof (struct WlanAddress));
1741   for (i=0;i<6;i++)
1742     wa->mac.mac[i] = a[i];
1743   wa->options = htonl (0);
1744   *buf = wa;
1745   *added = sizeof (struct WlanAddress);
1746   return GNUNET_OK;
1747 }
1748
1749
1750 /**
1751  * Entry point for the plugin.
1752  *
1753  * @param cls closure, the 'struct GNUNET_TRANSPORT_PluginEnvironment*'
1754  * @return the 'struct GNUNET_TRANSPORT_PluginFunctions*' or NULL on error
1755  */
1756 void *
1757 libgnunet_plugin_transport_wlan_init (void *cls)
1758 {
1759   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
1760   struct GNUNET_TRANSPORT_PluginFunctions *api;
1761   struct Plugin *plugin;
1762   char *interface;
1763   unsigned long long testmode;
1764   char *binary;
1765
1766   /* check for 'special' mode */
1767   if (NULL == env->receive)
1768   {
1769     /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
1770        initialze the plugin or the API */
1771     api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
1772     api->cls = NULL;
1773     api->address_pretty_printer = &wlan_plugin_address_pretty_printer;
1774     api->address_to_string = &wlan_plugin_address_to_string;
1775     api->string_to_address = &wlan_string_to_address;
1776     return api;
1777   }
1778
1779   testmode = 0;
1780   /* check configuration */
1781   if ( (GNUNET_YES == 
1782         GNUNET_CONFIGURATION_have_value (env->cfg, "transport-wlan", "TESTMODE")) &&
1783        ( (GNUNET_SYSERR ==
1784           GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-wlan",
1785                                                  "TESTMODE", &testmode)) ||
1786          (testmode > 2) ) )
1787   {
1788     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1789                                "transport-wlan", "TESTMODE");
1790     return NULL;
1791   }
1792   binary = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-transport-wlan");
1793   if ( (0 == testmode) &&
1794        (GNUNET_YES != GNUNET_OS_check_helper_binary (binary, GNUNET_YES, NULL)) )
1795   {
1796     LOG (GNUNET_ERROR_TYPE_ERROR,
1797          _("Helper binary `%s' not SUID, cannot run WLAN transport\n"),
1798          "gnunet-helper-transport-wlan");
1799     GNUNET_free (binary);
1800     return NULL;
1801   }
1802     GNUNET_free (binary);
1803   if (GNUNET_YES !=
1804       GNUNET_CONFIGURATION_get_value_string
1805       (env->cfg, "transport-wlan", "INTERFACE",
1806        &interface))
1807   {
1808     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1809                                "transport-wlan", "INTERFACE");
1810     return NULL;    
1811   }
1812
1813   plugin = GNUNET_malloc (sizeof (struct Plugin));
1814   plugin->interface = interface;
1815   plugin->env = env;
1816   GNUNET_STATISTICS_set (plugin->env->stats, _("# WLAN sessions allocated"),
1817                          0, GNUNET_NO);
1818   GNUNET_STATISTICS_set (plugin->env->stats, _("# WLAN MAC endpoints allocated"),
1819                          0, 0);
1820   GNUNET_BANDWIDTH_tracker_init (&plugin->tracker,
1821                                  GNUNET_BANDWIDTH_value_init (100 * 1024 *
1822                                                               1024 / 8), 100);
1823   plugin->fragment_data_tokenizer = GNUNET_SERVER_mst_create (&process_data, plugin);
1824   plugin->wlan_header_payload_tokenizer = GNUNET_SERVER_mst_create (&process_data, plugin);
1825   plugin->helper_payload_tokenizer = GNUNET_SERVER_mst_create (&process_data, plugin);
1826   plugin->beacon_task = GNUNET_SCHEDULER_add_now (&send_hello_beacon, 
1827                                                   plugin);
1828
1829   plugin->options = 0;
1830
1831   /* some compilers do not like switch on 'long long'... */
1832   switch ((unsigned int) testmode)
1833   {
1834   case 0: /* normal */ 
1835     plugin->helper_argv[0] = (char *) "gnunet-helper-transport-wlan";
1836     plugin->helper_argv[1] = interface;
1837     plugin->helper_argv[2] = NULL;
1838     plugin->suid_helper = GNUNET_HELPER_start (GNUNET_NO,
1839                                                "gnunet-helper-transport-wlan",
1840                                                plugin->helper_argv,
1841                                                &handle_helper_message,
1842                                                NULL,
1843                                                plugin);
1844     break;
1845   case 1: /* testmode, peer 1 */
1846     plugin->helper_argv[0] = (char *) "gnunet-helper-transport-wlan-dummy";
1847     plugin->helper_argv[1] = (char *) "1";
1848     plugin->helper_argv[2] = NULL;
1849     plugin->suid_helper = GNUNET_HELPER_start (GNUNET_NO,
1850                                                "gnunet-helper-transport-wlan-dummy",
1851                                                plugin->helper_argv,
1852                                                &handle_helper_message,
1853                                                NULL,
1854                                                plugin);
1855     break;
1856   case 2: /* testmode, peer 2 */
1857     plugin->helper_argv[0] = (char *) "gnunet-helper-transport-wlan-dummy";
1858     plugin->helper_argv[1] = (char *) "2";
1859     plugin->helper_argv[2] = NULL;
1860     plugin->suid_helper = GNUNET_HELPER_start (GNUNET_NO,
1861                                                "gnunet-helper-transport-wlan-dummy",
1862                                                plugin->helper_argv,
1863                                                &handle_helper_message,
1864                                                NULL,
1865                                                plugin);
1866     break;
1867   default:
1868     GNUNET_assert (0);
1869   }
1870
1871   api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
1872   api->cls = plugin;
1873   api->send = &wlan_plugin_send;
1874   api->get_session = &wlan_plugin_get_session;
1875   api->disconnect = &wlan_plugin_disconnect;
1876   api->address_pretty_printer = &wlan_plugin_address_pretty_printer;
1877   api->check_address = &wlan_plugin_address_suggested;
1878   api->address_to_string = &wlan_plugin_address_to_string;
1879   api->string_to_address = &wlan_string_to_address;
1880   return api;
1881 }
1882
1883
1884 /* end of plugin_transport_wlan.c */