2 This file is part of GNUnet
3 (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors)
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.
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.
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.
22 * @file transport/plugin_transport_wlan.c
23 * @brief transport plugin for wlan
24 * @author David Brodski
28 #include "gnunet_hello_lib.h"
29 #include "gnunet_protocols.h"
30 #include "gnunet_util_lib.h"
31 #include "gnunet_statistics_service.h"
32 #include "gnunet_transport_service.h"
33 #include "gnunet_transport_plugin.h"
34 #include "plugin_transport_wlan.h"
35 #include "gnunet_common.h"
36 #include "gnunet_crypto_lib.h"
38 #define PROTOCOL_PREFIX "wlan"
41 * Max size of packet from helper
46 * Time until retransmission of a fragment in ms
48 #define FRAGMENT_TIMEOUT GNUNET_TIME_UNIT_SECONDS
50 #define FRAGMENT_QUEUE_SIZE 10
52 #define DEBUG_wlan GNUNET_NO
55 * After how long do we expire an address that we
56 * learned from another peer if it is not reconfirmed
59 #define LEARNED_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 6)
62 * Initial handshake message for a session.
67 * Type is GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME.
69 struct GNUNET_MessageHeader header;
72 * Identity of the node connecting (TCP client)
74 struct GNUNET_PeerIdentity clientIdentity;
79 * Encapsulation of all of the state of the plugin.
86 struct GNUNET_TRANSPORT_PluginEnvironment *env;
89 * List of open sessions. head
91 struct Sessionqueue *sessions;
94 * List of open sessions. tail
96 struct Sessionqueue *sessions_tail;
105 * encapsulation to the local wlan server prog
108 struct GNUNET_SERVER_MessageStreamTokenizer * consoltoken;
112 * stdout pipe handle for the gnunet-wlan-helper process
114 struct GNUNET_DISK_PipeHandle *server_stdout;
117 * stdout file handle for the gnunet-wlan-helper process
119 const struct GNUNET_DISK_FileHandle *server_stdout_handle;
122 * stdin pipe handle for the gnunet-wlan-helper process
124 struct GNUNET_DISK_PipeHandle *server_stdin;
127 * stdin file handle for the gnunet-wlan-helper process
129 const struct GNUNET_DISK_FileHandle *server_stdin_handle;
132 * ID of the gnunet-wlan-server std read task
134 GNUNET_SCHEDULER_TaskIdentifier server_read_task;
137 * ID of the gnunet-wlan-server std read task
139 GNUNET_SCHEDULER_TaskIdentifier server_write_task;
142 * ID of the delay task for writing
144 GNUNET_SCHEDULER_TaskIdentifier server_write_delay_task;
147 * The process id of the wlan process
149 struct GNUNET_OS_Process *server_proc;
152 * The interface of the wlan card given to us by the user.
157 * The mac_address of the wlan card given to us by the helper.
162 * Sessions currently pending for transmission
163 * to this peer, if any.
165 struct Sessionqueue * pending_Sessions;
168 * Sessions currently pending for transmission
169 * to this peer (tail), if any.
171 struct Sessionqueue * pending_Sessions_tail;
174 * number of pending sessions
176 unsigned int pendingsessions;
179 * Messages in the fragmentation queue, head
182 struct FragmentMessage * pending_Fragment_Messages_head;
185 * Messages in the fragmentation queue, tail
188 struct FragmentMessage * pending_Fragment_Messages_tail;
191 * number of pending fragment message
194 unsigned int pending_fragment_messages;
197 * time of the next "hello-beacon"
200 struct GNUNET_TIME_Absolute beacon_time;
205 * Queue of sessions, for the general session queue and the pending session queue
210 struct Sessionqueue * next;
211 struct Sessionqueue * prev;
212 struct Session * content;
216 * Queue of ack received for messages send
221 struct AckQueue * next;
222 struct AckQueue * prev;
223 int fragment_num; //TODO change it to offset
227 * Queue for the fragments received
232 struct RecQueue * next;
233 struct RecQueue * prev;
240 * Information kept for each message that is yet to
243 struct PendingMessage
247 * The pending message
252 * Continuation function to call once the message
253 * has been sent. Can be NULL if there is no
254 * continuation to call.
256 GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
259 * Cls for transmit_cont
261 void * transmit_cont_cls;
264 * Timeout value for the pending message.
266 struct GNUNET_TIME_Absolute timeout;
269 * Size of the message
276 * Session infos gathered from a messages
282 * the session this message belongs to
284 struct Session * session;
292 * Session handle for connections.
300 struct SessionHeader header;
303 * Pointer to the global plugin struct.
305 struct Plugin *plugin;
308 * Message currently pending for transmission
309 * to this peer, if any.
311 struct PendingMessage *pending_message;
314 * To whom are we talking to (set to our identity
315 * if we are still waiting for the welcome message)
317 struct GNUNET_PeerIdentity target;
320 * encapsulation of the receive data
322 //struct GNUNET_SERVER_MessageStreamTokenizer * receive_token;
325 * offset of the next fragment for the receive_token, -1 means last message finished
331 * size of the message received, -1 means that the size is not known, -2 means no message received
337 * Sorted queue with the fragments received; head
340 struct RecQueue * frag_head;
343 * Sorted queue with the fragments received; tail
346 struct RecQueue * frag_tail;
354 * Address of the other peer (either based on our 'connect'
355 * call or on our 'accept' call).
360 * Last activity on this connection. Used to select preferred
363 struct GNUNET_TIME_Absolute last_activity;
366 * current number for message incoming, to distinguish between the messages
368 uint32_t message_id_in;
371 * current number for message outgoing, to distinguish between the messages
373 uint32_t message_id_out;
376 * does this session have a message in the fragment queue
386 struct FragmentMessage
389 * Session this message belongs to
392 struct Session *session;
395 * This is a doubly-linked list.
397 struct FragmentMessage *next;
400 * This is a doubly-linked list.
402 struct FragmentMessage *prev;
405 * The pending message
410 * Timeout value for the pending message.
412 struct GNUNET_TIME_Absolute timeout;
415 * Timeout value for the pending fragments.
416 * Stores the time when the next msg fragment ack has to be received
418 struct GNUNET_TIME_Absolute next_ack;
421 * Sorted queue with the acks received for fragments; head
424 struct AckQueue * head;
427 * Sorted queue with the acks received for fragments; tail
430 struct AckQueue * tail;
433 * Size of the message
438 * pos / next fragment number in the message, for fragmentation/segmentation,
439 * some acks can be missing but there is still time
441 uint32_t message_pos;
446 * Header for messages which need fragmentation
451 struct GNUNET_MessageHeader header;
454 * checksum/error correction
456 uint32_t crc GNUNET_PACKED;
459 * To whom are we talking to (set to our identity
460 * if we are still waiting for the welcome message)
462 struct GNUNET_PeerIdentity target;
464 // followed by payload
469 * Header for messages which need fragmentation
471 struct FragmentationHeader
474 struct GNUNET_MessageHeader header;
477 * To whom are we talking to (set to our identity
478 * if we are still waiting for the welcome message)
480 // struct GNUNET_PeerIdentity target GNUNET_PACKED;
483 * ID of message, to distinguish between the messages, picked randomly.
485 uint32_t message_id GNUNET_PACKED;
488 * Offset or number of this fragment, for fragmentation/segmentation (design choice, TBD)
490 uint16_t fragment_off_or_num GNUNET_PACKED;
493 * CRC of fragment (for error checking)
495 uint16_t message_crc GNUNET_PACKED;
499 * // 0x1 ack => Use two different message types in header.type! (FRAG_MESSAGE; FRAG_ACK)
500 * // 0x2 has data (not only ack)
501 * // 0x4 last fragment of message
504 // uint32_t flags GNUNET_PACKED;
507 * checksum/error correction
509 // uint32_t crc GNUNET_PACKED;
511 // followed by payload unless ACK
515 //enum { ACK_FRAGMENT = 1, DATA_FRAGMENT = 2, LAST_FRAGMENT = 4, NEW_MESSAGE = 8 };
518 getRadiotapHeader(struct RadiotapHeader * Header);
521 getWlanHeader(struct IeeeHeader * Header);
524 wlan_plugin_address_suggested(void *cls, const void *addr, size_t addrlen);
527 getcrc16(const char *msgbuf, size_t msgbuf_size);
530 do_transmit(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
533 check_fragment_queue(struct Plugin * plugin);
536 getcrc32(const char *msgbuf, size_t msgbuf_size);
539 * get the next message number, at the moment just a random one
544 get_next_message_id()
546 return GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX);
550 * start next message number generator
554 start_next_message_id()
556 //GNUNET_CRYPTO_random_init;
560 * search for a session with the addr
562 * @param plugin pointer to the plugin struct
563 * @param addr pointer to the mac address of the peer
564 * @return returns the session
567 static struct Session *
568 search_session(struct Plugin *plugin, const uint8_t * addr)
570 struct Sessionqueue * queue = plugin->sessions;
571 struct Sessionqueue * lastitem = NULL;
573 //just look at all the session for the needed one
574 while (queue != NULL)
576 // content is never NULL
577 GNUNET_assert (queue->content == NULL);
578 char * addr2 = queue->content->addr;
579 if (memcmp(addr, addr2, 6) == 0)
582 return queue->content;
592 * create a new session
594 * @param plugin pointer to the plugin struct
595 * @param addr pointer to the mac address of the peer
596 * @return returns the session
599 static struct Session *
600 create_session(struct Plugin *plugin,const uint8_t * addr)
602 struct Sessionqueue * queue = GNUNET_malloc (sizeof (struct Sessionqueue));
604 GNUNET_CONTAINER_DLL_insert_tail(plugin->sessions, plugin->sessions_tail, queue);
606 queue->content = GNUNET_malloc (sizeof (struct Session));
607 queue->content->plugin = plugin;
608 memcpy(queue->content->addr, addr, 6);
609 queue->content->message_id_out = get_next_message_id();
610 queue->content->has_fragment = 0;
611 queue->content->rec_size = -2;
613 plugin->session_count++;
614 return queue->content;
618 * get Session from address, create if no session exists
620 * @param plugin pointer to the plugin struct
621 * @param addr pointer to the mac address of the peer
622 * @return returns the session
624 //TODO add other possibilities to find the right session (are there other?)
625 static struct Session *
626 get_Session(struct Plugin *plugin, const uint8_t * addr)
628 struct Session * session = search_session(plugin, addr);
634 return create_session(plugin, addr);
636 /* -- not needed, layer above already has it--
637 //queue welcome message for new sessions, not realy needed
638 //struct WelcomeMessage welcome;
639 struct PendingMessage *pm;
640 pm = GNUNET_malloc (sizeof (struct PendingMessage));
641 pm->msg = GNUNET_malloc(GNUNET_HELLO_size(* (plugin->env->our_hello)));
642 pm->message_size = GNUNET_HELLO_size(* (plugin->env->our_hello));
643 //welcome.header.size = htons (GNUNET_HELLO_size(* (plugin->env->our_hello)));
644 //welcome.header.type = htons (GNUNET_MESSAGE_TYPE_WLAN_ADVERTISEMENT);
645 //welcome.clientIdentity = *plugin->env->my_identity;
646 memcpy ( (pm->msg), * plugin->env->our_hello, GNUNET_HELLO_size(* (plugin->env->our_hello)));
647 pm->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
648 queue->content->pending_message = pm;
649 plugin->pendingsessions ++;
650 GNUNET_CONTAINER_DLL_insert_tail(plugin->pending_Sessions, plugin->pending_Sessions_tail, queue);
652 check_fragment_queue(plugin);
657 * Queue the session to send data
661 queue_Session (struct Plugin *plugin,
662 struct Session * session)
664 struct Sessionqueue * queue = plugin->pending_Sessions;
665 struct Sessionqueue * lastitem = NULL;
667 while (queue != NULL){
668 // content is never NULL
669 GNUNET_assert (queue->content == NULL);
670 // is session already in queue?
671 if (session == queue->content){
679 // Session is not in the queue
681 queue = GNUNET_malloc (sizeof (struct Sessionqueue));
682 queue->content = session;
685 GNUNET_CONTAINER_DLL_insert_after (plugin->pending_Sessions,
686 plugin->pending_Sessions_tail,
687 plugin->pending_Sessions_tail, queue);
688 plugin->pendingsessions ++;
694 free_acks (struct FragmentMessage * fm){
695 struct AckQueue * fq;
696 while (fm->head != NULL){
698 GNUNET_CONTAINER_DLL_remove(fm->head, fm->tail, fq);
705 * Function to schedule the write task, executed after a delay
708 delay_fragment_task(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
710 struct Plugin * plugin = cls;
711 plugin->server_write_delay_task = GNUNET_SCHEDULER_NO_TASK;
713 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
716 // GNUNET_TIME_UNIT_FOREVER_REL is needed to clean up old msg
717 if (plugin->server_write_task == GNUNET_SCHEDULER_NO_TASK)
719 plugin->server_write_task = GNUNET_SCHEDULER_add_write_file(
720 GNUNET_TIME_UNIT_FOREVER_REL, plugin->server_stdin_handle,
721 &do_transmit, plugin);
727 * Function to calculate the time of the next periodic "hello-beacon"
730 set_next_beacon_time(struct Plugin * const plugin)
732 //under 10 known peers: once a second
733 if (plugin->session_count < 10)
735 plugin->beacon_time = GNUNET_TIME_absolute_add(
736 GNUNET_TIME_absolute_get(), GNUNET_TIME_UNIT_SECONDS);
738 //under 30 known peers: every 10 seconds
739 else if (plugin->session_count < 30)
741 plugin->beacon_time = GNUNET_TIME_absolute_add(
742 GNUNET_TIME_absolute_get(), GNUNET_TIME_relative_multiply(
743 GNUNET_TIME_UNIT_SECONDS, 10));
745 //over 30 known peers: once a minute
748 plugin->beacon_time = GNUNET_TIME_absolute_add(
749 GNUNET_TIME_absolute_get(), GNUNET_TIME_UNIT_MINUTES);
755 struct GNUNET_TIME_Relative
756 get_next_frag_timeout(struct FragmentMessage * fm)
758 return GNUNET_TIME_relative_min(GNUNET_TIME_absolute_get_remaining(
759 fm->next_ack), GNUNET_TIME_absolute_get_remaining(fm->timeout));
764 * Function to get the timeout value for acks for this session
767 struct GNUNET_TIME_Relative
768 get_ack_timeout (struct FragmentMessage * fm){
769 return FRAGMENT_TIMEOUT;
774 * Function to set the timer for the next timeout of the fragment queue
777 check_next_fragment_timeout(struct Plugin * const plugin)
779 struct FragmentMessage * fm;
780 struct GNUNET_TIME_Relative next_send;
782 next_send = GNUNET_TIME_absolute_get_remaining(plugin->beacon_time);
785 if (plugin->server_write_delay_task != GNUNET_SCHEDULER_NO_TASK)
787 GNUNET_SCHEDULER_cancel(plugin->server_write_delay_task);
789 fm = plugin->pending_Fragment_Messages_head;
791 GNUNET_assert(plugin->server_write_delay_task == GNUNET_SCHEDULER_NO_TASK);
793 //check if there are some fragments in the queue
797 = GNUNET_TIME_relative_min(next_send, get_next_frag_timeout(fm));
799 plugin->server_write_delay_task = GNUNET_SCHEDULER_add_delayed(next_send,
800 &delay_fragment_task, plugin);
807 * Function to get the next queued Session, removes the session from the queue
810 static struct Session *
811 get_next_queue_Session (struct Plugin * plugin){
812 struct Session * session;
813 struct Sessionqueue * sessionqueue;
814 struct Sessionqueue * sessionqueue_alt;
815 struct PendingMessage * pm;
816 sessionqueue = plugin->pending_Sessions;
817 while (sessionqueue != NULL){
818 session = sessionqueue->content;
819 pm = session->pending_message;
821 //check for message timeout
822 if (GNUNET_TIME_absolute_get_remaining(pm->timeout).rel_value > 0){
823 //check if session has no message in the fragment queue
824 if (! session->has_fragment){
825 plugin->pendingsessions --;
826 GNUNET_CONTAINER_DLL_remove (plugin->pending_Sessions,
827 plugin->pending_Sessions_tail, sessionqueue);
828 GNUNET_free(sessionqueue);
832 sessionqueue = sessionqueue->next;
836 session->pending_message = NULL;
837 //call the cont func that it did not work
838 if (pm->transmit_cont != NULL)
839 pm->transmit_cont (pm->transmit_cont_cls,
840 &(session->target), GNUNET_SYSERR);
841 GNUNET_free(pm->msg);
844 sessionqueue_alt = sessionqueue;
845 sessionqueue = sessionqueue->next;
846 plugin->pendingsessions --;
847 GNUNET_CONTAINER_DLL_remove (plugin->pending_Sessions,
848 plugin->pending_Sessions_tail, sessionqueue_alt);
850 GNUNET_free(sessionqueue_alt);
861 * Function to sort the message into the message fragment queue
864 sort_fragment_into_queue (struct Plugin * plugin, struct FragmentMessage * fm){
865 struct FragmentMessage * fm2;
866 //sort into the list at the right position
868 fm2 = plugin->pending_Fragment_Messages_head;
871 if (GNUNET_TIME_absolute_get_difference(fm2->next_ack, fm->next_ack).rel_value == 0){
878 GNUNET_CONTAINER_DLL_insert_after(plugin->pending_Fragment_Messages_head,
879 plugin->pending_Fragment_Messages_tail,fm2,fm);
884 free_fragment_message(struct Plugin * plugin,struct FragmentMessage * fm)
889 GNUNET_free_non_null(fm->msg);
890 GNUNET_CONTAINER_DLL_remove (plugin->pending_Fragment_Messages_head,
891 plugin->pending_Fragment_Messages_tail, fm);
893 plugin->pending_fragment_messages --;
894 check_fragment_queue(plugin);
900 * Function to check if there is some space in the fragment queue
904 check_fragment_queue (struct Plugin * plugin){
905 struct Session * session;
906 struct FragmentMessage * fm;
908 struct PendingMessage * pm;
910 if (plugin->pending_fragment_messages < FRAGMENT_QUEUE_SIZE){
911 session = get_next_queue_Session(plugin);
912 if (session != NULL){
913 pm = session->pending_message;
914 session->pending_message = NULL;
915 session->has_fragment = 1;
916 GNUNET_assert(pm != NULL);
918 fm = GNUNET_malloc(sizeof(struct FragmentMessage));
919 fm->message_size = pm->message_size;
921 fm->session = session;
922 fm->timeout.abs_value = pm->timeout.abs_value;
924 fm->next_ack = GNUNET_TIME_absolute_get();
926 if (pm->transmit_cont != NULL)
927 pm->transmit_cont (pm->transmit_cont_cls,
928 &(session->target), GNUNET_OK);
931 sort_fragment_into_queue(plugin,fm);
932 plugin->pending_fragment_messages ++;
934 //generate new message id
935 session->message_id_out = get_next_message_id();
937 //check if timeout changed
938 check_next_fragment_timeout(plugin);
944 check_finished_fragment(struct Plugin * plugin, struct FragmentMessage * fm){
945 struct AckQueue * ack;
948 if (fm->message_size >= (WLAN_MTU - sizeof(struct FragmentationHeader))
949 * fm->tail->fragment_num)
953 //check if all acks are present
956 if (counter == ack->fragment_num)
965 fm->session->has_fragment = 0;
966 free_fragment_message(plugin, fm);
973 * Function called to when wlan helper is ready to get some data
976 * @param GNUNET_SCHEDULER_TaskContext
980 do_transmit (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
983 struct Plugin * plugin = cls;
984 plugin->server_write_task = GNUNET_SCHEDULER_NO_TASK;
988 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
991 struct Session * session = NULL;
992 struct FragmentMessage * fm = NULL;
993 struct IeeeHeader * ieeewlanheader = NULL;
994 struct RadiotapHeader * radioHeader = NULL;
995 struct GNUNET_MessageHeader * msgheader = NULL;
996 struct GNUNET_MessageHeader * msgheader2 = NULL;
997 struct FragmentationHeader fragheader;
999 const char * copystart = NULL;
1000 uint16_t copysize = 0;
1001 uint copyoffset = 0;
1002 struct AckQueue * akt = NULL;
1004 //test if a "hello-beacon" has to be send
1005 if (GNUNET_TIME_absolute_get_remaining(plugin->beacon_time).rel_value == 0)
1007 //check if the message is not to big
1008 GNUNET_assert(sizeof(struct WlanHeader) + GNUNET_HELLO_size(
1009 *(plugin->env->our_hello)) <= WLAN_MTU);
1010 size = sizeof(struct GNUNET_MessageHeader)
1011 + sizeof(struct RadiotapHeader) + sizeof(struct IeeeHeader)
1012 + sizeof(struct GNUNET_MessageHeader) + GNUNET_HELLO_size(
1013 *(plugin->env->our_hello));
1015 msgheader = GNUNET_malloc(size);
1016 msgheader->size = htons(size - sizeof(struct GNUNET_MessageHeader));
1017 msgheader->type = htons(GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA);
1019 radioHeader = (struct RadiotapHeader *) &msgheader[1];
1020 getRadiotapHeader(radioHeader);
1022 ieeewlanheader = (struct IeeeHeader *) &radioHeader[1];
1023 getWlanHeader(ieeewlanheader);
1025 msgheader2 = (struct GNUNET_MessageHeader *) &ieeewlanheader[1];
1026 msgheader2->size = htons(GNUNET_HELLO_size(*(plugin->env->our_hello)));
1027 msgheader2->type = htons(GNUNET_MESSAGE_TYPE_WLAN_ADVERTISEMENT);
1029 memcpy(&msgheader2[1], *plugin->env->our_hello, GNUNET_HELLO_size(
1030 *(plugin->env->our_hello)));
1033 bytes = GNUNET_DISK_file_write(plugin->server_stdin_handle, msgheader,
1035 GNUNET_assert(bytes == size);
1037 set_next_beacon_time(plugin);
1038 check_next_fragment_timeout(plugin);
1044 fm = plugin->pending_Fragment_Messages_head;
1045 GNUNET_assert(fm != NULL);
1046 session = fm->session;
1047 GNUNET_assert(session != NULL);
1049 // test if message timed out
1050 if (GNUNET_TIME_absolute_get_remaining(fm->timeout).rel_value == 0){
1052 GNUNET_assert(plugin->pending_fragment_messages > 0);
1053 plugin->pending_fragment_messages --;
1054 GNUNET_CONTAINER_DLL_remove(plugin->pending_Fragment_Messages_head,
1055 plugin->pending_Fragment_Messages_tail, fm);
1057 GNUNET_free(fm->msg);
1060 check_fragment_queue(plugin);
1063 if (fm->message_size > WLAN_MTU) {
1064 size += sizeof(struct FragmentationHeader);
1065 // check/set for retransmission
1066 if (GNUNET_TIME_absolute_get_duration(fm->next_ack).rel_value == 0) {
1068 // be positive and try again later :-D
1069 fm->next_ack = GNUNET_TIME_relative_to_absolute(get_ack_timeout(fm));
1070 // find first missing fragment
1072 fm->message_pos = 0;
1074 //test if ack 0 was already received
1075 while (akt != NULL){
1076 //if fragment is present, take next
1077 if (akt->fragment_num == fm->message_pos) {
1080 //next ack is bigger then the fragment number
1081 //in case there is something like this: (acks) 1, 2, 5, 6, ...
1082 //and we send 3 again, the next number should be 4
1083 else if (akt->fragment_num > fm->message_pos) {
1094 copyoffset = (WLAN_MTU - sizeof(struct FragmentationHeader)) * fm->message_pos;
1095 fragheader.fragment_off_or_num = htons(fm->message_pos);
1096 fragheader.message_id = htonl(session->message_id_out);
1098 // start should be smaller then the packet size
1099 GNUNET_assert(copyoffset < fm->message_size);
1100 copystart = fm->msg + copyoffset;
1102 //size of the fragment is either the MTU - overhead
1103 //or the missing part of the message in case this is the last fragment
1104 copysize = GNUNET_MIN(fm->message_size - copyoffset,
1105 WLAN_MTU - sizeof(struct FragmentationHeader));
1106 fragheader.header.size = htons(copysize);
1107 fragheader.header.type = htons(GNUNET_MESSAGE_TYPE_WLAN_FRAGMENT);
1110 //get the next missing fragment
1114 //test if ack was already received
1115 while (akt != NULL){
1116 //if fragment is present, take next
1117 if (akt->fragment_num == fm->message_pos) {
1120 //next ack is bigger then the fragment number
1121 //in case there is something like this: (acks) 1, 2, 5, 6, ...
1122 //and we send 3 again, the next number should be 4
1123 else if (akt->fragment_num > fm->message_pos) {
1130 // there is no need to split
1131 copystart = fm->msg;
1132 copysize = fm->message_size;
1136 size += sizeof(struct RadiotapHeader) + sizeof(struct IeeeHeader)
1137 + sizeof(struct GNUNET_MessageHeader);
1138 msgheader = GNUNET_malloc(size);
1139 msgheader->size = htons(size - sizeof(struct GNUNET_MessageHeader));
1140 msgheader->type = htons(GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA);
1142 radioHeader = (struct RadiotapHeader*) &msgheader[1];
1143 getRadiotapHeader(radioHeader);
1145 ieeewlanheader = (struct IeeeHeader *) &radioHeader[1];
1146 getWlanHeader(ieeewlanheader);
1149 //could be faster if content is just send and not copyed before
1150 //fragmentheader is needed
1151 if (fm->message_size > WLAN_MTU){
1152 fragheader.message_crc = htons(getcrc16(copystart, copysize));
1153 memcpy(&ieeewlanheader[1],&fragheader, sizeof(struct FragmentationHeader));
1154 memcpy(&ieeewlanheader[1] + sizeof(struct FragmentationHeader),copystart,copysize);
1156 memcpy(&ieeewlanheader[1],copystart,copysize);
1159 bytes = GNUNET_DISK_file_write(plugin->server_stdin_handle, msgheader, size);
1160 GNUNET_assert(bytes == size);
1162 //check if this was the last fragment of this message, if true then queue at the end of the list
1163 if (copysize + copyoffset >= fm->message_size){
1164 GNUNET_assert(copysize + copyoffset == fm->message_size);
1166 GNUNET_CONTAINER_DLL_remove (plugin->pending_Fragment_Messages_head,
1167 plugin->pending_Fragment_Messages_tail, fm);
1169 GNUNET_CONTAINER_DLL_insert_tail(plugin->pending_Fragment_Messages_head,
1170 plugin->pending_Fragment_Messages_tail, fm);
1171 // if fragments have opimized timeouts
1172 //sort_fragment_into_queue(plugin,fm);
1175 check_next_fragment_timeout(plugin);
1184 * @param msgbuf pointer tor the data
1185 * @param msgbuf_size size of the data
1187 * @return 32bit crc value
1191 getcrc32 (const char *msgbuf,
1192 size_t msgbuf_size){
1193 //TODO calc some crc
1200 * @param msgbuf pointer tor the data
1201 * @param msgbuf_size size of the data
1203 * @return 16bit crc value
1207 getcrc16 (const char *msgbuf,
1208 size_t msgbuf_size){
1209 //TODO calc some crc
1214 * Function that can be used by the transport service to transmit
1215 * a message using the plugin.
1217 * @param cls closure
1218 * @param target who should receive this message
1219 * @param priority how important is the message
1220 * @param msgbuf the message to transmit
1221 * @param msgbuf_size number of bytes in 'msgbuf'
1222 * @param timeout when should we time out
1223 * @param session which session must be used (or NULL for "any")
1224 * @param addr the address to use (can be NULL if the plugin
1225 * is "on its own" (i.e. re-use existing TCP connection))
1226 * @param addrlen length of the address in bytes
1227 * @param force_address GNUNET_YES if the plugin MUST use the given address,
1228 * otherwise the plugin may use other addresses or
1229 * existing connections (if available)
1230 * @param cont continuation to call once the message has
1231 * been transmitted (or if the transport is ready
1232 * for the next transmission call; or if the
1233 * peer disconnected...)
1234 * @param cont_cls closure for cont
1235 * @return number of bytes used (on the physical network, with overheads);
1236 * -1 on hard errors (i.e. address invalid); 0 is a legal value
1237 * and does NOT mean that the message was not transmitted (DV)
1240 wlan_plugin_send (void *cls,
1241 const struct GNUNET_PeerIdentity * target,
1244 unsigned int priority,
1245 struct GNUNET_TIME_Relative timeout,
1246 struct Session *session,
1250 GNUNET_TRANSPORT_TransmitContinuation cont,
1253 struct Plugin * plugin = cls;
1254 struct PendingMessage * newmsg = NULL;
1255 struct WlanHeader * wlanheader = NULL;
1256 //check if msglen > 0
1257 GNUNET_assert(msgbuf_size > 0);
1259 //get session if needed
1260 if (session == NULL)
1262 if (wlan_plugin_address_suggested(plugin, addr, addrlen) == GNUNET_OK)
1264 session = get_Session(plugin, addr);
1268 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1269 _("Wlan Address len %d is wrong\n"), addrlen);
1274 //TODO target "problem" not solved
1275 session->target = *target;
1278 //first queue session
1279 queue_Session(plugin, session);
1281 //queue message in session
1282 //test if there is no other message in the "queue"
1283 GNUNET_assert (session->pending_message == NULL);
1285 newmsg = GNUNET_malloc(sizeof(struct PendingMessage));
1286 (newmsg->msg) = GNUNET_malloc(msgbuf_size + sizeof(struct WlanHeader));
1287 wlanheader = (struct WlanHeader *) newmsg->msg;
1288 //copy msg to buffer, not fragmented / segmented yet, but with message header
1289 wlanheader->header.size = htons(msgbuf_size);
1290 wlanheader->header.type = htons(GNUNET_MESSAGE_TYPE_WLAN_DATA);
1291 memcpy(&(wlanheader->target), target, sizeof(struct GNUNET_PeerIdentity));
1292 wlanheader->crc = htonl(getcrc32(msgbuf, msgbuf_size));
1293 memcpy(&wlanheader[1], msgbuf, msgbuf_size);
1294 newmsg->transmit_cont = cont;
1295 newmsg->transmit_cont_cls = cont_cls;
1296 newmsg->timeout = GNUNET_TIME_relative_to_absolute(timeout);
1297 newmsg->message_size = msgbuf_size + sizeof(struct WlanHeader);
1299 check_fragment_queue(plugin);
1300 //FIXME not the correct size
1305 static struct FragmentMessage *
1306 get_fragment_message_from_session(struct Session * session)
1308 struct FragmentMessage * fm = session->plugin->pending_Fragment_Messages_head;
1311 if (fm->session == session)
1321 * Function that can be used to force the plugin to disconnect
1322 * from the given peer and cancel all previous transmissions
1323 * (and their continuation).
1325 * @param cls closure
1326 * @param target peer from which to disconnect
1329 wlan_plugin_disconnect(void *cls, const struct GNUNET_PeerIdentity *target)
1331 struct Plugin *plugin = cls;
1332 struct Sessionqueue * queue = plugin->sessions;
1333 struct Sessionqueue * pendingsession = plugin->pending_Sessions;
1334 struct PendingMessage * pm = NULL;
1335 struct FragmentMessage * fm;
1337 // just look at all the session for the needed one
1338 while (queue != NULL)
1340 // content is never NULL
1341 GNUNET_assert (queue->content == NULL);
1342 if (memcmp(target, &(queue->content->target),
1343 sizeof(struct GNUNET_PeerIdentity)) == 0)
1346 //is this session pending for send
1347 while (pendingsession != NULL)
1349 if (pendingsession->content == queue->content)
1351 plugin->pendingsessions --;
1352 GNUNET_CONTAINER_DLL_remove (plugin->pending_Sessions,
1353 plugin->pending_Sessions_tail, pendingsession);
1354 GNUNET_free(pendingsession);
1357 pendingsession = pendingsession->next;
1360 //is something of this session in the fragment queue?
1361 fm = get_fragment_message_from_session(queue->content);
1362 free_fragment_message(plugin,fm);
1365 // remove PendingMessage
1366 pm = queue->content->pending_message;
1367 GNUNET_free(pm->msg);
1370 GNUNET_free(queue->content);
1371 GNUNET_CONTAINER_DLL_remove(plugin->sessions, plugin->sessions_tail, queue);
1373 plugin->session_count --;
1378 queue = queue->next;
1384 * Convert the transports address to a nice, human-readable
1387 * @param cls closure
1388 * @param type name of the transport that generated the address
1389 * @param addr one of the addresses of the host, NULL for the last address
1390 * the specific address format depends on the transport
1391 * @param addrlen length of the address
1392 * @param numeric should (IP) addresses be displayed in numeric form?
1393 * @param timeout after how long should we give up?
1394 * @param asc function to call on each string
1395 * @param asc_cls closure for asc
1398 wlan_plugin_address_pretty_printer (void *cls,
1403 struct GNUNET_TIME_Relative timeout,
1404 GNUNET_TRANSPORT_AddressStringCallback
1408 const unsigned char * input;
1410 GNUNET_assert(cls !=NULL);
1413 /* invalid address (MAC addresses have 6 bytes) */
1415 asc (asc_cls, NULL);
1418 input = (const unsigned char*) addr;
1419 GNUNET_snprintf (ret,
1421 "%s Mac-Adress %X:%X:%X:%X:%X:%X",
1423 input[0], input[1], input[2], input[3], input[4], input[5]);
1430 * Another peer has suggested an address for this
1431 * peer and transport plugin. Check that this could be a valid
1432 * address. If so, consider adding it to the list
1435 * @param cls closure
1436 * @param addr pointer to the address
1437 * @param addrlen length of addr
1438 * @return GNUNET_OK if this is a plausible address for this peer
1444 wlan_plugin_address_suggested (void *cls,
1448 //struct Plugin *plugin = cls;
1450 /* check if the address is plausible; if so,
1451 add it to our list! */
1453 GNUNET_assert(cls !=NULL);
1454 //FIXME mitm is not checked
1455 //Mac Adress has 6 bytes
1457 /* TODO check for bad addresses like milticast, broadcast, etc */
1460 return GNUNET_SYSERR;
1463 return GNUNET_SYSERR;
1468 * Function called for a quick conversion of the binary address to
1469 * a numeric address. Note that the caller must not free the
1470 * address and that the next call to this function is allowed
1471 * to override the address again.
1473 * @param cls closure
1474 * @param addr binary address
1475 * @param addrlen length of the address
1476 * @return string representing the same address
1479 wlan_plugin_address_to_string (void *cls,
1484 const unsigned char * input;
1486 GNUNET_assert(cls !=NULL);
1489 /* invalid address (MAC addresses have 6 bytes) */
1493 input = (const unsigned char*) addr;
1494 GNUNET_snprintf (ret,
1496 "%s Mac-Adress %X:%X:%X:%X:%X:%X",
1498 input[0], input[1], input[2], input[3], input[4], input[5]);
1499 return GNUNET_strdup (ret);
1506 * Function used for to process the data from the suid process
1511 wlan_process_helper (void *cls,
1513 const struct GNUNET_MessageHeader *hdr)
1515 struct Plugin *plugin = cls;
1516 struct IeeeHeader * wlanIeeeHeader = NULL;
1517 struct Session * session = NULL;
1518 struct WlanHeader * wlanheader = NULL;
1519 struct FragmentationHeader * fh = NULL;
1520 struct FragmentMessage * fm = NULL;
1521 const struct GNUNET_MessageHeader * temp_hdr = NULL;
1522 const char * tempmsg = NULL;
1523 struct Session_light * session_light;
1524 struct AckQueue * ack;
1525 struct AckQueue * ack2;
1529 if (ntohs(hdr->type) == GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA)
1531 //call wlan_process_helper with the message inside, later with wlan: analyze signal
1532 GNUNET_assert(ntohs(hdr->size) >= sizeof(struct IeeeHeader));
1533 wlanIeeeHeader = (struct IeeeHeader *) &hdr[1];
1535 session_light = GNUNET_malloc(sizeof(struct Session_light));
1536 memcpy(session_light->addr, wlanIeeeHeader->mac3, 6);
1537 session_light->session = search_session(plugin, session_light->addr);
1539 //process only if it is an broadcast or for this computer both with the gnunet bssid
1541 if (memcmp(wlanIeeeHeader->mac2, macbc, sizeof(macbc)))
1543 //check for broadcast or mac
1544 if (memcmp(wlanIeeeHeader->mac1, bc_all_mac, sizeof(bc_all_mac))
1545 || memcmp(wlanIeeeHeader->mac1, plugin->mac_address,
1546 sizeof(plugin->mac_address)))
1548 // process the inner data
1550 temp_hdr = (struct GNUNET_MessageHeader *) &wlanIeeeHeader[1];
1551 while (pos < hdr->size)
1553 wlan_process_helper(plugin, &session_light,
1555 pos += temp_hdr->size + sizeof(struct GNUNET_MessageHeader);
1563 else if (ntohs(hdr->type) == GNUNET_MESSAGE_TYPE_WLAN_ADVERTISEMENT)
1565 //TODO better DOS protection, error handling
1566 GNUNET_assert(client != NULL);
1567 session_light = (struct Session_light *) client;
1568 if (session_light->session == NULL){
1569 session_light->session = get_Session(plugin, session_light->addr);
1571 GNUNET_assert(GNUNET_HELLO_get_id(
1572 (const struct GNUNET_HELLO_Message *) &hdr[1],
1573 &(session_light->session->target) ) != GNUNET_SYSERR);
1578 else if (ntohs(hdr->type) == GNUNET_MESSAGE_TYPE_WLAN_DATA)
1580 GNUNET_assert(client != NULL);
1581 session_light = (struct Session_light *) client;
1582 if (session_light->session == NULL){
1583 session_light->session = search_session(plugin, session_light->addr);
1585 session = session_light->session;
1586 wlanheader =(struct WlanHeader *) &hdr[1];
1587 tempmsg = (char*) &wlanheader[1];
1588 temp_hdr = ( const struct GNUNET_MessageHeader *) &wlanheader[1];
1590 if (getcrc32(tempmsg, wlanheader->header.size) != wlanheader->crc){
1591 //wrong crc, dispose message
1592 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1593 "WLAN message crc was wrong\n");
1597 //if not in session list
1598 if (session == NULL){
1600 //try if it is a hello message
1601 if (ntohs(temp_hdr->type) == GNUNET_MESSAGE_TYPE_HELLO){
1602 session = create_session(plugin, session_light->addr);
1603 session_light->session = session;
1604 GNUNET_assert(GNUNET_HELLO_get_id(
1605 (const struct GNUNET_HELLO_Message *) temp_hdr,
1606 &session->target ) != GNUNET_SYSERR);
1609 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1610 "WLAN client not in session list and not a hello message\n");
1614 //"receive" the message
1615 plugin->env->receive(plugin, &session->target,
1616 temp_hdr, 1, session, session->addr, sizeof(session->addr));
1619 else if (ntohs(hdr->type) == GNUNET_MESSAGE_TYPE_WLAN_FRAGMENT)
1621 GNUNET_assert(client != NULL);
1622 session_light = (struct Session_light *) client;
1623 if (session_light->session == NULL)
1625 session_light->session = search_session(plugin, session_light->addr);
1627 session = session_light->session;
1629 fh = (struct FragmentationHeader *) &hdr[1];
1630 tempmsg = (char*) &fh[1];
1632 //if not in session list
1633 if (session != NULL)
1635 if (getcrc16(tempmsg, fh->header.size) != fh->message_crc)
1637 //wrong crc, dispose message
1638 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1639 "WLAN fragment crc was wrong\n");
1644 //todo fragments to message
1649 GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
1650 "WLAN client not in session list and it is a fragment message\n");
1656 else if (ntohs(hdr->type) == GNUNET_MESSAGE_TYPE_WLAN_FRAGMENT_ACK)
1658 GNUNET_assert(client != NULL);
1659 session_light = (struct Session_light *) client;
1660 if (session_light->session == NULL)
1662 session_light->session = search_session(plugin, session_light->addr);
1664 session = session_light->session;
1665 fh = (struct FragmentationHeader *) &hdr[1];
1666 if (fh->message_id == session->message_id_out)
1668 fm = get_fragment_message_from_session(session);
1671 ack = GNUNET_malloc(sizeof(struct AckQueue));
1672 ack->fragment_num = fh->fragment_off_or_num;
1675 if (ack2->fragment_num != ack->fragment_num)
1677 if (ack2->fragment_num > ack->fragment_num)
1679 GNUNET_CONTAINER_DLL_insert_before(fm->head,fm->tail,ack2,ack);
1681 check_finished_fragment(plugin, fm);
1691 GNUNET_CONTAINER_DLL_insert_tail(fm->head,fm->tail,ack);
1692 //should never happen but...
1693 check_finished_fragment(plugin, fm);
1697 GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
1698 "WLAN fragment not in fragment list but id is right\n");
1706 else if (ntohs(hdr->type) == GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL)
1709 if (ntohs(hdr->size) == 6)
1711 plugin->mac_address = GNUNET_malloc(6);
1712 memcpy(plugin->mac_address, &hdr[1], 6);
1714 GNUNET_ERROR_TYPE_DEBUG,
1715 "Notifying transport of address %s\n",
1716 wlan_plugin_address_to_string(cls, plugin->mac_address, hdr->size));
1717 plugin->env->notify_address(plugin->env->cls, "wlan",
1718 &plugin->mac_address, sizeof(plugin->mac_address),
1719 GNUNET_TIME_UNIT_FOREVER_REL);
1723 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Wrong wlan mac address %s\n",
1724 plugin->mac_address);
1738 wlan_plugin_helper_read (void *cls,
1739 const struct GNUNET_SCHEDULER_TaskContext *tc)
1741 struct Plugin *plugin = cls;
1742 plugin->server_read_task = GNUNET_SCHEDULER_NO_TASK;
1744 char mybuf[WLAN_MTU + sizeof(struct GNUNET_MessageHeader)];
1747 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
1750 bytes = GNUNET_DISK_file_read (plugin->server_stdout_handle,
1751 mybuf, sizeof(mybuf));
1755 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1756 _("Finished reading from wlan-helper stdout with code: %d\n"), bytes);
1760 GNUNET_SERVER_mst_receive(plugin->consoltoken, NULL,
1761 mybuf, bytes, GNUNET_NO, GNUNET_NO);
1763 GNUNET_assert(plugin->server_read_task == GNUNET_SCHEDULER_NO_TASK);
1764 plugin->server_read_task =
1765 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
1766 plugin->server_stdout_handle, &wlan_plugin_helper_read, plugin);
1771 * Start the gnunet-wlan-helper process.
1773 * @param plugin the transport plugin
1775 * @return GNUNET_YES if process was started, GNUNET_SYSERR on error
1778 wlan_transport_start_wlan_helper(struct Plugin *plugin)
1781 plugin->server_stdout = GNUNET_DISK_pipe(GNUNET_YES, GNUNET_NO, GNUNET_YES);
1782 if (plugin->server_stdout == NULL)
1783 return GNUNET_SYSERR;
1785 plugin->server_stdin = GNUNET_DISK_pipe(GNUNET_YES, GNUNET_YES, GNUNET_NO);
1786 if (plugin->server_stdin == NULL)
1787 return GNUNET_SYSERR;
1790 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1791 "Starting gnunet-wlan-helper process cmd: %s %s\n", "gnunet-wlan-helper", plugin->interface);
1793 /* Start the server process */
1794 plugin->server_proc = GNUNET_OS_start_process(plugin->server_stdin,
1795 plugin->server_stdout, "gnunet-transport-wlan-helper",
1796 "gnunet-transport-wlan-helper", plugin->interface, NULL);
1797 if (plugin->server_proc == NULL)
1800 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1801 "Failed to start gnunet-wlan-helper process\n");
1803 return GNUNET_SYSERR;
1805 /* Close the write end of the read pipe */
1806 GNUNET_DISK_pipe_close_end(plugin->server_stdout, GNUNET_DISK_PIPE_END_WRITE);
1808 /* Close the read end of the write pipe */
1809 GNUNET_DISK_pipe_close_end(plugin->server_stdin, GNUNET_DISK_PIPE_END_READ);
1811 plugin->server_stdout_handle = GNUNET_DISK_pipe_handle(plugin->server_stdout,
1812 GNUNET_DISK_PIPE_END_READ);
1813 plugin->server_stdin_handle = GNUNET_DISK_pipe_handle(plugin->server_stdin,
1814 GNUNET_DISK_PIPE_END_WRITE);
1816 GNUNET_assert(plugin->server_read_task == GNUNET_SCHEDULER_NO_TASK);
1817 plugin->server_read_task = GNUNET_SCHEDULER_add_read_file(
1818 GNUNET_TIME_UNIT_FOREVER_REL, plugin->server_stdout_handle,
1819 &wlan_plugin_helper_read, plugin);
1826 * Entry point for the plugin.
1828 * @param cls closure, the 'struct GNUNET_TRANSPORT_PluginEnvironment*'
1829 * @return the 'struct GNUNET_TRANSPORT_PluginFunctions*' or NULL on error
1832 libgnunet_plugin_transport_wlan_init (void *cls)
1834 struct GNUNET_SERVICE_Context *service;
1835 struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
1836 struct GNUNET_TRANSPORT_PluginFunctions *api;
1837 struct Plugin *plugin;
1839 GNUNET_assert(cls !=NULL);
1841 service = GNUNET_SERVICE_start ("transport-wlan", env->cfg);
1842 if (service == NULL){
1843 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1844 _("Failed to start service for `%s' transport plugin.\n"),
1849 plugin = GNUNET_malloc (sizeof (struct Plugin));
1851 plugin->pendingsessions = 0;
1852 plugin->session_count = 0;
1853 plugin->server_write_task = GNUNET_SCHEDULER_NO_TASK;
1854 plugin->server_read_task = GNUNET_SCHEDULER_NO_TASK;
1855 plugin->server_write_delay_task = GNUNET_SCHEDULER_NO_TASK;
1857 wlan_transport_start_wlan_helper(plugin);
1858 plugin->consoltoken = GNUNET_SERVER_mst_create(&wlan_process_helper,plugin);
1860 //plugin->sessions = GNUNET_malloc (sizeof (struct Sessionqueue));
1861 //plugin->pending_Sessions = GNUNET_malloc (sizeof (struct Sessionqueue));
1863 api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
1865 api->send = &wlan_plugin_send;
1866 api->disconnect = &wlan_plugin_disconnect;
1867 api->address_pretty_printer = &wlan_plugin_address_pretty_printer;
1868 api->check_address = &wlan_plugin_address_suggested;
1869 api->address_to_string = &wlan_plugin_address_to_string;
1872 start_next_message_id();
1879 * Exit point from the plugin.
1884 libgnunet_plugin_transport_wlan_done (void *cls)
1886 struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
1887 struct Plugin *plugin = api->cls;
1889 GNUNET_SERVER_mst_destroy(plugin->consoltoken);
1891 GNUNET_assert(cls !=NULL);
1893 GNUNET_free_non_null(plugin->mac_address);
1894 GNUNET_free (plugin);
1899 /* end of plugin_transport_wlan.c */