-werror fix
[oweals/gnunet.git] / src / transport / plugin_transport_wlan.c
1 /*
2  This file is part of GNUnet
3  (C) 2010 2011 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  */
26
27 //TODO split rx and tx structures for better handling
28
29 #include "platform.h"
30 #include "gnunet_hello_lib.h"
31 #include "gnunet_protocols.h"
32 #include "gnunet_util_lib.h"
33 #include "gnunet_statistics_service.h"
34 #include "gnunet_transport_service.h"
35 #include "gnunet_transport_plugin.h"
36 #include "plugin_transport_wlan.h"
37 #include "gnunet_common.h"
38 #include "gnunet_crypto_lib.h"
39 #include "gnunet_fragmentation_lib.h"
40 #include "gnunet_constants.h"
41
42 /**
43  * DEBUG switch
44  */
45 #define DEBUG_WLAN GNUNET_EXTRA_LOGGING
46
47
48 #define PROTOCOL_PREFIX "wlan"
49
50 #define PLUGIN_LOG_NAME "wlan-plugin"
51
52 /**
53  * Max size of packet
54  */
55 #define WLAN_MTU 1430
56
57 /**
58  * time out of a session
59  */
60 #define SESSION_TIMEOUT GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT
61
62 /**
63  * time out of a mac endpoint
64  */
65 #define MACENDPOINT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, 2)
66
67 /**
68  * scaling factor for hello beacon
69  */
70 #define HELLO_BEACON_SCALING_FACTOR 30
71
72 /**
73  * scaling factor for restarting the helper
74  */
75 #define HELPER_RESTART_SCALING_FACTOR 2
76
77 /**
78  * max size of fragment queue
79  */
80 #define FRAGMENT_QUEUE_SIZE 10
81 /**
82  * max messages in fragment queue per session/client
83  */
84 #define FRAGMENT_QUEUE_MESSAGES_OUT_PER_SESSION 1
85
86 /**
87  * max messages in fragment queue per MAC
88  */
89 #define FRAGMENT_QUEUE_MESSAGES_OUT_PER_MACENDPOINT 1
90
91 /**
92  * max messages in in queue
93  */
94 #define MESSAGES_IN_QUEUE_SIZE 10
95 /**
96  * max messages in in queue per session/client
97  */
98 #define MESSAGES_IN_DEFRAG_QUEUE_PER_MAC 1
99
100 /**
101  * Link layer control fields for better compatibility
102  * (i.e. GNUnet over WLAN is not IP-over-WLAN).
103  */
104 #define WLAN_LLC_DSAP_FIELD 0x1f
105 #define WLAN_LLC_SSAP_FIELD 0x1f
106
107
108 #define IEEE80211_ADDR_LEN      6       /* size of 802.11 address */
109
110 #define IEEE80211_FC0_VERSION_MASK              0x03
111 #define IEEE80211_FC0_VERSION_SHIFT             0
112 #define IEEE80211_FC0_VERSION_0                 0x00
113 #define IEEE80211_FC0_TYPE_MASK                 0x0c
114 #define IEEE80211_FC0_TYPE_SHIFT                2
115 #define IEEE80211_FC0_TYPE_MGT                  0x00
116 #define IEEE80211_FC0_TYPE_CTL                  0x04
117 #define IEEE80211_FC0_TYPE_DATA                 0x08
118
119
120 /**
121  * Encapsulation of all of the state of the plugin.
122  */
123 struct Plugin
124 {
125   /**
126    * Our environment.
127    */
128   struct GNUNET_TRANSPORT_PluginEnvironment *env;
129
130   /**
131    * List of open connections. head
132    */
133   struct MacEndpoint *mac_head;
134
135   /**
136    * List of open connections. tail
137    */
138   struct MacEndpoint *mac_tail;
139
140   /**
141    * Number of connections
142    */
143   unsigned int mac_count;
144
145   /**
146    * encapsulation of data from the local wlan helper program
147    */
148   struct GNUNET_SERVER_MessageStreamTokenizer *suid_tokenizer;
149
150   /**
151    * encapsulation of packets received from the wlan helper
152    */
153   struct GNUNET_SERVER_MessageStreamTokenizer *data_tokenizer;
154
155   /**
156    * stdout pipe handle for the gnunet-helper-transport-wlan process
157    */
158   struct GNUNET_DISK_PipeHandle *server_stdout;
159
160   /**
161    * stdout file handle for the gnunet-helper-transport-wlan process
162    */
163   const struct GNUNET_DISK_FileHandle *server_stdout_handle;
164
165   /**
166    * stdin pipe handle for the gnunet-helper-transport-wlan process
167    */
168   struct GNUNET_DISK_PipeHandle *server_stdin;
169
170   /**
171    * stdin file handle for the gnunet-helper-transport-wlan process
172    */
173   const struct GNUNET_DISK_FileHandle *server_stdin_handle;
174
175   /**
176    * ID of the gnunet-wlan-server std read task
177    */
178   GNUNET_SCHEDULER_TaskIdentifier server_read_task;
179
180   /**
181    * ID of the gnunet-wlan-server std read task
182    */
183   GNUNET_SCHEDULER_TaskIdentifier server_write_task;
184
185   /**
186    * ID of the delay task for writing
187    */
188   GNUNET_SCHEDULER_TaskIdentifier server_write_delay_task;
189
190   /**
191    * The process id of the wlan process
192    */
193   struct GNUNET_OS_Process *server_proc;
194
195   /**
196    * The interface of the wlan card given to us by the user.
197    */
198   char *interface;
199
200   /**
201    * Mode of operation for the helper, 0 = normal, 1 = first loopback, 2 = second loopback
202    */
203   long long unsigned int testmode;
204
205   /**
206    * The mac_address of the wlan card given to us by the helper.
207    */
208   struct GNUNET_TRANSPORT_WLAN_MacAddress mac_address;
209
210   /**
211    * Sessions currently pending for transmission
212    * to a peer, if any.
213    */
214   struct Sessionqueue *pending_Sessions_head;
215
216   /**
217    * Sessions currently pending for transmission
218    * to a peer (tail), if any.
219    */
220   struct Sessionqueue *pending_Sessions_tail;
221
222   /**
223    * number of pending sessions
224    */
225   unsigned int pendingsessions;
226
227   /**
228    * Messages in the sending queues
229    */
230   int pending_Fragment_Messages;
231
232   /**
233    * messages ready for send, head
234    */
235   struct FragmentMessage_queue *sending_messages_head;
236
237   /**
238    * messages ready for send, tail
239    */
240   struct FragmentMessage_queue *sending_messages_tail;
241
242   /**
243    * time of the next "hello-beacon"
244    */
245   struct GNUNET_TIME_Absolute beacon_time;
246
247   /**
248    * queue to send acks for received fragments (head)
249    */
250   struct AckSendQueue *ack_send_queue_head;
251
252   /**
253    * queue to send acks for received fragments (tail)
254    */
255   struct AckSendQueue *ack_send_queue_tail;
256
257   /**
258    * Tracker for bandwidth limit
259    */
260   struct GNUNET_BANDWIDTH_Tracker tracker;
261
262   /**
263    * saves the current state of the helper process
264    */
265   int helper_is_running;
266 };
267
268 /**
269  * Struct to store data if file write did not accept the whole packet
270  */
271 struct Finish_send
272 {
273   /**
274    * pointer to the global plugin struct
275    */
276   struct Plugin *plugin;
277
278   /**
279    * head of the next part to send to the helper
280    */
281   const char *head_of_next_write;
282
283   /**
284    * Start of the message to send, needed for free
285    */
286   struct GNUNET_MessageHeader *msgstart;
287
288   /**
289    * rest size to send
290    */
291   ssize_t size;
292 };
293
294 /**
295  * Queue of sessions, for the general session queue and the pending session queue
296  */
297 //TODO DOXIGEN
298 struct Sessionqueue
299 {
300   struct Sessionqueue *next;
301   struct Sessionqueue *prev;
302   struct Session *content;
303 #if !HAVE_UNALIGNED_64_ACCESS
304   void *dummy;                  /* for alignment, see #1909 */
305 #endif
306 };
307
308 /**
309  * Queue of fragmented messages, for the sending queue of the plugin
310  */
311 //TODO DOXIGEN
312 struct FragmentMessage_queue
313 {
314   struct FragmentMessage_queue *next;
315   struct FragmentMessage_queue *prev;
316   struct FragmentMessage *content;
317 };
318
319 /**
320  * Queue for the fragments received
321  */
322 //TODO DOXIGEN
323 struct Receive_Fragment_Queue
324 {
325   struct Receive_Fragment_Queue *next;
326   struct Receive_Fragment_Queue *prev;
327   uint16_t num;
328   const char *msg;
329   uint16_t size;
330   struct Radiotap_rx rxinfo;
331 };
332
333 //TODO DOXIGEN
334 struct MacEndpoint_id_fragment_triple
335 {
336   struct MacEndpoint *endpoint;
337   uint32_t message_id;
338   struct FragmentMessage *fm;
339 };
340
341 //TODO DOXIGEN
342 struct Plugin_Session_pair
343 {
344   struct Plugin *plugin;
345   struct Session *session;
346 };
347
348
349 GNUNET_NETWORK_STRUCT_BEGIN
350
351 /**
352  * Header for messages which need fragmentation
353  */
354 struct WlanHeader
355 {
356
357   struct GNUNET_MessageHeader header;
358
359   /**
360    * checksum/error correction
361    */
362   uint32_t crc GNUNET_PACKED;
363
364   /**
365    * To whom are we talking to (set to our identity
366    * if we are still waiting for the welcome message)
367    */
368   struct GNUNET_PeerIdentity target;
369
370   /**
371    *  Where the packet came from
372    */
373   struct GNUNET_PeerIdentity source;
374
375 // followed by payload
376
377 };
378 GNUNET_NETWORK_STRUCT_END
379
380 /**
381  * Information kept for each message that is yet to
382  * be transmitted.
383  */
384 struct PendingMessage
385 {
386   /**
387    * dll next
388    */
389   struct PendingMessage *next;
390
391   /**
392    * dll prev
393    */
394   struct PendingMessage *prev;
395
396   /**
397    * The pending message
398    */
399   struct WlanHeader *msg;
400
401   /**
402    * Size of the message
403    */
404   size_t message_size;
405
406   /**
407    * Continuation function to call once the message
408    * has been sent.  Can be NULL if there is no
409    * continuation to call.
410    */
411   GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
412
413   /**
414    * Cls for transmit_cont
415    */
416   void *transmit_cont_cls;
417
418   /**
419    * Timeout value for the pending message.
420    */
421   struct GNUNET_TIME_Absolute timeout;
422
423 };
424
425
426 /**
427  * Queue for acks to send for fragments recived
428  */
429 struct AckSendQueue
430 {
431
432   /**
433    * next ack in the ack send queue
434    */
435   struct AckSendQueue *next;
436
437   /**
438    * previous ack in the ack send queue
439    */
440   struct AckSendQueue *prev;
441
442   /**
443    * pointer to the session this ack belongs to
444    */
445   struct MacEndpoint *endpoint;
446
447   /**
448    * ID of message, to distinguish between the messages, picked randomly.
449    */
450   uint32_t message_id;
451
452   /**
453    * pointer to the radiotap header with the ACK Message.
454    */
455   const struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *radioHeader;
456 };
457
458
459 /**
460  * Session infos gathered from a messages
461  */
462 struct Session_light
463 {
464   /**
465    * the session this message belongs to
466    */
467   struct Session *session;
468   /**
469    * peer mac address
470    */
471   struct GNUNET_TRANSPORT_WLAN_MacAddress addr;
472
473   /**
474    * mac endpoint
475    */
476   struct MacEndpoint *macendpoint;
477 };
478
479 /**
480  * Session handle for connections.
481  */
482 struct Session
483 {
484
485   /**
486    * API requirement.
487    */
488   struct SessionHeader header;
489
490   /**
491    * Message currently pending for transmission
492    * to this peer, if any. head
493    */
494   struct PendingMessage *pending_message_head;
495
496   /**
497    * Message currently pending for transmission
498    * to this peer, if any. tail
499    */
500   struct PendingMessage *pending_message_tail;
501
502   /**
503    * To whom are we talking to (set to our identity
504    * if we are still waiting for the welcome message)
505    */
506   struct GNUNET_PeerIdentity target;
507
508   /**
509    * Address of the other peer (either based on our 'connect'
510    * call or on our 'accept' call).
511    */
512   void *connect_addr;
513
514   /**
515    * Last activity on this connection.  Used to select preferred
516    * connection and timeout
517    */
518   struct GNUNET_TIME_Absolute last_activity;
519
520   /**
521    * Timeout task.
522    */
523   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
524
525   /**
526    * peer connection
527    */
528   struct MacEndpoint *mac;
529
530   /**
531    * count of messages in the fragment out queue for this session
532    */
533
534   int fragment_messages_out_count;
535
536 };
537
538 /**
539  * Struct to represent one network card connection
540  */
541 struct MacEndpoint
542 {
543   /**
544    * Pointer to the global plugin struct.
545    */
546   struct Plugin *plugin;
547
548   /**
549    * Struct to hold the session reachable over this mac; head
550    */
551   struct Sessionqueue *sessions_head;
552
553   /**
554    * Struct to hold the session reachable over this mac; tail
555    */
556   struct Sessionqueue *sessions_tail;
557
558   /**
559    * Messages currently sending
560    * to a peer, if any.
561    */
562   struct FragmentMessage *sending_messages_head;
563
564   /**
565    * Messages currently sending
566    * to a peer (tail), if any.
567    */
568   struct FragmentMessage *sending_messages_tail;
569
570   /**
571    * dll next
572    */
573   struct MacEndpoint *next;
574
575   /**
576    * dll prev
577    */
578   struct MacEndpoint *prev;
579
580   /**
581    * peer mac address
582    */
583   struct GNUNET_TRANSPORT_WLAN_MacAddress addr;
584
585   /**
586    * Defrag context for this mac endpoint
587    */
588   struct GNUNET_DEFRAGMENT_Context *defrag;
589
590   /**
591    * count of messages in the fragment out queue for this mac endpoint
592    */
593   int fragment_messages_out_count;
594
595   //TODO DOXIGEN
596   uint8_t rate;
597   uint16_t tx_power;
598   uint8_t antenna;
599
600   /**
601    * Duplicates received
602    */
603   int dups;
604
605   /**
606    * Fragments received
607    */
608   int fragc;
609
610   /**
611    * Acks received
612    */
613   int acks;
614
615   /**
616    * Last activity on this endpoint.  Used to select preferred
617    * connection.
618    */
619   struct GNUNET_TIME_Absolute last_activity;
620
621   /**
622    * Timeout task.
623    */
624   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
625 };
626
627 /**
628  * Struct for Messages in the fragment queue
629  */
630 struct FragmentMessage
631 {
632
633   /**
634    * Session this message belongs to
635    */
636   struct Session *session;
637
638   /**
639    * This is a doubly-linked list.
640    */
641   struct FragmentMessage *next;
642
643   /**
644    * This is a doubly-linked list.
645    */
646   struct FragmentMessage *prev;
647
648   /**
649    * Fragmentation context
650    */
651   struct GNUNET_FRAGMENT_Context *fragcontext;
652
653   /**
654    * Timeout value for the message.
655    */
656   struct GNUNET_TIME_Absolute timeout;
657
658   /**
659    * Timeout task.
660    */
661   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
662
663   /**
664    * pointer to the radiotap header
665    */
666   struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *radioHeader;
667 };
668
669
670 static void
671 do_transmit (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
672
673
674 static void
675 free_session (struct Plugin *plugin, struct Sessionqueue *queue,
676               int do_free_macendpoint);
677
678
679 static struct MacEndpoint *
680 create_macendpoint (struct Plugin *plugin, const struct GNUNET_TRANSPORT_WLAN_MacAddress *addr);
681
682
683 static void
684 finish_sending (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
685
686
687 /**
688  * Generates a nice hexdump of a memory area.
689  *
690  * \param  mem     pointer to memory to dump
691  * \param  length  how many bytes to dump
692  */
693 static void
694 hexdump (const void *mem, unsigned length)
695 {
696   char line[80];
697   char *src = (char *) mem;
698
699   printf ("dumping %u bytes from %p\r\n"
700           "       0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F    0123456789ABCDEF\r\n",
701           length, src);
702   unsigned i;
703   int j;
704
705   for (i = 0; i < length; i += 16, src += 16)
706   {
707     char *t = line;
708
709     t += sprintf (t, "%04x:  ", i);
710     for (j = 0; j < 16; j++)
711     {
712       if (i + j < length)
713         t += sprintf (t, "%02X", src[j] & 0xff);
714       else
715         t += sprintf (t, "  ");
716
717       t += sprintf (t, (j % 2) ? " " : "-");
718     }
719
720     t += sprintf (t, "  ");
721     for (j = 0; j < 16; j++)
722     {
723       if (i + j < length)
724       {
725         if (isprint ((unsigned char) src[j]))
726           t += sprintf (t, "%c", src[j]);
727         else
728           t += sprintf (t, ".");
729       }
730       else
731       {
732         t += sprintf (t, " ");
733       }
734     }
735
736     t += sprintf (t, "\r\n");
737     printf ("%s", line);
738   }
739 }
740
741
742 /**
743  * Function to find a MacEndpoint with a specific mac addr
744  * @param plugin pointer to the plugin struct
745  * @param addr pointer to the mac address
746  * @param create_new GNUNET_YES if a new end point should be created
747  * @return
748  */
749 static struct MacEndpoint *
750 get_macendpoint (struct Plugin *plugin, const struct GNUNET_TRANSPORT_WLAN_MacAddress *addr,
751                  int create_new)
752 {
753   struct MacEndpoint *queue = plugin->mac_head;
754
755   while (queue != NULL)
756   {
757     //GNUNET_assert (queue->sessions_head != NULL);
758     if (memcmp (addr, &queue->addr, sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)) == 0)
759       return queue;             /* session found */
760     queue = queue->next;
761   }
762
763   if (create_new == GNUNET_YES)
764   {
765     return create_macendpoint (plugin, addr);
766   }
767   else
768   {
769     return NULL;
770   }
771 }
772
773
774 /**
775  * search for a session with the macendpoint and peer id
776  *
777  * @param plugin pointer to the plugin struct
778  * @param endpoint pointer to the mac endpoint of the peer
779  * @param peer pointer to the peerid
780  * @return returns the session
781  */
782 static struct Session *
783 search_session (struct Plugin *plugin, const struct MacEndpoint *endpoint,
784                 const struct GNUNET_PeerIdentity *peer)
785 {
786   GNUNET_assert (endpoint != NULL);
787   struct Sessionqueue *queue = endpoint->sessions_head;
788
789   while (queue != NULL)
790   {
791     GNUNET_assert (queue->content != NULL);
792     if (memcmp
793         (peer, &queue->content->target,
794          sizeof (struct GNUNET_PeerIdentity)) == 0)
795       return queue->content;    /* session found */
796     queue = queue->next;
797   }
798   return NULL;
799 }
800
801 /**
802  * Function called for a quick conversion of the binary address to
803  * a numeric address.  Note that the caller must not free the
804  * address and that the next call to this function is allowed
805  * to override the address again.
806  *
807  * @param cls closure
808  * @param addr binary address
809  * @param addrlen length of the address
810  * @return string representing the same address
811  */
812 static const char *
813 wlan_plugin_address_to_string (void *cls, const void *addr, size_t addrlen)
814 {
815   static char ret[40];
816   const struct GNUNET_TRANSPORT_WLAN_MacAddress *mac;
817
818   if (addrlen != sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress))
819   {
820     GNUNET_break (0);
821     return NULL;
822   }
823   mac = addr;
824   GNUNET_snprintf (ret, sizeof (ret), "%s Mac-Address %X:%X:%X:%X:%X:%X",
825                    PROTOCOL_PREFIX, mac->mac[0], mac->mac[1], mac->mac[2],
826                    mac->mac[3], mac->mac[4], mac->mac[5]);
827
828   return ret;
829 }
830
831 /**
832  * Function for the scheduler if a session times out
833  * @param cls pointer to the Sessionqueue
834  * @param tc pointer to the GNUNET_SCHEDULER_TaskContext
835  */
836 static void
837 session_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
838 {
839   struct Sessionqueue *queue = cls;
840
841   GNUNET_assert (queue != NULL);
842   GNUNET_assert (queue->content != NULL);
843   queue->content->timeout_task = GNUNET_SCHEDULER_NO_TASK;
844   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
845   {
846     return;
847   }
848   if (GNUNET_TIME_absolute_get_remaining
849       (GNUNET_TIME_absolute_add
850        (queue->content->last_activity, SESSION_TIMEOUT)).rel_value == 0)
851   {
852
853     GNUNET_assert (queue->content->mac != NULL);
854     GNUNET_assert (queue->content->mac->plugin != NULL);
855     GNUNET_STATISTICS_update (queue->content->mac->plugin->env->stats,
856                               _("# wlan session timeouts"), 1, GNUNET_NO);
857     free_session (queue->content->mac->plugin, queue, GNUNET_YES);
858   }
859   else
860   {
861     queue->content->timeout_task =
862         GNUNET_SCHEDULER_add_delayed (SESSION_TIMEOUT, &session_timeout, queue);
863   }
864 }
865
866 /**
867  * create a new session
868  *
869  * @param plugin pointer to the plugin struct
870  * @param endpoint pointer to the mac endpoint of the peer
871  * @param peer peer identity to use for this session
872  * @return returns the session
873  */
874 static struct Session *
875 create_session (struct Plugin *plugin, struct MacEndpoint *endpoint,
876                 const struct GNUNET_PeerIdentity *peer)
877 {
878   GNUNET_assert (endpoint != NULL);
879   GNUNET_assert (plugin != NULL);
880   GNUNET_STATISTICS_update (plugin->env->stats, _("# wlan session created"), 1,
881                             GNUNET_NO);
882   struct Sessionqueue *queue =
883       GNUNET_malloc (sizeof (struct Sessionqueue) + sizeof (struct Session));
884
885   GNUNET_CONTAINER_DLL_insert_tail (endpoint->sessions_head,
886                                     endpoint->sessions_tail, queue);
887
888   queue->content = (struct Session *) &queue[1];
889   queue->content->mac = endpoint;
890   queue->content->target = *peer;
891   queue->content->last_activity = GNUNET_TIME_absolute_get ();
892   queue->content->timeout_task =
893       GNUNET_SCHEDULER_add_delayed (SESSION_TIMEOUT, &session_timeout, queue);
894
895   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
896                    "New session %p with endpoint %p: %s\n", queue->content,
897                    endpoint, wlan_plugin_address_to_string (NULL,
898                                                             endpoint->addr.mac,
899                                                             6));
900   return queue->content;
901 }
902
903 /**
904  * Get session from address, create if no session exists
905  *
906  * @param plugin pointer to the plugin struct
907  * @param addr pointer to the mac address of the peer
908  * @param peer pointer to the peerid
909  * @return returns the session
910  */
911 static struct Session *
912 get_session (struct Plugin *plugin, const struct GNUNET_TRANSPORT_WLAN_MacAddress *addr,
913              const struct GNUNET_PeerIdentity *peer)
914 {
915   struct MacEndpoint *mac;
916
917   mac = get_macendpoint (plugin, addr, GNUNET_YES);
918   struct Session *session = search_session (plugin, mac, peer);
919
920   if (session != NULL)
921     return session;
922   return create_session (plugin, mac, peer);
923 }
924
925 /**
926  * Queue the session to send data
927  * checks if there is a message pending
928  * checks if this session is not allready in the queue
929  * @param plugin pointer to the plugin
930  * @param session pointer to the session to add
931  */
932 static void
933 queue_session (struct Plugin *plugin, struct Session *session)
934 {
935   struct Sessionqueue *queue = plugin->pending_Sessions_head;
936
937   if (session->pending_message_head != NULL)
938   {
939     while (queue != NULL)
940     {
941       // content is never NULL
942       GNUNET_assert (queue->content != NULL);
943       // is session already in queue?
944       if (session == queue->content)
945       {
946         return;
947       }
948       // try next
949       queue = queue->next;
950     }
951
952     // Session is not in the queue
953
954     queue = GNUNET_malloc (sizeof (struct Sessionqueue));
955     queue->content = session;
956
957     //insert at the tail
958     GNUNET_CONTAINER_DLL_insert_tail (plugin->pending_Sessions_head,
959                                       plugin->pending_Sessions_tail, queue);
960     plugin->pendingsessions++;
961     GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending sessions"),
962                            plugin->pendingsessions, GNUNET_NO);
963   }
964
965 }
966
967 /**
968  * Function to schedule the write task, executed after a delay
969  * @param cls pointer to the plugin struct
970  * @param tc GNUNET_SCHEDULER_TaskContext pointer
971  */
972 static void
973 delay_fragment_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
974 {
975   struct Plugin *plugin = cls;
976
977   plugin->server_write_delay_task = GNUNET_SCHEDULER_NO_TASK;
978
979   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
980     return;
981
982   // GNUNET_TIME_UNIT_FOREVER_REL is needed to clean up old msg
983   if (plugin->server_write_task == GNUNET_SCHEDULER_NO_TASK)
984   {
985     plugin->server_write_task =
986         GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL,
987                                          plugin->server_stdin_handle,
988                                          &do_transmit, plugin);
989   }
990 }
991
992 /**
993  * Function to calculate the time of the next periodic "hello-beacon"
994  * @param plugin pointer to the plugin struct
995  */
996 static void
997 set_next_beacon_time (struct Plugin *const plugin)
998 {
999   //under 10 known peers: once a second
1000   if (plugin->mac_count < 10)
1001   {
1002     plugin->beacon_time =
1003         GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
1004                                   GNUNET_TIME_relative_multiply
1005                                   (GNUNET_TIME_UNIT_SECONDS,
1006                                    HELLO_BEACON_SCALING_FACTOR));
1007   }
1008   //under 30 known peers: every 10 seconds
1009   else if (plugin->mac_count < 30)
1010   {
1011     plugin->beacon_time =
1012         GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
1013                                   GNUNET_TIME_relative_multiply
1014                                   (GNUNET_TIME_UNIT_SECONDS,
1015                                    10 * HELLO_BEACON_SCALING_FACTOR));
1016   }
1017   //over 30 known peers: once a minute
1018   else
1019   {
1020     plugin->beacon_time =
1021         GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
1022                                   GNUNET_TIME_relative_multiply
1023                                   (GNUNET_TIME_UNIT_MINUTES,
1024                                    HELLO_BEACON_SCALING_FACTOR));
1025   }
1026 }
1027
1028 /**
1029  * Function to set the timer for the next timeout of the fragment queue
1030  * @param plugin the handle to the plugin struct
1031  */
1032 static void
1033 set_next_send (struct Plugin *const plugin)
1034 {
1035   struct GNUNET_TIME_Relative next_send;
1036
1037   //abort if helper is not running
1038   if (plugin->helper_is_running == GNUNET_NO)
1039   {
1040     return;
1041   }
1042
1043   //cancel old task
1044   if (plugin->server_write_delay_task != GNUNET_SCHEDULER_NO_TASK)
1045   {
1046     GNUNET_SCHEDULER_cancel (plugin->server_write_delay_task);
1047     plugin->server_write_delay_task = GNUNET_SCHEDULER_NO_TASK;
1048   }
1049
1050   //check if some acks are in the queue
1051   if (plugin->ack_send_queue_head != NULL)
1052   {
1053     next_send = GNUNET_TIME_UNIT_ZERO;
1054   }
1055
1056   //check if there are some fragments in the queue
1057   else if (plugin->sending_messages_head != NULL)
1058   {
1059     next_send = GNUNET_TIME_UNIT_ZERO;
1060   }
1061   else
1062   {
1063     next_send = GNUNET_TIME_absolute_get_remaining (plugin->beacon_time);
1064   }
1065
1066   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
1067                    "Next packet is send in: %u\n", next_send.rel_value);
1068   if (next_send.rel_value == GNUNET_TIME_UNIT_ZERO.rel_value)
1069   {
1070     if (plugin->server_write_task == GNUNET_SCHEDULER_NO_TASK)
1071     {
1072       plugin->server_write_task =
1073           GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL,
1074                                            plugin->server_stdin_handle,
1075                                            &do_transmit, plugin);
1076     }
1077   }
1078   else
1079   {
1080     if (plugin->server_write_delay_task == GNUNET_SCHEDULER_NO_TASK)
1081     {
1082       plugin->server_write_delay_task =
1083           GNUNET_SCHEDULER_add_delayed (next_send, &delay_fragment_task,
1084                                         plugin);
1085     }
1086   }
1087 }
1088
1089 /**
1090  * Function to get the next queued Session, removes the session from the queue
1091  * @param plugin pointer to the plugin struct
1092  * @return pointer to the session found, returns NULL if there is now session in the queue
1093  */
1094 static struct Session *
1095 get_next_queue_session (struct Plugin *plugin)
1096 {
1097   struct Session *session;
1098   struct Sessionqueue *sessionqueue;
1099   struct Sessionqueue *sessionqueue_alt;
1100   struct PendingMessage *pm;
1101
1102   sessionqueue = plugin->pending_Sessions_head;
1103
1104   while (sessionqueue != NULL)
1105   {
1106     session = sessionqueue->content;
1107
1108     GNUNET_assert (session != NULL);
1109     pm = session->pending_message_head;
1110
1111     if (pm == NULL)
1112     {
1113       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME,
1114                        "pending message is empty, should not happen. session %p\n",
1115                        session);
1116       sessionqueue_alt = sessionqueue;
1117       sessionqueue = sessionqueue->next;
1118       plugin->pendingsessions--;
1119       GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending sessions"),
1120                              plugin->pendingsessions, GNUNET_NO);
1121       GNUNET_CONTAINER_DLL_remove (plugin->pending_Sessions_head,
1122                                    plugin->pending_Sessions_tail,
1123                                    sessionqueue_alt);
1124
1125       GNUNET_free (sessionqueue_alt);
1126       continue;
1127
1128     }
1129
1130     //check for message timeout
1131     if (GNUNET_TIME_absolute_get_remaining (pm->timeout).rel_value > 0)
1132     {
1133       //check if session has no message in the fragment queue
1134       if ((session->mac->fragment_messages_out_count <
1135            FRAGMENT_QUEUE_MESSAGES_OUT_PER_MACENDPOINT) &&
1136           (session->fragment_messages_out_count <
1137            FRAGMENT_QUEUE_MESSAGES_OUT_PER_SESSION))
1138       {
1139         plugin->pendingsessions--;
1140         GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending sessions"),
1141                                plugin->pendingsessions, GNUNET_NO);
1142         GNUNET_CONTAINER_DLL_remove (plugin->pending_Sessions_head,
1143                                      plugin->pending_Sessions_tail,
1144                                      sessionqueue);
1145         GNUNET_free (sessionqueue);
1146
1147         return session;
1148       }
1149       else
1150       {
1151         sessionqueue = sessionqueue->next;
1152       }
1153     }
1154     else
1155     {
1156       GNUNET_CONTAINER_DLL_remove (session->pending_message_head,
1157                                    session->pending_message_tail, pm);
1158
1159       //call the cont func that it did not work
1160       if (pm->transmit_cont != NULL)
1161         pm->transmit_cont (pm->transmit_cont_cls, &(session->target),
1162                            GNUNET_SYSERR);
1163       GNUNET_free (pm->msg);
1164       GNUNET_free (pm);
1165
1166       if (session->pending_message_head == NULL)
1167       {
1168         sessionqueue_alt = sessionqueue;
1169         sessionqueue = sessionqueue->next;
1170         plugin->pendingsessions--;
1171         GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending sessions"),
1172                                plugin->pendingsessions, GNUNET_NO);
1173         GNUNET_CONTAINER_DLL_remove (plugin->pending_Sessions_head,
1174                                      plugin->pending_Sessions_tail,
1175                                      sessionqueue_alt);
1176
1177         GNUNET_free (sessionqueue_alt);
1178       }
1179     }
1180
1181   }
1182   return NULL;
1183 }
1184
1185 /**
1186  * frees the space of a message in the fragment queue (send queue)
1187  * @param plugin the plugin struct
1188  * @param fm message to free
1189  */
1190 static void
1191 free_fragment_message (struct Plugin *plugin, struct FragmentMessage *fm)
1192 {
1193   struct Session *session = fm->session;
1194   struct MacEndpoint *endpoint = session->mac;
1195   struct FragmentMessage_queue *fmq;
1196   struct FragmentMessage_queue *fmq_next;
1197
1198   fmq = plugin->sending_messages_head;
1199   while (fmq != NULL)
1200   {
1201     fmq_next = fmq->next;
1202     if (fmq->content == fm)
1203     {
1204       GNUNET_CONTAINER_DLL_remove (plugin->sending_messages_head,
1205                                    plugin->sending_messages_tail, fmq);
1206       GNUNET_free (fmq);
1207     }
1208     fmq = fmq_next;
1209   }
1210
1211   session->mac->fragment_messages_out_count--;
1212   session->fragment_messages_out_count--;
1213   plugin->pending_Fragment_Messages--;
1214   GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending fragments"),
1215                          plugin->pending_Fragment_Messages, GNUNET_NO);
1216   GNUNET_CONTAINER_DLL_remove (endpoint->sending_messages_head,
1217                                endpoint->sending_messages_tail, fm);
1218   GNUNET_FRAGMENT_context_destroy (fm->fragcontext);
1219   if (fm->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1220   {
1221     GNUNET_SCHEDULER_cancel (fm->timeout_task);
1222     fm->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1223   }
1224   GNUNET_free (fm);
1225   queue_session (plugin, session);
1226   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
1227                    "Free pending fragment messages %p, session %p\n", fm,
1228                    session);
1229 }
1230
1231
1232 /**
1233  * function to fill the radiotap header
1234  *
1235  * @param plugin pointer to the plugin struct
1236  * @param endpoint pointer to the endpoint
1237  * @param header pointer to the radiotap header
1238  * @param size total message size
1239  * @return GNUNET_YES at success
1240  */
1241 static int
1242 getRadiotapHeader (struct Plugin *plugin, struct MacEndpoint *endpoint,
1243                    struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *header,
1244                    uint16_t size)
1245 {
1246   header->header.type = ntohs (GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA);
1247   header->header.size = ntohs (size);
1248   if (endpoint != NULL)
1249   {
1250     header->rate = endpoint->rate;
1251     header->tx_power = endpoint->tx_power;
1252     header->antenna = endpoint->antenna;
1253   }
1254   else
1255   {
1256     header->rate = 255;
1257     header->tx_power = 0;
1258     header->antenna = 0;
1259   }
1260
1261   return GNUNET_YES;
1262 }
1263
1264
1265 /**
1266  * function to generate the wlan hardware header for one packet
1267  * @param Header address to write the header to
1268  * @param to_mac_addr address of the recipient
1269  * @param plugin pointer to the plugin struct
1270  * @param size size of the whole packet, needed to calculate the time to send the packet
1271  *        FIXME: 'size' is initialized inconsistently throughout the code (sometimes payload, sometimes everything)
1272  * @return GNUNET_YES if there was no error
1273  */
1274 static int
1275 getWlanHeader (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *Header,
1276                const struct GNUNET_TRANSPORT_WLAN_MacAddress *to_mac_addr, struct Plugin *plugin,
1277                unsigned int size)
1278 {
1279   const int rate = 11000000;
1280
1281   Header->frame_control = htons (IEEE80211_FC0_TYPE_DATA); // FIXME: check: might need to shift by 8?
1282   Header->addr1 = *to_mac_addr;
1283   Header->addr2 = plugin->mac_address;
1284   Header->addr3 = mac_bssid_gnunet;
1285   Header->duration = GNUNET_htole16 ((size * 1000000) / rate + 290);
1286   Header->sequence_control = 0; // FIXME?
1287   Header->llc[0] = WLAN_LLC_DSAP_FIELD;
1288   Header->llc[1] = WLAN_LLC_SSAP_FIELD;
1289   Header->llc[2] = 0;  // FIXME?
1290   Header->llc[3] = 0;  // FIXME?
1291   return GNUNET_YES;
1292 }
1293
1294
1295 /**
1296  * function to add a fragment of a message to send
1297  * @param cls FragmentMessage this message belongs to
1298  * @param hdr pointer to the start of the message
1299  */
1300 static void
1301 add_message_for_send (void *cls, const struct GNUNET_MessageHeader *hdr)
1302 {
1303   struct FragmentMessage *fm = cls;
1304   struct FragmentMessage_queue *fmqueue;
1305   struct MacEndpoint *endpoint;
1306   struct Plugin *plugin;
1307   uint16_t size;
1308
1309   GNUNET_assert (cls != NULL);
1310   endpoint = fm->session->mac;
1311   plugin = endpoint->plugin;
1312
1313   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
1314                    "Adding fragment of message %p to send, session %p, endpoint %p, type %u\n",
1315                    fm, fm->session, endpoint, hdr->type);
1316   size = sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage) + ntohs (hdr->size);
1317   fm->radioHeader = GNUNET_malloc (size);
1318   getRadiotapHeader (plugin, fm->session->mac, fm->radioHeader, size);
1319   getWlanHeader (&fm->radioHeader->frame, &(fm->session->mac->addr), plugin,
1320                  size);
1321   memcpy (&fm->radioHeader[1], hdr, ntohs (hdr->size));
1322   // FIXME: yucky allocation structure!
1323   fmqueue = GNUNET_malloc (sizeof (struct FragmentMessage_queue));
1324   fmqueue->content = fm;
1325   GNUNET_CONTAINER_DLL_insert_tail (plugin->sending_messages_head,
1326                                     plugin->sending_messages_tail, fmqueue);
1327   set_next_send (plugin);
1328 }
1329
1330
1331 /**
1332  * We have been notified that gnunet-helper-transport-wlan has written something to stdout.
1333  * Handle the output, then reschedule this function to be called again once
1334  * more is available.
1335  *
1336  * @param cls the plugin handle
1337  * @param tc the scheduling context
1338  */
1339 static void
1340 wlan_plugin_helper_read (void *cls,
1341                          const struct GNUNET_SCHEDULER_TaskContext *tc)
1342 {
1343   struct Plugin *plugin = cls;
1344
1345   plugin->server_read_task = GNUNET_SCHEDULER_NO_TASK;
1346
1347   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1348     return;
1349
1350   char mybuf[WLAN_MTU + sizeof (struct GNUNET_MessageHeader)];
1351   ssize_t bytes;
1352
1353   bytes =
1354       GNUNET_DISK_file_read (plugin->server_stdout_handle, mybuf,
1355                              sizeof (mybuf));
1356   if (bytes <= 0)
1357   {
1358     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
1359                      _
1360                      ("Finished reading from gnunet-helper-transport-wlan stdout with code: %d\n"),
1361                      bytes);
1362     return;
1363   }
1364   GNUNET_SERVER_mst_receive (plugin->suid_tokenizer, NULL, mybuf, bytes,
1365                              GNUNET_NO, GNUNET_NO);
1366
1367   GNUNET_assert (plugin->server_read_task == GNUNET_SCHEDULER_NO_TASK);
1368   plugin->server_read_task =
1369       GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
1370                                       plugin->server_stdout_handle,
1371                                       &wlan_plugin_helper_read, plugin);
1372 }
1373
1374 /**
1375  * Start the gnunet-helper-transport-wlan process.
1376  *
1377  * @param plugin the transport plugin
1378  * @return GNUNET_YES if process was started, GNUNET_SYSERR on error
1379  */
1380 static int
1381 wlan_transport_start_wlan_helper (struct Plugin *plugin)
1382 {
1383   const char *filenamehw = "gnunet-helper-transport-wlan";
1384   const char *filenameloopback = "gnunet-helper-transport-wlan-dummy";
1385   char *absolute_filename = NULL;
1386
1387   if (plugin->helper_is_running == GNUNET_YES)
1388   {
1389     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
1390                      "wlan_transport_start_wlan_helper not needed, helper already running!");
1391     return GNUNET_YES;
1392   }
1393
1394   plugin->server_stdout = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES);
1395   if (plugin->server_stdout == NULL)
1396     return GNUNET_SYSERR;
1397
1398   plugin->server_stdin = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_YES, GNUNET_NO);
1399   if (plugin->server_stdin == NULL)
1400     return GNUNET_SYSERR;
1401
1402   if ((plugin->testmode == 1) || (plugin->testmode == 2))
1403   {
1404     if (GNUNET_OS_check_helper_binary (filenameloopback) == GNUNET_YES)
1405     {
1406       absolute_filename = GNUNET_strdup (filenameloopback);
1407     }
1408     else
1409     {
1410       char cwd[FILENAME_MAX];
1411
1412       GNUNET_assert (getcwd (cwd, sizeof (cwd)) != NULL);
1413
1414       GNUNET_asprintf (&absolute_filename, "%s%s%s", cwd, DIR_SEPARATOR_STR,
1415                        filenameloopback);
1416
1417       if (GNUNET_DISK_file_test (filenameloopback) != GNUNET_YES)
1418       {
1419         GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME,
1420                          "Helper `%s' not found! %i\n", absolute_filename);
1421         GNUNET_break (0);
1422       }
1423     }
1424   }
1425
1426   /* Start the server process */
1427
1428   if (plugin->testmode == 0)
1429   {
1430
1431     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
1432                      "Starting gnunet-helper-transport-wlan process cmd: %s %s %i\n",
1433                      filenamehw, plugin->interface, plugin->testmode);
1434     if (GNUNET_OS_check_helper_binary (filenamehw) == GNUNET_YES)
1435     {
1436       plugin->server_proc =
1437           GNUNET_OS_start_process (GNUNET_NO, plugin->server_stdin, plugin->server_stdout,
1438                                    filenamehw, filenamehw, plugin->interface,
1439                                    NULL);
1440     }
1441     else if (GNUNET_OS_check_helper_binary (filenamehw) == GNUNET_NO)
1442     {
1443       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME,
1444                        "gnunet-helper-transport-wlan is not suid, please change it or look at the doku\n");
1445       GNUNET_break (0);
1446     }
1447     else
1448     {
1449       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME,
1450                        "gnunet-helper-transport-wlan not found, please look if it exists and is the $PATH variable!\n");
1451       GNUNET_break (0);
1452     }
1453
1454   }
1455   else if (plugin->testmode == 1)
1456   {
1457
1458     GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, PLUGIN_LOG_NAME,
1459                      "Starting gnunet-helper-transport-wlan-dummy loopback 1 process cmd: %s %s %i\n",
1460                      absolute_filename, plugin->interface, plugin->testmode);
1461     plugin->server_proc =
1462         GNUNET_OS_start_process (GNUNET_NO, plugin->server_stdin, plugin->server_stdout,
1463                                  absolute_filename, absolute_filename, "1",
1464                                  NULL);
1465     if (plugin->server_proc == NULL)
1466     {
1467       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME,
1468                        "`%s' not found, please look if it exists and is in the $PATH variable!\n",
1469                        absolute_filename);
1470       GNUNET_break (0);
1471     }
1472   }
1473   else if (plugin->testmode == 2)
1474   {
1475     GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, PLUGIN_LOG_NAME,
1476                      "Starting gnunet-helper-transport-wlan-dummy loopback 2 process cmd: %s %s %i\n",
1477                      absolute_filename, plugin->interface, plugin->testmode);
1478     plugin->server_proc =
1479         GNUNET_OS_start_process (GNUNET_NO, plugin->server_stdin, plugin->server_stdout,
1480                                  absolute_filename, absolute_filename, "2",
1481                                  NULL);
1482     if (plugin->server_proc == NULL)
1483     {
1484       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME,
1485                        "`%s' not found, please look if it exists and is in the $PATH variable!\n",
1486                        absolute_filename);
1487       GNUNET_break (0);
1488     }
1489   }
1490   if (absolute_filename != NULL)
1491     GNUNET_free (absolute_filename);
1492   if (plugin->server_proc == NULL)
1493   {
1494     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
1495                      "Failed to start gnunet-helper-transport-wlan process\n");
1496     return GNUNET_SYSERR;
1497   }
1498
1499
1500
1501   /* Close the write end of the read pipe */
1502   GNUNET_DISK_pipe_close_end (plugin->server_stdout,
1503                               GNUNET_DISK_PIPE_END_WRITE);
1504
1505   /* Close the read end of the write pipe */
1506   GNUNET_DISK_pipe_close_end (plugin->server_stdin, GNUNET_DISK_PIPE_END_READ);
1507
1508   plugin->server_stdout_handle =
1509       GNUNET_DISK_pipe_handle (plugin->server_stdout,
1510                                GNUNET_DISK_PIPE_END_READ);
1511   plugin->server_stdin_handle =
1512       GNUNET_DISK_pipe_handle (plugin->server_stdin,
1513                                GNUNET_DISK_PIPE_END_WRITE);
1514
1515   GNUNET_assert (plugin->server_read_task == GNUNET_SCHEDULER_NO_TASK);
1516
1517   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
1518                    "Adding server_read_task for the gnunet-helper-transport-wlan\n");
1519   plugin->server_read_task =
1520       GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
1521                                       plugin->server_stdout_handle,
1522                                       &wlan_plugin_helper_read, plugin);
1523
1524   plugin->helper_is_running = GNUNET_YES;
1525   return GNUNET_YES;
1526 }
1527
1528 /**
1529  * Stops the gnunet-helper-transport-wlan process.
1530  *
1531  * @param plugin the transport plugin
1532  * @return GNUNET_YES if process was started, GNUNET_SYSERR on error
1533  */
1534 static int
1535 wlan_transport_stop_wlan_helper (struct Plugin *plugin)
1536 {
1537   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
1538                    "Stoping WLAN helper process\n");
1539
1540   if (plugin->helper_is_running == GNUNET_NO)
1541   {
1542     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
1543                      "wlan_transport_stop_wlan_helper not needed, helper already stopped!");
1544     return GNUNET_YES;
1545   }
1546
1547   if (plugin->server_write_delay_task != GNUNET_SCHEDULER_NO_TASK)
1548   {
1549     GNUNET_SCHEDULER_cancel (plugin->server_write_delay_task);
1550     plugin->server_write_delay_task = GNUNET_SCHEDULER_NO_TASK;
1551   }
1552
1553   if (plugin->server_write_task != GNUNET_SCHEDULER_NO_TASK)
1554   {
1555     GNUNET_SCHEDULER_cancel (plugin->server_write_task);
1556     plugin->server_write_task = GNUNET_SCHEDULER_NO_TASK;
1557   }
1558
1559   if (plugin->server_read_task != GNUNET_SCHEDULER_NO_TASK)
1560   {
1561     GNUNET_SCHEDULER_cancel (plugin->server_read_task);
1562     plugin->server_read_task = GNUNET_SCHEDULER_NO_TASK;
1563   }
1564
1565   GNUNET_DISK_pipe_close (plugin->server_stdout);
1566   GNUNET_DISK_pipe_close (plugin->server_stdin);
1567   GNUNET_OS_process_kill (plugin->server_proc, SIGKILL);
1568   GNUNET_OS_process_wait (plugin->server_proc);
1569   GNUNET_OS_process_close (plugin->server_proc);
1570
1571   plugin->helper_is_running = GNUNET_NO;
1572
1573   return GNUNET_YES;
1574 }
1575
1576 /**
1577  * function for delayed restart of the helper process
1578  * @param cls Finish_send struct if message should be finished
1579  * @param tc TaskContext
1580  */
1581 static void
1582 delay_restart_helper (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1583 {
1584   struct Finish_send *finish = cls;
1585   struct Plugin *plugin;
1586
1587   plugin = finish->plugin;
1588
1589   plugin->server_write_task = GNUNET_SCHEDULER_NO_TASK;
1590   if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
1591   {
1592     GNUNET_free_non_null (finish->msgstart);
1593     GNUNET_free (finish);
1594     return;
1595   }
1596
1597   wlan_transport_start_wlan_helper (plugin);
1598
1599   if (finish->size != 0)
1600   {
1601     plugin->server_write_task =
1602         GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL,
1603                                          plugin->server_stdin_handle,
1604                                          &finish_sending, finish);
1605   }
1606   else
1607   {
1608     set_next_send (plugin);
1609     GNUNET_free_non_null (finish->msgstart);
1610     GNUNET_free (finish);
1611   }
1612
1613 }
1614
1615 /**
1616  * Function to restart the helper
1617  * @param plugin pointer to the global plugin struct
1618  * @param finish pointer to the Finish_send struct to finish
1619  */
1620 static void
1621 restart_helper (struct Plugin *plugin, struct Finish_send *finish)
1622 {
1623   static struct GNUNET_TIME_Relative next_try = { 1000 };
1624   GNUNET_assert (finish != NULL);
1625
1626   wlan_transport_stop_wlan_helper (plugin);
1627   plugin->server_write_task =
1628       GNUNET_SCHEDULER_add_delayed (next_try, &delay_restart_helper, finish);
1629   GNUNET_TIME_relative_multiply (next_try, HELPER_RESTART_SCALING_FACTOR);
1630
1631 }
1632
1633 /**
1634  * function to finish a sending if not all could have been writen befor
1635  * @param cls pointer to the Finish_send struct
1636  * @param tc TaskContext
1637  */
1638 static void
1639 finish_sending (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1640 {
1641   struct Finish_send *finish = cls;
1642   struct Plugin *plugin;
1643   ssize_t bytes;
1644
1645   plugin = finish->plugin;
1646   plugin->server_write_task = GNUNET_SCHEDULER_NO_TASK;
1647
1648   if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
1649   {
1650     GNUNET_free (finish->msgstart);
1651     GNUNET_free (finish);
1652     return;
1653   }
1654   bytes =
1655       GNUNET_DISK_file_write (plugin->server_stdin_handle,
1656                               finish->head_of_next_write, finish->size);
1657
1658   if (bytes != finish->size)
1659   {
1660     if (bytes != GNUNET_SYSERR)
1661     {
1662       finish->head_of_next_write += bytes;
1663       finish->size -= bytes;
1664       plugin->server_write_task =
1665           GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL,
1666                                            plugin->server_stdin_handle,
1667                                            &finish_sending, finish);
1668     }
1669     else
1670     {
1671       restart_helper (plugin, finish);
1672     }
1673   }
1674   else
1675   {
1676     GNUNET_free (finish->msgstart);
1677     GNUNET_free (finish);
1678     set_next_send (plugin);
1679   }
1680 }
1681
1682
1683 /**
1684  * function to send a hello beacon
1685  * @param plugin pointer to the plugin struct
1686  */
1687 static void
1688 send_hello_beacon (struct Plugin *plugin)
1689 {
1690   uint16_t size;
1691   ssize_t bytes;
1692   uint16_t hello_size;
1693   struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *radioHeader;
1694   const struct GNUNET_MessageHeader *hello;
1695   struct Finish_send *finish;
1696
1697   GNUNET_assert (plugin != NULL);
1698   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
1699                    "Sending hello beacon\n");
1700   GNUNET_STATISTICS_update (plugin->env->stats, _("# wlan hello beacons send"),
1701                             1, GNUNET_NO);
1702   hello = plugin->env->get_our_hello ();
1703   hello_size = GNUNET_HELLO_size ((struct GNUNET_HELLO_Message *) hello);
1704   GNUNET_assert (sizeof (struct WlanHeader) + hello_size <= WLAN_MTU);
1705
1706   size = sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage) + hello_size;
1707   radioHeader = GNUNET_malloc (size);
1708   getRadiotapHeader (plugin, NULL, radioHeader, size);
1709   getWlanHeader (&radioHeader->frame, &bc_all_mac, plugin, size);
1710   memcpy (&radioHeader[1], hello, hello_size);
1711   bytes = GNUNET_DISK_file_write (plugin->server_stdin_handle, radioHeader, size);
1712   GNUNET_free (radioHeader);
1713   if (bytes == GNUNET_SYSERR)
1714   {
1715     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME,
1716                      _
1717                      ("Error writing to wlan helper. errno == %d, ERROR: %s\n"),
1718                      errno, strerror (errno));
1719     finish = GNUNET_malloc (sizeof (struct Finish_send));
1720     finish->plugin = plugin;
1721     finish->head_of_next_write = NULL;
1722     finish->size = 0;
1723     finish->msgstart = NULL;
1724     restart_helper (plugin, finish);
1725     set_next_beacon_time (plugin);
1726   }
1727   else
1728   {
1729     GNUNET_assert (bytes == size);
1730     set_next_beacon_time (plugin);
1731     set_next_send (plugin);
1732   }
1733 }
1734
1735
1736 /**
1737  * function to add an ack to send it for a received fragment
1738  *
1739  * @param cls MacEndpoint this ack belongs to
1740  * @param msg_id id of the message
1741  * @param hdr pointer to the hdr where the ack is stored
1742  */
1743 static void
1744 add_ack_for_send (void *cls, uint32_t msg_id,
1745                   const struct GNUNET_MessageHeader *hdr)
1746 {
1747   struct MacEndpoint *endpoint = cls;
1748   struct Plugin *plugin = endpoint->plugin;
1749   struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage* radioHeader;
1750   struct AckSendQueue *ack;
1751   struct GNUNET_MessageHeader *msgheader;
1752   uint16_t size;
1753
1754   GNUNET_assert (endpoint != NULL);
1755   size = sizeof (struct AckSendQueue) + sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage) + ntohs (hdr->size);
1756   ack = GNUNET_malloc (size);
1757   ack->message_id = msg_id;
1758   ack->endpoint = endpoint;
1759   radioHeader = (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage*) &ack[1];
1760   ack->radioHeader = radioHeader;
1761   getRadiotapHeader (plugin, ack->endpoint, radioHeader, size - sizeof (struct AckSendQueue));
1762   size = ntohs (hdr->size);
1763   getWlanHeader (&radioHeader->frame, 
1764                  &ack->endpoint->addr, 
1765                  plugin,
1766                  size);
1767   msgheader = (struct GNUNET_MessageHeader *) &radioHeader[1];
1768   memcpy (msgheader, hdr, size);
1769   GNUNET_CONTAINER_DLL_insert_tail (plugin->ack_send_queue_head,
1770                                     plugin->ack_send_queue_tail, ack);
1771   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
1772                    "Adding ack with message id %u to send, AckSendQueue %p, endpoint %p\n",
1773                    msg_id, ack, endpoint);
1774   set_next_send (plugin);
1775 }
1776
1777
1778 /**
1779  * Function for the scheduler if a FragmentMessage times out
1780  * @param cls pointer to the FragmentMessage
1781  * @param tc pointer to the GNUNET_SCHEDULER_TaskContext
1782  */
1783 static void
1784 fragmentmessage_timeout (void *cls,
1785                          const struct GNUNET_SCHEDULER_TaskContext *tc)
1786 {
1787   struct FragmentMessage *fm = cls;
1788
1789   GNUNET_assert (fm != NULL);
1790   fm->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1791   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
1792   {
1793     return;
1794   }
1795   free_fragment_message (fm->session->mac->plugin, fm);
1796 }
1797
1798 /**
1799  * Function to check if there is some space in the fragment queue
1800  * inserts a message if space is available
1801  * @param plugin the plugin struct
1802  */
1803
1804 static void
1805 check_fragment_queue (struct Plugin *plugin)
1806 {
1807   struct Session *session;
1808   struct FragmentMessage *fm;
1809   struct GNUNET_PeerIdentity pid;
1810
1811   struct PendingMessage *pm;
1812
1813   if (plugin->pending_Fragment_Messages < FRAGMENT_QUEUE_SIZE)
1814   {
1815     session = get_next_queue_session (plugin);
1816     if (session != NULL)
1817     {
1818       pm = session->pending_message_head;
1819       GNUNET_assert (pm != NULL);
1820       GNUNET_CONTAINER_DLL_remove (session->pending_message_head,
1821                                    session->pending_message_tail, pm);
1822       session->mac->fragment_messages_out_count++;
1823       session->fragment_messages_out_count++;
1824       plugin->pending_Fragment_Messages++;
1825       GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending fragments"),
1826                              plugin->pending_Fragment_Messages, GNUNET_NO);
1827
1828       fm = GNUNET_malloc (sizeof (struct FragmentMessage));
1829       fm->session = session;
1830       fm->timeout.abs_value = pm->timeout.abs_value;
1831       fm->fragcontext =
1832           GNUNET_FRAGMENT_context_create (plugin->env->stats, WLAN_MTU,
1833                                           &plugin->tracker,
1834                                           GNUNET_TIME_UNIT_SECONDS,
1835                                           &(pm->msg->header),
1836                                           &add_message_for_send, fm);
1837       fm->timeout_task =
1838           GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
1839                                         (fm->timeout), fragmentmessage_timeout,
1840                                         fm);
1841       GNUNET_CONTAINER_DLL_insert_tail (session->mac->sending_messages_head,
1842                                         session->mac->sending_messages_tail,
1843                                         fm);
1844
1845       if (pm->transmit_cont != NULL)
1846       {
1847         pid = session->target;
1848         pm->transmit_cont (pm->transmit_cont_cls, &pid, GNUNET_OK);
1849         GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
1850                          "called pm->transmit_cont for %p\n", session);
1851       }
1852       else
1853       {
1854         GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
1855                          "no pm->transmit_cont for %p\n", session);
1856       }
1857       GNUNET_free (pm);
1858
1859       if (session->pending_message_head != NULL)
1860       {
1861         //requeue session
1862         queue_session (plugin, session);
1863       }
1864
1865     }
1866   }
1867
1868   //check if timeout changed
1869   set_next_send (plugin);
1870 }
1871
1872
1873 /**
1874  * Function to send an ack, does not free the ack
1875  * @param plugin pointer to the plugin
1876  */
1877 static void
1878 send_ack (struct Plugin *plugin)
1879 {
1880   ssize_t bytes;
1881   struct AckSendQueue *ack;
1882   struct Finish_send *finish;
1883
1884   GNUNET_assert (plugin != NULL);
1885   ack = plugin->ack_send_queue_head;
1886   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
1887                    "Sending ack for message_id %u for mac endpoint %p, size %u\n",
1888                    ack->message_id, ack->endpoint,
1889                    ntohs (ack->radioHeader->header.size));
1890   GNUNET_STATISTICS_update (plugin->env->stats, _("# wlan acks send"), 1,
1891                             GNUNET_NO);
1892   bytes =
1893       GNUNET_DISK_file_write (plugin->server_stdin_handle, ack->radioHeader,
1894                               ntohs (ack->radioHeader->header.size));
1895   if (bytes == GNUNET_SYSERR)
1896   {
1897     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME,
1898                      _
1899                      ("Error writing to wlan helper. errno == %d, ERROR: %s\n"),
1900                      errno, strerror (errno));
1901     finish = GNUNET_malloc (sizeof (struct Finish_send));
1902     finish->plugin = plugin;
1903     finish->head_of_next_write = NULL;
1904     finish->size = 0;
1905     finish->msgstart = NULL;
1906     restart_helper (plugin, finish);
1907     return;
1908   }
1909   GNUNET_assert (bytes == ntohs (ack->radioHeader->header.size));
1910   GNUNET_CONTAINER_DLL_remove (plugin->ack_send_queue_head,
1911                                plugin->ack_send_queue_tail, ack);
1912   GNUNET_free (ack);
1913   set_next_send (plugin);
1914 }
1915
1916
1917 /**
1918  * Function called when wlan helper is ready to get some data
1919  *
1920  * @param cls closure
1921  * @param tc GNUNET_SCHEDULER_TaskContext
1922  */
1923 static void
1924 do_transmit (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1925 {
1926   struct Plugin *plugin = cls;
1927   struct Session *session;
1928   struct FragmentMessage *fm;
1929   struct Finish_send *finish;
1930   struct FragmentMessage_queue *fmq;
1931   ssize_t bytes;
1932
1933
1934   GNUNET_assert (plugin != NULL);
1935   plugin->server_write_task = GNUNET_SCHEDULER_NO_TASK;
1936   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1937     return;
1938   if (plugin->ack_send_queue_head != NULL)
1939   {
1940     send_ack (plugin);
1941     return;
1942   }
1943   //test if a "hello-beacon" has to be send
1944   if (GNUNET_TIME_absolute_get_remaining (plugin->beacon_time).rel_value == 0)
1945   {
1946     send_hello_beacon (plugin);
1947     return;
1948   }
1949   if (NULL == plugin->sending_messages_head)
1950   {
1951     /* do_transmit did nothing, should not happen */  
1952     GNUNET_break (0);
1953     set_next_send (plugin);
1954     return;
1955   }
1956   GNUNET_STATISTICS_update (plugin->env->stats, _("# wlan fragments send"), 1,
1957                             GNUNET_NO);
1958   
1959   fmq = plugin->sending_messages_head;
1960   fm = fmq->content;
1961   GNUNET_CONTAINER_DLL_remove (plugin->sending_messages_head,
1962                                plugin->sending_messages_tail, fmq);
1963   GNUNET_free (fmq);
1964   
1965   session = fm->session;
1966   GNUNET_assert (session != NULL);
1967   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
1968                    "Sending GNUNET_MESSAGE_TYPE_WLAN_FRAGMENT for fragment message %p, size: %u\n",
1969                    fm, ntohs (fm->radioHeader->header.size));
1970   bytes =
1971     GNUNET_DISK_file_write (plugin->server_stdin_handle, 
1972                             fm->radioHeader,
1973                             ntohs (fm->radioHeader->header.size));
1974   if (bytes != ntohs (fm->radioHeader->header.size))
1975   {
1976     finish = GNUNET_malloc (sizeof (struct Finish_send));
1977     finish->plugin = plugin;
1978     finish->msgstart = &fm->radioHeader->header;
1979     GNUNET_assert (plugin->server_write_task == GNUNET_SCHEDULER_NO_TASK);
1980     if (bytes == GNUNET_SYSERR)
1981     {
1982       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME,
1983                        _
1984                        ("Error writing to wlan helper. errno == %d, ERROR: %s\n"),
1985                        errno, strerror (errno));     
1986       finish->head_of_next_write = (char*) fm->radioHeader;
1987       finish->size = ntohs (fm->radioHeader->header.size);
1988       restart_helper (plugin, finish);
1989     }
1990     else
1991     {
1992       finish->head_of_next_write = ((char*) fm->radioHeader) + bytes;
1993       finish->size = ntohs (fm->radioHeader->header.size) - bytes;
1994       plugin->server_write_task =
1995         GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL,
1996                                          plugin->server_stdin_handle,
1997                                          &finish_sending, finish);
1998     }    
1999   }
2000   else
2001   {
2002     GNUNET_free (fm->radioHeader);
2003     fm->radioHeader = NULL;
2004     set_next_send (plugin);
2005   }
2006   GNUNET_FRAGMENT_context_transmission_done (fm->fragcontext);
2007 }
2008
2009
2010 /**
2011  * Another peer has suggested an address for this
2012  * peer and transport plugin.  Check that this could be a valid
2013  * address.  If so, consider adding it to the list
2014  * of addresses.
2015  *
2016  * @param cls closure
2017  * @param addr pointer to the address
2018  * @param addrlen length of addr
2019  * @return GNUNET_OK if this is a plausible address for this peer
2020  *         and transport
2021  */
2022 static int
2023 wlan_plugin_address_suggested (void *cls, const void *addr, size_t addrlen)
2024 {
2025   //struct Plugin *plugin = cls;
2026
2027   /* check if the address is plausible; if so,
2028    * add it to our list! */
2029
2030   GNUNET_assert (cls != NULL);
2031   //FIXME mitm is not checked
2032   //Mac Address has 6 bytes
2033   if (addrlen == 6)
2034   {
2035     /* TODO check for bad addresses like multicast, broadcast, etc */
2036     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
2037                      "wlan_plugin_address_suggested got good address, size %u!\n",
2038                      addrlen);
2039     return GNUNET_OK;
2040   }
2041   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
2042                    "wlan_plugin_address_suggested got bad address, size %u!\n",
2043                    addrlen);
2044   return GNUNET_SYSERR;
2045 }
2046
2047
2048 /**
2049  * Creates a new outbound session the transport service will use to send data to the
2050  * peer
2051  *
2052  * @param cls the plugin
2053  * @param address the address
2054  * @return the session or NULL of max connections exceeded
2055  */
2056
2057 static struct Session *
2058 wlan_plugin_get_session (void *cls,
2059                   const struct GNUNET_HELLO_Address *address)
2060 {
2061   struct Plugin *plugin = cls;
2062   struct Session * s = NULL;
2063
2064   GNUNET_assert (plugin != NULL);
2065   GNUNET_assert (address != NULL);
2066
2067   if (GNUNET_OK == wlan_plugin_address_suggested (plugin,
2068             address->address,
2069             address->address_length))
2070   {
2071     s = get_session (plugin, address->address, &address->peer);
2072   }
2073   else
2074   {
2075     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME,
2076                      _("Wlan Address len %d is wrong\n"), address->address_length);
2077     return s;
2078   }
2079
2080   return s;
2081 }
2082
2083 /**
2084  * Function that can be used by the transport service to transmit
2085  * a message using the plugin.   Note that in the case of a
2086  * peer disconnecting, the continuation MUST be called
2087  * prior to the disconnect notification itself.  This function
2088  * will be called with this peer's HELLO message to initiate
2089  * a fresh connection to another peer.
2090  *
2091  * @param cls closure
2092  * @param session which session must be used
2093  * @param msgbuf the message to transmit
2094  * @param msgbuf_size number of bytes in 'msgbuf'
2095  * @param priority how important is the message (most plugins will
2096  *                 ignore message priority and just FIFO)
2097  * @param to how long to wait at most for the transmission (does not
2098  *                require plugins to discard the message after the timeout,
2099  *                just advisory for the desired delay; most plugins will ignore
2100  *                this as well)
2101  * @param cont continuation to call once the message has
2102  *        been transmitted (or if the transport is ready
2103  *        for the next transmission call; or if the
2104  *        peer disconnected...); can be NULL
2105  * @param cont_cls closure for cont
2106  * @return number of bytes used (on the physical network, with overheads);
2107  *         -1 on hard errors (i.e. address invalid); 0 is a legal value
2108  *         and does NOT mean that the message was not transmitted (DV)
2109  */
2110 static ssize_t
2111 wlan_plugin_send (void *cls,
2112                   struct Session *session,
2113                   const char *msgbuf, size_t msgbuf_size,
2114                   unsigned int priority,
2115                   struct GNUNET_TIME_Relative to,
2116                   GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
2117 {
2118   struct Plugin *plugin = cls;
2119   struct PendingMessage *newmsg;
2120   struct WlanHeader *wlanheader;
2121
2122   GNUNET_assert (plugin != NULL);
2123   GNUNET_assert (session != NULL);
2124   GNUNET_assert (msgbuf_size > 0);
2125
2126   //queue message:
2127
2128   //queue message in session
2129   //test if there is no other message in the "queue"
2130   //FIXME: to many send requests
2131   if (session->pending_message_head != NULL)
2132   {
2133     newmsg = session->pending_message_head;
2134     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
2135                      "wlan_plugin_send: a pending message is already in the queue for this client\n remaining time to send this message is %u, queued fragment messages for this mac connection %u\n",
2136                      GNUNET_TIME_absolute_get_remaining (newmsg->
2137                                                          timeout).rel_value,
2138                      session->mac->fragment_messages_out_count);
2139   }
2140
2141   newmsg = GNUNET_malloc (sizeof (struct PendingMessage));
2142   newmsg->msg = GNUNET_malloc (msgbuf_size + sizeof (struct WlanHeader));
2143   wlanheader = newmsg->msg;
2144   //copy msg to buffer, not fragmented / segmented yet, but with message header
2145   wlanheader->header.size = htons (msgbuf_size + sizeof (struct WlanHeader));
2146   wlanheader->header.type = htons (GNUNET_MESSAGE_TYPE_WLAN_DATA);
2147   memcpy (&(wlanheader->target), &session->target, sizeof (struct GNUNET_PeerIdentity));
2148   memcpy (&(wlanheader->source), plugin->env->my_identity,
2149           sizeof (struct GNUNET_PeerIdentity));
2150   wlanheader->crc = 0;
2151   memcpy (&wlanheader[1], msgbuf, msgbuf_size);
2152   wlanheader->crc =
2153       htonl (GNUNET_CRYPTO_crc32_n
2154              ((char *) wlanheader, msgbuf_size + sizeof (struct WlanHeader)));
2155
2156   newmsg->transmit_cont = cont;
2157   newmsg->transmit_cont_cls = cont_cls;
2158   newmsg->timeout = GNUNET_TIME_relative_to_absolute (to);
2159
2160   newmsg->timeout.abs_value = newmsg->timeout.abs_value - 500;
2161
2162   newmsg->message_size = msgbuf_size + sizeof (struct WlanHeader);
2163
2164   GNUNET_CONTAINER_DLL_insert_tail (session->pending_message_head,
2165                                     session->pending_message_tail, newmsg);
2166
2167   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
2168                    "New message for %p with size (incl wlan header) %u added\n",
2169                    session, newmsg->message_size);
2170 #if DEBUG_WLAN > 1
2171   hexdump (msgbuf, GNUNET_MIN (msgbuf_size, 256));
2172 #endif
2173   //queue session
2174   queue_session (plugin, session);
2175
2176   check_fragment_queue (plugin);
2177   //FIXME not the correct size
2178   return msgbuf_size;
2179 }
2180
2181
2182 /**
2183  * function to free a mac endpoint
2184  * @param plugin pointer to the plugin struct
2185  * @param endpoint pointer to the MacEndpoint to free
2186  */
2187 static void
2188 free_macendpoint (struct Plugin *plugin, struct MacEndpoint *endpoint)
2189 {
2190   struct Sessionqueue *sessions;
2191   struct Sessionqueue *sessions_next;
2192
2193   GNUNET_assert (endpoint != NULL);
2194
2195   sessions = endpoint->sessions_head;
2196   while (sessions != NULL)
2197   {
2198     sessions_next = sessions->next;
2199     free_session (plugin, sessions, GNUNET_NO);
2200     sessions = sessions_next;
2201   }
2202
2203   GNUNET_CONTAINER_DLL_remove (plugin->mac_head, plugin->mac_tail, endpoint);
2204   if (endpoint->timeout_task != GNUNET_SCHEDULER_NO_TASK)
2205   {
2206     GNUNET_SCHEDULER_cancel (endpoint->timeout_task);
2207     endpoint->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2208   }
2209   plugin->mac_count--;
2210   GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan mac endpoints"),
2211                          plugin->mac_count, GNUNET_NO);
2212   GNUNET_free (endpoint);
2213
2214 }
2215
2216 /**
2217  * function to free a session
2218  * @param plugin pointer to the plugin
2219  * @param queue pointer to the sessionqueue element to free
2220  * @param do_free_macendpoint if GNUNET_YES and mac endpoint would be empty, free mac endpoint
2221  */
2222 static void
2223 free_session (struct Plugin *plugin, struct Sessionqueue *queue,
2224               int do_free_macendpoint)
2225 {
2226   struct Sessionqueue *pendingsession;
2227   struct Sessionqueue *pendingsession_tmp;
2228   struct PendingMessage *pm;
2229   struct MacEndpoint *endpoint;
2230   struct FragmentMessage *fm;
2231   struct FragmentMessage *fmnext;
2232   int check = 0;
2233
2234   GNUNET_assert (plugin != NULL);
2235   GNUNET_assert (queue != NULL);
2236   GNUNET_assert (queue->content != NULL);
2237
2238   //session found
2239   //is this session pending for send
2240   pendingsession = plugin->pending_Sessions_head;
2241   while (pendingsession != NULL)
2242   {
2243     pendingsession_tmp = pendingsession;
2244     pendingsession = pendingsession->next;
2245     GNUNET_assert (pendingsession_tmp->content != NULL);
2246     if (pendingsession_tmp->content == queue->content)
2247     {
2248       plugin->pendingsessions--;
2249       GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending sessions"),
2250                              plugin->pendingsessions, GNUNET_NO);
2251       GNUNET_CONTAINER_DLL_remove (plugin->pending_Sessions_head,
2252                                    plugin->pending_Sessions_tail,
2253                                    pendingsession_tmp);
2254       GNUNET_free (pendingsession_tmp);
2255
2256       GNUNET_assert (check == 0);
2257       check = 1;
2258     }
2259   }
2260
2261   endpoint = queue->content->mac;
2262   fm = endpoint->sending_messages_head;
2263   while (fm != NULL)
2264   {
2265     fmnext = fm->next;
2266     if (fm->session == queue->content)
2267     {
2268       free_fragment_message (plugin, fm);
2269     }
2270     fm = fmnext;
2271   }
2272
2273   // remove PendingMessage
2274   pm = queue->content->pending_message_head;
2275   while (pm != NULL)
2276   {
2277     GNUNET_CONTAINER_DLL_remove (queue->content->pending_message_head,
2278                                  queue->content->pending_message_tail, pm);
2279     GNUNET_free (pm->msg);
2280     GNUNET_free (pm);
2281     pm = queue->content->pending_message_head;
2282   }
2283
2284   GNUNET_CONTAINER_DLL_remove (endpoint->sessions_head, endpoint->sessions_tail,
2285                                queue);
2286   //Check that no ohter session on this endpoint for this session exits
2287   GNUNET_assert (search_session (plugin, endpoint, &queue->content->target) ==
2288                  NULL);
2289   if (endpoint->sessions_head == NULL && do_free_macendpoint == GNUNET_YES)
2290   {
2291     free_macendpoint (plugin, endpoint);
2292     //check if no endpoint with the same address exists
2293     GNUNET_assert (get_macendpoint (plugin, &endpoint->addr, GNUNET_NO) ==
2294                    NULL);
2295   }
2296
2297   if (queue->content->timeout_task != GNUNET_SCHEDULER_NO_TASK)
2298   {
2299     GNUNET_SCHEDULER_cancel (queue->content->timeout_task);
2300     queue->content->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2301   }
2302   GNUNET_free (queue);
2303
2304   check_fragment_queue (plugin);
2305 }
2306
2307 /**
2308  * Function that can be used to force the plugin to disconnect
2309  * from the given peer and cancel all previous transmissions
2310  * (and their continuation).
2311  *
2312  * @param cls closure
2313  * @param target peer from which to disconnect
2314  */
2315 static void
2316 wlan_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target)
2317 {
2318   struct Plugin *plugin = cls;
2319   struct Sessionqueue *queue;
2320   struct Sessionqueue *queue_next;
2321   struct MacEndpoint *endpoint = plugin->mac_head;
2322   struct MacEndpoint *endpoint_next;
2323
2324   // just look at all the session for the needed one
2325   while (endpoint != NULL)
2326   {
2327     queue = endpoint->sessions_head;
2328     endpoint_next = endpoint->next;
2329     while (queue != NULL)
2330     {
2331       // content is never NULL
2332       GNUNET_assert (queue->content != NULL);
2333       queue_next = queue->next;
2334       if (memcmp
2335           (target, &(queue->content->target),
2336            sizeof (struct GNUNET_PeerIdentity)) == 0)
2337       {
2338         free_session (plugin, queue, GNUNET_YES);
2339       }
2340       // try next
2341       queue = queue_next;
2342     }
2343     endpoint = endpoint_next;
2344   }
2345 }
2346
2347 /**
2348  * Convert the transports address to a nice, human-readable
2349  * format.
2350  *
2351  * @param cls closure
2352  * @param type name of the transport that generated the address
2353  * @param addr one of the addresses of the host, NULL for the last address
2354  *        the specific address format depends on the transport
2355  * @param addrlen length of the address
2356  * @param numeric should (IP) addresses be displayed in numeric form?
2357  * @param timeout after how long should we give up?
2358  * @param asc function to call on each string
2359  * @param asc_cls closure for asc
2360  */
2361 static void
2362 wlan_plugin_address_pretty_printer (void *cls, const char *type,
2363                                     const void *addr, size_t addrlen,
2364                                     int numeric,
2365                                     struct GNUNET_TIME_Relative timeout,
2366                                     GNUNET_TRANSPORT_AddressStringCallback asc,
2367                                     void *asc_cls)
2368 {
2369   char *ret;
2370   const unsigned char *input;
2371
2372   //GNUNET_assert(cls !=NULL);
2373   if (addrlen != sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress))
2374   {
2375     /* invalid address (MAC addresses have 6 bytes) */
2376     //GNUNET_break (0);
2377     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
2378                      "Func wlan_plugin_address_pretty_printer got size: %u, worng size!\n",
2379                      addrlen);
2380     asc (asc_cls, NULL);
2381     return;
2382   }
2383   input = (const unsigned char *) addr;
2384   GNUNET_asprintf (&ret,
2385                    "Transport %s: %s Mac-Address %.2X:%.2X:%.2X:%.2X:%.2X:%.2X",
2386                    type, PROTOCOL_PREFIX, input[0], input[1], input[2],
2387                    input[3], input[4], input[5]);
2388   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
2389                    "Func wlan_plugin_address_pretty_printer got size: %u, nummeric %u, type %s; made string: %s\n",
2390                    addrlen, numeric, type, ret);
2391   asc (asc_cls, ret);
2392   //only one mac address per plugin
2393   asc (asc_cls, NULL);
2394 }
2395
2396
2397
2398 /**
2399  * handels the data after all fragments are put together
2400  * @param cls macendpoint this messages belongs to
2401  * @param hdr pointer to the data
2402  */
2403 static void
2404 wlan_data_message_handler (void *cls, const struct GNUNET_MessageHeader *hdr)
2405 {
2406   struct MacEndpoint *endpoint = (struct MacEndpoint *) cls;
2407   struct Plugin *plugin = endpoint->plugin;
2408   struct WlanHeader *wlanheader;
2409   struct Session *session;
2410
2411   const struct GNUNET_MessageHeader *temp_hdr;
2412   struct GNUNET_PeerIdentity tmpsource;
2413   int crc;
2414
2415   GNUNET_assert (plugin != NULL);
2416
2417   if (ntohs (hdr->type) == GNUNET_MESSAGE_TYPE_WLAN_DATA)
2418   {
2419
2420     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
2421                      "Func wlan_data_message_handler got GNUNET_MESSAGE_TYPE_WLAN_DATA size: %u\n",
2422                      ntohs (hdr->size));
2423
2424     if (ntohs (hdr->size) <
2425         sizeof (struct WlanHeader) + sizeof (struct GNUNET_MessageHeader))
2426     {
2427       //packet not big enought
2428       return;
2429     }
2430
2431     GNUNET_STATISTICS_update (plugin->env->stats,
2432                               _("# wlan whole messages received"), 1,
2433                               GNUNET_NO);
2434     wlanheader = (struct WlanHeader *) hdr;
2435
2436     session = search_session (plugin, endpoint, &wlanheader->source);
2437
2438     temp_hdr = (const struct GNUNET_MessageHeader *) &wlanheader[1];
2439     crc = ntohl (wlanheader->crc);
2440     wlanheader->crc = 0;
2441     if (GNUNET_CRYPTO_crc32_n
2442         ((char *) wlanheader, ntohs (wlanheader->header.size)) != crc)
2443     {
2444       //wrong crc, dispose message
2445       GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, PLUGIN_LOG_NAME,
2446                        "Wlan message header crc was wrong: %u != %u\n",
2447                        GNUNET_CRYPTO_crc32_n ((char *) wlanheader,
2448                                               ntohs (wlanheader->header.size)),
2449                        crc);
2450       hexdump ((void *) hdr, ntohs (hdr->size));
2451       return;
2452     }
2453
2454     //if not in session list
2455     if (session == NULL)
2456     {
2457       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
2458                        "WLAN client not in session list: packet size = %u, inner size = %u, header size = %u\n",
2459                        ntohs (wlanheader->header.size), ntohs (temp_hdr->size),
2460                        sizeof (struct WlanHeader));
2461       //try if it is a hello message
2462       if (ntohs (wlanheader->header.size) >=
2463           ntohs (temp_hdr->size) + sizeof (struct WlanHeader))
2464       {
2465         if (ntohs (temp_hdr->type) == GNUNET_MESSAGE_TYPE_HELLO)
2466         {
2467           if (GNUNET_HELLO_get_id
2468               ((const struct GNUNET_HELLO_Message *) temp_hdr,
2469                &tmpsource) == GNUNET_OK)
2470           {
2471             session = create_session (plugin, endpoint, &tmpsource);
2472           }
2473           else
2474           {
2475             GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, PLUGIN_LOG_NAME,
2476                              "WLAN client not in session list and hello message is not okay\n");
2477             return;
2478           }
2479
2480         }
2481         else
2482         {
2483           GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, PLUGIN_LOG_NAME,
2484                            "WLAN client not in session list and not a hello message\n");
2485           return;
2486         }
2487       }
2488       else
2489       {
2490         GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, PLUGIN_LOG_NAME,
2491                          "WLAN client not in session list and message size in does not fit\npacket size = %u, inner size = %u, header size = %u\n",
2492                          ntohs (wlanheader->header.size),
2493                          ntohs (temp_hdr->size), sizeof (struct WlanHeader));
2494         return;
2495       }
2496     }
2497
2498     //"receive" the message
2499
2500     if (memcmp
2501         (&wlanheader->source, &session->target,
2502          sizeof (struct GNUNET_PeerIdentity)) != 0)
2503     {
2504       //wrong peer id
2505       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
2506                        "WLAN peer source id doesn't match packet peer source id: session %p\n",
2507                        session);
2508       return;
2509     }
2510
2511     if (memcmp
2512         (&wlanheader->target, plugin->env->my_identity,
2513          sizeof (struct GNUNET_PeerIdentity)) != 0)
2514     {
2515       //wrong peer id
2516       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
2517                        "WLAN peer target id doesn't match our peer id: session %p\n",
2518                        session);
2519       return;
2520     }
2521
2522     GNUNET_SERVER_mst_receive (plugin->data_tokenizer, session,
2523                                (const char *) temp_hdr,
2524                                ntohs (hdr->size) - sizeof (struct WlanHeader),
2525                                GNUNET_YES, GNUNET_NO);
2526
2527     return;
2528   }
2529   else
2530   {
2531     GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, PLUGIN_LOG_NAME,
2532                      "wlan_data_message_handler got wrong message type: %u\n",
2533                      ntohs (hdr->size));
2534     return;
2535   }
2536 }
2537
2538 /**
2539  * function to process the a message, give it to the higher layer
2540  * @param cls pointer to the plugin
2541  * @param client pointer to the session this message belongs to
2542  * @param hdr start of the message
2543  */
2544 //TODO ATS informations
2545 static void
2546 process_data (void *cls, void *client, const struct GNUNET_MessageHeader *hdr)
2547 {
2548
2549   GNUNET_assert (client != NULL);
2550   GNUNET_assert (cls != NULL);
2551   struct Session *session = (struct Session *) client;
2552   struct Plugin *plugin = (struct Plugin *) cls;
2553   struct GNUNET_ATS_Information ats[2];
2554
2555   ats[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE);
2556   ats[0].value = htonl (1);
2557   ats[1].type = htonl (GNUNET_ATS_NETWORK_TYPE);
2558   ats[1].value = htonl (GNUNET_ATS_NET_WLAN);
2559
2560   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
2561                    "Calling plugin->env->receive for session %p; %s; size: %u\n",
2562                    session, wlan_plugin_address_to_string (NULL,
2563                                                            session->mac->
2564                                                            addr.mac, 6),
2565                    htons (hdr->size));
2566   plugin->env->receive (plugin->env->cls, &(session->target), hdr,
2567                         (const struct GNUNET_ATS_Information *) &ats, 2,
2568                         session, (const char *) &session->mac->addr,
2569                         sizeof (session->mac->addr));
2570 }
2571
2572 /**
2573  * Function used for to process the data received from the wlan interface
2574  *
2575  * @param cls the plugin handle
2576  * @param session_light pointer to the struct holding known informations
2577  * @param hdr hdr of the GNUNET_MessageHeader
2578  * @param rxinfo pointer to the radiotap informations got with this packet FIXME: give ATS for info
2579  */
2580 static void
2581 wlan_data_helper (void *cls, struct Session_light *session_light,
2582                   const struct GNUNET_MessageHeader *hdr,
2583                   const struct Radiotap_rx *rxinfo)
2584 {
2585   struct Plugin *plugin = cls;
2586   struct FragmentMessage *fm;
2587   struct FragmentMessage *fm2;
2588   struct GNUNET_PeerIdentity tmpsource;
2589
2590   GNUNET_assert (plugin != NULL);
2591
2592   //ADVERTISEMENT
2593   if (ntohs (hdr->type) == GNUNET_MESSAGE_TYPE_HELLO)
2594   {
2595
2596     //TODO better DOS protection, error handling
2597     //TODO test first than create session
2598     GNUNET_assert (session_light != NULL);
2599
2600     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
2601                      "Func wlan_data_helper got GNUNET_MESSAGE_TYPE_HELLO size: %u; %s\n",
2602                      ntohs (hdr->size), wlan_plugin_address_to_string (NULL,
2603                                                                        session_light->addr.
2604                                                                        mac, 6));
2605     if (session_light->macendpoint == NULL)
2606     {
2607       session_light->macendpoint =
2608           get_macendpoint (plugin, &session_light->addr, GNUNET_YES);
2609     }
2610
2611
2612     if (GNUNET_HELLO_get_id
2613         ((const struct GNUNET_HELLO_Message *) hdr, &tmpsource) == GNUNET_OK)
2614     {
2615       session_light->session =
2616           search_session (plugin, session_light->macendpoint, &tmpsource);
2617       if (session_light->session == NULL)
2618       {
2619         session_light->session =
2620             create_session (plugin, session_light->macendpoint, &tmpsource);
2621       }
2622       GNUNET_STATISTICS_update (plugin->env->stats,
2623                                 _("# wlan hello messages received"), 1,
2624                                 GNUNET_NO);
2625       plugin->env->receive (plugin->env->cls, &session_light->session->target,
2626                             hdr, NULL, 0, session_light->session,
2627                             (const char *) &session_light->session->mac->addr,
2628                             sizeof (session_light->session->mac->addr));
2629     }
2630     else
2631     {
2632       GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, PLUGIN_LOG_NAME,
2633                        "WLAN client not in session list and hello message is not okay\n");
2634       return;
2635     }
2636   }
2637
2638   //FRAGMENT
2639
2640   else if (ntohs (hdr->type) == GNUNET_MESSAGE_TYPE_FRAGMENT)
2641   {
2642
2643     GNUNET_assert (session_light != NULL);
2644     if (session_light->macendpoint == NULL)
2645     {
2646       session_light->macendpoint =
2647           get_macendpoint (plugin, &session_light->addr, GNUNET_YES);
2648     }
2649
2650     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
2651                      "Func wlan_data_helper got GNUNET_MESSAGE_TYPE_FRAGMENT with size: %u; mac endpoint %p: %s\n",
2652                      ntohs (hdr->size), session_light->macendpoint,
2653                      wlan_plugin_address_to_string (NULL,
2654                                                     session_light->addr.mac,
2655                                                     6));
2656     GNUNET_STATISTICS_update (plugin->env->stats,
2657                               _("# wlan fragments received"), 1, GNUNET_NO);
2658     int ret =
2659         GNUNET_DEFRAGMENT_process_fragment (session_light->macendpoint->defrag,
2660                                             hdr);
2661
2662     if (ret == GNUNET_NO)
2663     {
2664       session_light->macendpoint->dups++;
2665     }
2666     else if (ret == GNUNET_OK)
2667     {
2668       session_light->macendpoint->fragc++;
2669     }
2670     set_next_send (plugin);
2671
2672   }
2673
2674   //ACK
2675
2676   else if (ntohs (hdr->type) == GNUNET_MESSAGE_TYPE_FRAGMENT_ACK)
2677   {
2678     GNUNET_assert (session_light != NULL);
2679     if (session_light->macendpoint == NULL)
2680     {
2681       session_light->macendpoint =
2682           get_macendpoint (plugin, &session_light->addr, GNUNET_NO);
2683     }
2684
2685     if (session_light->macendpoint == NULL)
2686     {
2687       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
2688                        "Macendpoint does not exist for this GNUNET_MESSAGE_TYPE_FRAGMENT_ACK size: %u; %s\n",
2689                        ntohs (hdr->size), wlan_plugin_address_to_string (NULL,
2690                                                                          session_light->addr.mac,
2691                                                                          6));
2692       return;
2693     }
2694
2695     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
2696                      "Func wlan_data_helper got GNUNET_MESSAGE_TYPE_FRAGMENT_ACK size: %u; mac endpoint: %p; %s\n",
2697                      ntohs (hdr->size), session_light->macendpoint,
2698                      wlan_plugin_address_to_string (NULL,
2699                                                     session_light->addr.mac,
2700                                                     6));
2701     fm = session_light->macendpoint->sending_messages_head;
2702     while (fm != NULL)
2703     {
2704       fm2 = fm->next;
2705       GNUNET_STATISTICS_update (plugin->env->stats, _("# wlan acks received"),
2706                                 1, GNUNET_NO);
2707       int ret = GNUNET_FRAGMENT_process_ack (fm->fragcontext, hdr);
2708
2709       if (ret == GNUNET_OK)
2710       {
2711         GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
2712                          "Got last ack, finished fragment message %p\n", fm);
2713         session_light->macendpoint->acks++;
2714         fm->session->last_activity = GNUNET_TIME_absolute_get ();
2715         session_light->macendpoint->last_activity = fm->session->last_activity;
2716         free_fragment_message (plugin, fm);
2717         check_fragment_queue (plugin);
2718         return;
2719       }
2720       if (ret == GNUNET_NO)
2721       {
2722         GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
2723                          "Got ack for: %p\n", fm);
2724         session_light->macendpoint->acks++;
2725         return;
2726       }
2727       if (ret == GNUNET_SYSERR)
2728       {
2729
2730       }
2731
2732       fm = fm2;
2733     }
2734
2735     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
2736                      "WLAN fragment not in fragment list\n");
2737     return;
2738
2739   }
2740   else
2741   {
2742     // TODO Wrong data?
2743     GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, PLUGIN_LOG_NAME,
2744                      "WLAN packet inside the WLAN helper packet has not the right type: %u size: %u\n",
2745                      ntohs (hdr->type), ntohs (hdr->size));
2746     GNUNET_break (0);
2747     return;
2748   }
2749
2750 #if 0
2751   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
2752                    "Helper finished\n");
2753 #endif
2754
2755 }
2756
2757 /**
2758  * Function to print mac addresses nicely.
2759  *
2760  * @param mac the mac address
2761  * @return string to a static buffer with the human-readable mac, will be overwritten during the next call to this function
2762  */
2763 static const char *
2764 macprinter (const struct GNUNET_TRANSPORT_WLAN_MacAddress * mac)
2765 {
2766   static char macstr[20];
2767
2768   GNUNET_snprintf (macstr, sizeof (macstr), "%2X:%2X:%2X:%2X:%2X:%2X", mac->mac[0], mac->mac[1],
2769                    mac->mac[2], mac->mac[3], mac->mac[4], mac->mac[5]);
2770   return macstr;
2771 }
2772
2773 /**
2774  * Function for the scheduler if a mac endpoint times out
2775  * @param cls pointer to the MacEndpoint
2776  * @param tc pointer to the GNUNET_SCHEDULER_TaskContext
2777  */
2778 static void
2779 macendpoint_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2780 {
2781   struct MacEndpoint *endpoint = cls;
2782
2783   GNUNET_assert (endpoint != NULL);
2784   endpoint->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2785   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
2786   {
2787     return;
2788   }
2789   if (GNUNET_TIME_absolute_get_remaining
2790       (GNUNET_TIME_absolute_add
2791        (endpoint->last_activity, MACENDPOINT_TIMEOUT)).rel_value == 0)
2792   {
2793     GNUNET_assert (endpoint->plugin != NULL);
2794     GNUNET_STATISTICS_update (endpoint->plugin->env->stats,
2795                               _("# wlan mac endpoints timeouts"), 1, GNUNET_NO);
2796     free_macendpoint (endpoint->plugin, endpoint);
2797   }
2798   else
2799   {
2800     endpoint->timeout_task =
2801         GNUNET_SCHEDULER_add_delayed (MACENDPOINT_TIMEOUT, &macendpoint_timeout,
2802                                       endpoint);
2803   }
2804 }
2805
2806 /**
2807  * function to create an macendpoint
2808  * @param plugin pointer to the plugin struct
2809  * @param addr pointer to the macaddress
2810  * @return returns a macendpoint
2811  */
2812 static struct MacEndpoint *
2813 create_macendpoint (struct Plugin *plugin, const struct GNUNET_TRANSPORT_WLAN_MacAddress *addr)
2814 {
2815   struct MacEndpoint *newend = GNUNET_malloc (sizeof (struct MacEndpoint));
2816
2817   GNUNET_assert (plugin != NULL);
2818   GNUNET_STATISTICS_update (plugin->env->stats,
2819                             _("# wlan mac endpoints created"), 1, GNUNET_NO);
2820   newend->addr = *addr;
2821   newend->plugin = plugin;
2822   newend->addr = *addr;
2823   newend->fragment_messages_out_count = 0;
2824   newend->defrag =
2825       GNUNET_DEFRAGMENT_context_create (plugin->env->stats, WLAN_MTU,
2826                                         MESSAGES_IN_DEFRAG_QUEUE_PER_MAC,
2827                                         newend, &wlan_data_message_handler,
2828                                         &add_ack_for_send);
2829   newend->last_activity = GNUNET_TIME_absolute_get ();
2830   newend->timeout_task =
2831       GNUNET_SCHEDULER_add_delayed (MACENDPOINT_TIMEOUT, &macendpoint_timeout,
2832                                     newend);
2833
2834   plugin->mac_count++;
2835   GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan mac endpoints"),
2836                          plugin->mac_count, GNUNET_NO);
2837   GNUNET_CONTAINER_DLL_insert_tail (plugin->mac_head, plugin->mac_tail, newend);
2838   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
2839                    "New Mac Endpoint %p: %s\n", newend,
2840                    wlan_plugin_address_to_string (NULL, newend->addr.mac, 6));
2841   return newend;
2842 }
2843
2844 /**
2845  * Function used for to process the data from the suid process
2846  *
2847  * @param cls the plugin handle
2848  * @param client client that send the data (not used)
2849  * @param hdr header of the GNUNET_MessageHeader
2850  */
2851 static void
2852 wlan_process_helper (void *cls, void *client,
2853                      const struct GNUNET_MessageHeader *hdr)
2854 {
2855   struct Plugin *plugin = cls;
2856   const struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *wlanIeeeHeader;
2857   struct Session_light *session_light = NULL;
2858   const struct Radiotap_rx *rxinfo;
2859   const struct GNUNET_MessageHeader *temp_hdr = NULL;
2860
2861   int datasize = 0;
2862   int pos;
2863
2864   GNUNET_assert (plugin != NULL);
2865   switch (ntohs (hdr->type))
2866   {
2867   case GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA:
2868     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
2869                      "Func wlan_process_helper got GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA size: %u\n",
2870                      ntohs (hdr->size));
2871     GNUNET_STATISTICS_update (plugin->env->stats,
2872                               _("# wlan WLAN_HELPER_DATA received"), 1,
2873                               GNUNET_NO);
2874     //call wlan_process_helper with the message inside, later with wlan: analyze signal
2875     if (ntohs (hdr->size) <
2876         sizeof (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame) +
2877         2 * sizeof (struct GNUNET_MessageHeader) + sizeof (struct Radiotap_rx))
2878     {
2879       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
2880                        "Size of packet is too small; size: %u min size: %u\n",
2881                        ntohs (hdr->size),
2882                        sizeof (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame) +
2883                        sizeof (struct GNUNET_MessageHeader));
2884       //GNUNET_break (0);
2885       /* FIXME: restart SUID process */
2886       return;
2887     }
2888
2889     rxinfo = (const struct Radiotap_rx *) &hdr[1];
2890     wlanIeeeHeader = (const struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *) &rxinfo[1];
2891
2892     //process only if it is an broadcast or for this computer both with the gnunet bssid
2893
2894     //check for bssid
2895     if (memcmp
2896         (&wlanIeeeHeader->addr3, &mac_bssid_gnunet,
2897          sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)) == 0)
2898     {
2899       //check for broadcast or mac
2900       if ((memcmp
2901            (&wlanIeeeHeader->addr1, &bc_all_mac,
2902             sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)) == 0) ||
2903           (memcmp
2904            (&wlanIeeeHeader->addr1, &(plugin->mac_address),
2905             sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)) == 0))
2906       {
2907         //if packet is from us return
2908         if ((memcmp
2909              (&wlanIeeeHeader->addr2, &(plugin->mac_address),
2910               sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)) == 0))
2911         {
2912           return;
2913         }
2914         // process the inner data
2915
2916
2917         datasize =
2918             ntohs (hdr->size) - sizeof (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame) -
2919             sizeof (struct GNUNET_MessageHeader) - sizeof (struct Radiotap_rx);
2920
2921         session_light = GNUNET_malloc (sizeof (struct Session_light));
2922         session_light->addr = wlanIeeeHeader->addr2;
2923         //session_light->session = search_session(plugin,session_light->addr);
2924         GNUNET_STATISTICS_update (plugin->env->stats,
2925                                   _("# wlan messages for this client received"),
2926                                   1, GNUNET_NO);
2927
2928         pos = 0;
2929         while (pos < datasize)
2930         {
2931           temp_hdr = (struct GNUNET_MessageHeader *) &wlanIeeeHeader[1] + pos;
2932           if (ntohs (temp_hdr->size) <= datasize + pos)
2933           {
2934             GNUNET_STATISTICS_update (plugin->env->stats,
2935                                       _
2936                                       ("# wlan messages inside WLAN_HELPER_DATA received"),
2937                                       1, GNUNET_NO);
2938             wlan_data_helper (plugin, session_light, temp_hdr, rxinfo);
2939           }
2940           else
2941           {
2942             GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
2943                              "Size of packet is too small; size: %u > size of packet: %u\n",
2944                              ntohs (temp_hdr->size), datasize + pos);
2945           }
2946           pos += ntohs (temp_hdr->size);
2947
2948         }
2949
2950         //clean up
2951         GNUNET_free (session_light);
2952       }
2953       else
2954       {
2955         GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
2956                          "Func wlan_process_helper got wrong MAC: %s\n",
2957                          macprinter (&wlanIeeeHeader->addr1));
2958       }
2959     }
2960     else
2961     {
2962       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
2963                        "Func wlan_process_helper got wrong BSSID: %s\n",
2964                        macprinter (&wlanIeeeHeader->addr2));
2965     }
2966     break;
2967   case GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL:
2968     //TODO more control messages
2969     if (ntohs (hdr->size) != sizeof (struct GNUNET_TRANSPORT_WLAN_HelperControlMessage))
2970     {
2971       GNUNET_break (0);
2972       /* FIXME: restart SUID process */
2973       return;
2974     }
2975     memcpy (&plugin->mac_address, &hdr[1], sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress));
2976     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
2977                      "Received WLAN_HELPER_CONTROL message with transport of address %s\n",
2978                      wlan_plugin_address_to_string (cls, &plugin->mac_address,
2979                                                     sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)));
2980     plugin->env->notify_address (plugin->env->cls, GNUNET_YES,
2981                                  &plugin->mac_address,
2982                                  sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress));
2983     break;
2984   default:
2985     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
2986                      "Func wlan_process_helper got unknown message with number %u, size %u\n",
2987                      ntohs (hdr->type), ntohs (hdr->size));
2988
2989 #if DEBUG_WLAN > 1
2990     hexdump (hdr, GNUNET_MIN (ntohs (hdr->size), 256));
2991 #endif
2992     GNUNET_break (0);
2993     return;
2994   }
2995 }
2996
2997
2998
2999 /**
3000  * Exit point from the plugin.
3001  * @param cls pointer to the api struct
3002  */
3003
3004 //FIXME cleanup
3005 void *
3006 libgnunet_plugin_transport_wlan_done (void *cls)
3007 {
3008   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
3009   struct Plugin *plugin = api->cls;
3010   struct MacEndpoint *endpoint;
3011   struct MacEndpoint *endpoint_next;
3012
3013   if (NULL == plugin)
3014   {
3015     GNUNET_free (api);
3016     return NULL;
3017   }
3018   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
3019                    "libgnunet_plugin_transport_wlan_done started\n");
3020   wlan_transport_stop_wlan_helper (plugin);
3021
3022   GNUNET_assert (cls != NULL);
3023   //free sessions
3024   endpoint = plugin->mac_head;
3025   while (endpoint != NULL)
3026   {
3027     endpoint_next = endpoint->next;
3028     free_macendpoint (plugin, endpoint);
3029     endpoint = endpoint_next;
3030
3031   }
3032
3033
3034   if (plugin->suid_tokenizer != NULL)
3035     GNUNET_SERVER_mst_destroy (plugin->suid_tokenizer);
3036
3037   if (plugin->data_tokenizer != NULL)
3038     GNUNET_SERVER_mst_destroy (plugin->data_tokenizer);
3039
3040   GNUNET_free_non_null (plugin->interface);
3041   GNUNET_free (plugin);
3042   GNUNET_free (api);
3043   return NULL;
3044 }
3045
3046
3047 /**
3048  * Entry point for the plugin.
3049  *
3050  * @param cls closure, the 'struct GNUNET_TRANSPORT_PluginEnvironment*'
3051  * @return the 'struct GNUNET_TRANSPORT_PluginFunctions*' or NULL on error
3052  */
3053 void *
3054 libgnunet_plugin_transport_wlan_init (void *cls)
3055 {
3056   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
3057   struct GNUNET_TRANSPORT_PluginFunctions *api;
3058   struct Plugin *plugin;
3059
3060   if (NULL == env->receive)
3061   {
3062     /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
3063        initialze the plugin or the API */
3064     api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
3065     api->cls = NULL;
3066     api->address_pretty_printer = &wlan_plugin_address_pretty_printer;
3067     api->address_to_string = &wlan_plugin_address_to_string;
3068     api->string_to_address = NULL; // FIXME!
3069     return api;
3070   }
3071
3072   plugin = GNUNET_malloc (sizeof (struct Plugin));
3073   plugin->env = env;
3074   plugin->pendingsessions = 0;
3075   GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending sessions"),
3076                          plugin->pendingsessions, GNUNET_NO);
3077   plugin->mac_count = 0;
3078   GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan mac endpoints"),
3079                          plugin->mac_count, GNUNET_NO);
3080   plugin->server_write_task = GNUNET_SCHEDULER_NO_TASK;
3081   plugin->server_read_task = GNUNET_SCHEDULER_NO_TASK;
3082   plugin->server_write_delay_task = GNUNET_SCHEDULER_NO_TASK;
3083   GNUNET_BANDWIDTH_tracker_init (&plugin->tracker,
3084                                  GNUNET_BANDWIDTH_value_init (100 * 1024 *
3085                                                               1024 / 8), 100);
3086
3087   plugin->suid_tokenizer =
3088       GNUNET_SERVER_mst_create (&wlan_process_helper, plugin);
3089
3090   plugin->data_tokenizer = GNUNET_SERVER_mst_create (&process_data, plugin);
3091
3092   //plugin->sessions = GNUNET_malloc (sizeof (struct Sessionqueue));
3093   //plugin->pending_Sessions_head = GNUNET_malloc (sizeof (struct Sessionqueue));
3094
3095   api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
3096   api->cls = plugin;
3097   api->send = &wlan_plugin_send;
3098   api->get_session = &wlan_plugin_get_session;
3099   api->disconnect = &wlan_plugin_disconnect;
3100   api->address_pretty_printer = &wlan_plugin_address_pretty_printer;
3101   api->check_address = &wlan_plugin_address_suggested;
3102   api->address_to_string = &wlan_plugin_address_to_string;
3103
3104   //read config
3105
3106   if (GNUNET_CONFIGURATION_have_value (env->cfg, "transport-wlan", "TESTMODE"))
3107   {
3108     if (GNUNET_SYSERR ==
3109         GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-wlan",
3110                                                "TESTMODE", &(plugin->testmode)))
3111       plugin->testmode = 0;     //default value
3112   }
3113
3114   if (GNUNET_CONFIGURATION_have_value (env->cfg, "transport-wlan", "INTERFACE"))
3115   {
3116     if (GNUNET_CONFIGURATION_get_value_string
3117         (env->cfg, "transport-wlan", "INTERFACE",
3118          &(plugin->interface)) != GNUNET_YES)
3119     {
3120       libgnunet_plugin_transport_wlan_done (api);
3121       return NULL;
3122     }
3123   }
3124
3125   //start the plugin
3126   wlan_transport_start_wlan_helper (plugin);
3127   set_next_beacon_time (plugin);
3128   set_next_send (plugin);
3129   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
3130                    "wlan init finished\n");
3131   return api;
3132 }
3133
3134
3135
3136
3137 /* end of plugin_transport_wlan.c */