+ /**
+ * Timeout task.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier timeout_task;
+
+ /**
+ * Fragment to send
+ */
+ char *frag;
+
+ /**
+ * size of message
+ */
+ size_t size;
+
+ /**
+ * pointer to the ieee wlan header
+ */
+ struct ieee80211_frame *ieeewlanheader;
+ /**
+ * pointer to the radiotap header
+ */
+ struct Radiotap_Send *radioHeader;
+};
+
+static void
+do_transmit (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+static void
+free_session (struct Plugin *plugin, struct Sessionqueue *queue,
+ int do_free_macendpoint);
+static struct MacEndpoint *
+create_macendpoint (struct Plugin *plugin, const struct MacAddress *addr);
+
+static void
+finish_sending (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+/**
+ * Generates a nice hexdump of a memory area.
+ *
+ * \param mem pointer to memory to dump
+ * \param length how many bytes to dump
+ */
+static void
+hexdump (const void *mem, unsigned length)
+{
+ char line[80];
+ char *src = (char *) mem;
+
+ printf ("dumping %u bytes from %p\r\n"
+ " 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF\r\n",
+ length, src);
+ unsigned i;
+ int j;
+
+ for (i = 0; i < length; i += 16, src += 16)
+ {
+ char *t = line;
+
+ t += sprintf (t, "%04x: ", i);
+ for (j = 0; j < 16; j++)
+ {
+ if (i + j < length)
+ t += sprintf (t, "%02X", src[j] & 0xff);
+ else
+ t += sprintf (t, " ");
+
+ t += sprintf (t, j % 2 ? " " : "-");
+ }
+
+ t += sprintf (t, " ");
+ for (j = 0; j < 16; j++)
+ {
+ if (i + j < length)
+ {
+ if (isprint ((unsigned char) src[j]))
+ t += sprintf (t, "%c", src[j]);
+ else
+ t += sprintf (t, ".");
+ }
+ else
+ {
+ t += sprintf (t, " ");
+ }
+ }
+
+ t += sprintf (t, "\r\n");
+ printf ("%s", line);
+ }
+}
+
+/**
+ * Function to find a MacEndpoint with a specific mac addr
+ * @param plugin pointer to the plugin struct
+ * @param addr pointer to the mac address
+ * @param create_new GNUNET_YES if a new end point should be created
+ * @return
+ */
+static struct MacEndpoint *
+get_macendpoint (struct Plugin *plugin, const struct MacAddress *addr,
+ int create_new)
+{
+ struct MacEndpoint *queue = plugin->mac_head;
+
+ while (queue != NULL)
+ {
+ //GNUNET_assert (queue->sessions_head != NULL);
+ if (memcmp (addr, &queue->addr, sizeof (struct MacAddress)) == 0)
+ return queue; /* session found */
+ queue = queue->next;
+ }
+
+ if (create_new == GNUNET_YES)
+ {
+ return create_macendpoint (plugin, addr);
+ }
+ else
+ {
+ return NULL;
+ }
+
+}
+
+/**
+ * search for a session with the macendpoint and peer id
+ *
+ * @param plugin pointer to the plugin struct
+ * @param endpoint pointer to the mac endpoint of the peer
+ * @param peer pointer to the peerid
+ * @return returns the session
+ */
+static struct Session *
+search_session (struct Plugin *plugin, const struct MacEndpoint *endpoint,
+ const struct GNUNET_PeerIdentity *peer)
+{
+ GNUNET_assert (endpoint != NULL);
+ struct Sessionqueue *queue = endpoint->sessions_head;
+
+ while (queue != NULL)
+ {
+ GNUNET_assert (queue->content != NULL);
+ if (memcmp
+ (peer, &queue->content->target,
+ sizeof (struct GNUNET_PeerIdentity)) == 0)
+ return queue->content; /* session found */
+ queue = queue->next;
+ }
+ return NULL;
+}
+
+/**
+ * Function called for a quick conversion of the binary address to
+ * a numeric address. Note that the caller must not free the
+ * address and that the next call to this function is allowed
+ * to override the address again.
+ *
+ * @param cls closure
+ * @param addr binary address
+ * @param addrlen length of the address
+ * @return string representing the same address
+ */
+static const char *
+wlan_plugin_address_to_string (void *cls, const void *addr, size_t addrlen)
+{
+ static char ret[40];
+ const struct MacAddress *mac;
+
+ if (addrlen != sizeof (struct MacAddress))
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ mac = addr;
+ GNUNET_snprintf (ret, sizeof (ret), "%s Mac-Address %X:%X:%X:%X:%X:%X",
+ PROTOCOL_PREFIX, mac->mac[0], mac->mac[1], mac->mac[2],
+ mac->mac[3], mac->mac[4], mac->mac[5]);
+
+ return ret;
+}
+
+/**
+ * Function for the scheduler if a session times out
+ * @param cls pointer to the Sessionqueue
+ * @param tc pointer to the GNUNET_SCHEDULER_TaskContext
+ */
+static void
+session_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct Sessionqueue *queue = cls;
+
+ GNUNET_assert (queue != NULL);
+ GNUNET_assert (queue->content != NULL);
+ queue->content->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
+ {
+ return;
+ }
+ if (GNUNET_TIME_absolute_get_remaining
+ (GNUNET_TIME_absolute_add
+ (queue->content->last_activity, SESSION_TIMEOUT)).rel_value == 0)
+ {
+
+ GNUNET_assert (queue->content->mac != NULL);
+ GNUNET_assert (queue->content->mac->plugin != NULL);
+ GNUNET_STATISTICS_update (queue->content->mac->plugin->env->stats,
+ _("# wlan session timeouts"), 1, GNUNET_NO);
+ free_session (queue->content->mac->plugin, queue, GNUNET_YES);
+ }
+ else
+ {
+ queue->content->timeout_task =
+ GNUNET_SCHEDULER_add_delayed (SESSION_TIMEOUT, &session_timeout, queue);
+ }
+}
+
+/**
+ * create a new session
+ *
+ * @param plugin pointer to the plugin struct
+ * @param endpoint pointer to the mac endpoint of the peer
+ * @param peer peer identity to use for this session
+ * @return returns the session
+ */
+
+static struct Session *
+create_session (struct Plugin *plugin, struct MacEndpoint *endpoint,
+ const struct GNUNET_PeerIdentity *peer)
+{
+ GNUNET_assert (endpoint != NULL);
+ GNUNET_assert (plugin != NULL);
+ GNUNET_STATISTICS_update (plugin->env->stats, _("# wlan session created"), 1,
+ GNUNET_NO);
+ struct Sessionqueue *queue =
+ GNUNET_malloc (sizeof (struct Sessionqueue) + sizeof (struct Session));
+
+ GNUNET_CONTAINER_DLL_insert_tail (endpoint->sessions_head,
+ endpoint->sessions_tail, queue);
+
+ queue->content = (struct Session *) &queue[1];
+ queue->content->mac = endpoint;
+ memcpy (&(queue->content->target), peer, sizeof (struct GNUNET_PeerIdentity));
+ queue->content->last_activity = GNUNET_TIME_absolute_get ();
+ queue->content->timeout_task =
+ GNUNET_SCHEDULER_add_delayed (SESSION_TIMEOUT, &session_timeout, queue);
+
+#if DEBUG_wlan
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "New session %p with endpoint %p: %s\n", queue->content,
+ endpoint, wlan_plugin_address_to_string (NULL,
+ endpoint->addr.mac,
+ 6));
+#endif
+
+ return queue->content;
+}
+
+/**
+ * Get session from address, create if no session exists
+ *
+ * @param plugin pointer to the plugin struct
+ * @param addr pointer to the mac address of the peer
+ * @param peer pointer to the peerid
+ * @return returns the session
+ */
+static struct Session *
+get_session (struct Plugin *plugin, const struct MacAddress *addr,
+ const struct GNUNET_PeerIdentity *peer)
+{
+ struct MacEndpoint *mac;
+
+ mac = get_macendpoint (plugin, addr, GNUNET_YES);
+ struct Session *session = search_session (plugin, mac, peer);
+
+ if (session != NULL)
+ return session;
+ return create_session (plugin, mac, peer);
+}
+
+/**
+ * Queue the session to send data
+ * checks if there is a message pending
+ * checks if this session is not allready in the queue
+ * @param plugin pointer to the plugin
+ * @param session pointer to the session to add
+ */
+static void
+queue_session (struct Plugin *plugin, struct Session *session)
+{
+ struct Sessionqueue *queue = plugin->pending_Sessions_head;
+
+ if (session->pending_message_head != NULL)
+ {
+ while (queue != NULL)
+ {
+ // content is never NULL
+ GNUNET_assert (queue->content != NULL);
+ // is session already in queue?
+ if (session == queue->content)
+ {
+ return;
+ }
+ // try next
+ queue = queue->next;
+ }
+
+ // Session is not in the queue
+
+ queue = GNUNET_malloc (sizeof (struct Sessionqueue));
+ queue->content = session;
+
+ //insert at the tail
+ GNUNET_CONTAINER_DLL_insert_tail (plugin->pending_Sessions_head,
+ plugin->pending_Sessions_tail, queue);
+ plugin->pendingsessions++;
+ GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending sessions"),
+ plugin->pendingsessions, GNUNET_NO);
+ }
+
+}
+
+/**
+ * Function to schedule the write task, executed after a delay
+ * @param cls pointer to the plugin struct
+ * @param tc GNUNET_SCHEDULER_TaskContext pointer
+ */
+static void
+delay_fragment_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct Plugin *plugin = cls;
+
+ plugin->server_write_delay_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
+
+ // GNUNET_TIME_UNIT_FOREVER_REL is needed to clean up old msg
+ if (plugin->server_write_task == GNUNET_SCHEDULER_NO_TASK)
+ {
+ plugin->server_write_task =
+ GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL,
+ plugin->server_stdin_handle,
+ &do_transmit, plugin);
+ }
+}
+
+/**
+ * Function to calculate the time of the next periodic "hello-beacon"
+ * @param plugin pointer to the plugin struct
+ */
+
+static void
+set_next_beacon_time (struct Plugin *const plugin)
+{
+ //under 10 known peers: once a second
+ if (plugin->mac_count < 10)
+ {
+ plugin->beacon_time =
+ GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
+ GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_SECONDS,
+ HELLO_BEACON_SCALING_FACTOR));
+ }
+ //under 30 known peers: every 10 seconds
+ else if (plugin->mac_count < 30)
+ {
+ plugin->beacon_time =
+ GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
+ GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_SECONDS,
+ 10 * HELLO_BEACON_SCALING_FACTOR));
+ }
+ //over 30 known peers: once a minute
+ else
+ {
+ plugin->beacon_time =
+ GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
+ GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_MINUTES,
+ HELLO_BEACON_SCALING_FACTOR));
+ }
+}
+
+/**
+ * Function to set the timer for the next timeout of the fragment queue
+ * @param plugin the handle to the plugin struct
+ */
+
+static void
+set_next_send (struct Plugin *const plugin)
+{
+ struct GNUNET_TIME_Relative next_send;
+
+ //cancel old task
+ if (plugin->server_write_delay_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (plugin->server_write_delay_task);
+ plugin->server_write_delay_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ //check if some acks are in the queue
+ if (plugin->ack_send_queue_head != NULL)
+ {
+ next_send = GNUNET_TIME_UNIT_ZERO;
+ }
+
+ //check if there are some fragments in the queue
+ else if (plugin->sending_messages_head != NULL)
+ {
+ next_send = GNUNET_TIME_UNIT_ZERO;
+ }
+ else
+ {
+ next_send = GNUNET_TIME_absolute_get_remaining (plugin->beacon_time);
+ }
+
+#if DEBUG_wlan
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Next packet is send in: %u\n", next_send.rel_value);
+#endif
+
+ if (next_send.rel_value == GNUNET_TIME_UNIT_ZERO.rel_value)
+ {
+ if (plugin->server_write_task == GNUNET_SCHEDULER_NO_TASK)
+ {
+ plugin->server_write_task =
+ GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL,
+ plugin->server_stdin_handle,
+ &do_transmit, plugin);
+ }
+ }
+ else
+ {
+ if (plugin->server_write_delay_task == GNUNET_SCHEDULER_NO_TASK)
+ {
+ plugin->server_write_delay_task =
+ GNUNET_SCHEDULER_add_delayed (next_send, &delay_fragment_task,
+ plugin);
+ }
+ }
+}
+
+/**
+ * Function to get the next queued Session, removes the session from the queue
+ * @param plugin pointer to the plugin struct
+ * @return pointer to the session found, returns NULL if there is now session in the queue
+ */
+static struct Session *
+get_next_queue_session (struct Plugin *plugin)
+{
+ struct Session *session;
+ struct Sessionqueue *sessionqueue;
+ struct Sessionqueue *sessionqueue_alt;
+ struct PendingMessage *pm;
+
+ sessionqueue = plugin->pending_Sessions_head;
+
+ while (sessionqueue != NULL)
+ {
+ session = sessionqueue->content;
+
+ GNUNET_assert (session != NULL);
+ pm = session->pending_message_head;
+
+ if (pm == NULL)
+ {
+#if DEBUG_wlan
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME,
+ "pending message is empty, should not happen. session %p\n",
+ session);
+#endif
+ sessionqueue_alt = sessionqueue;
+ sessionqueue = sessionqueue->next;
+ plugin->pendingsessions--;
+ GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending sessions"),
+ plugin->pendingsessions, GNUNET_NO);
+ GNUNET_CONTAINER_DLL_remove (plugin->pending_Sessions_head,
+ plugin->pending_Sessions_tail,
+ sessionqueue_alt);
+
+ GNUNET_free (sessionqueue_alt);
+ continue;
+
+ }
+
+ //check for message timeout
+ if (GNUNET_TIME_absolute_get_remaining (pm->timeout).rel_value > 0)
+ {
+ //check if session has no message in the fragment queue
+ if ((session->mac->fragment_messages_out_count <
+ FRAGMENT_QUEUE_MESSAGES_OUT_PER_MACENDPOINT) &&
+ (session->fragment_messages_out_count <
+ FRAGMENT_QUEUE_MESSAGES_OUT_PER_SESSION))
+ {
+ plugin->pendingsessions--;
+ GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending sessions"),
+ plugin->pendingsessions, GNUNET_NO);
+ GNUNET_CONTAINER_DLL_remove (plugin->pending_Sessions_head,
+ plugin->pending_Sessions_tail,
+ sessionqueue);
+ GNUNET_free (sessionqueue);
+
+ return session;
+ }
+ else
+ {
+ sessionqueue = sessionqueue->next;
+ }
+ }
+ else
+ {
+ GNUNET_CONTAINER_DLL_remove (session->pending_message_head,
+ session->pending_message_tail, pm);
+
+ //call the cont func that it did not work
+ if (pm->transmit_cont != NULL)
+ pm->transmit_cont (pm->transmit_cont_cls, &(session->target),
+ GNUNET_SYSERR);
+ GNUNET_free (pm->msg);
+ GNUNET_free (pm);
+
+ if (session->pending_message_head == NULL)
+ {
+ sessionqueue_alt = sessionqueue;
+ sessionqueue = sessionqueue->next;
+ plugin->pendingsessions--;
+ GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending sessions"),
+ plugin->pendingsessions, GNUNET_NO);
+ GNUNET_CONTAINER_DLL_remove (plugin->pending_Sessions_head,
+ plugin->pending_Sessions_tail,
+ sessionqueue_alt);
+
+ GNUNET_free (sessionqueue_alt);
+ }
+ }
+
+ }
+ return NULL;
+}
+
+/**
+ * frees the space of a message in the fragment queue (send queue)
+ * @param plugin the plugin struct
+ * @param fm message to free
+ */
+static void
+free_fragment_message (struct Plugin *plugin, struct FragmentMessage *fm)
+{
+ struct Session *session = fm->session;
+ struct MacEndpoint *endpoint = session->mac;
+ struct FragmentMessage_queue *fmq;
+ struct FragmentMessage_queue *fmq_next;
+
+ fmq = plugin->sending_messages_head;
+ while (fmq != NULL)
+ {
+ fmq_next = fmq->next;
+ if (fmq->content == fm)
+ {
+ GNUNET_CONTAINER_DLL_remove (plugin->sending_messages_head,
+ plugin->sending_messages_tail, fmq);
+ GNUNET_free (fmq);
+ }
+ fmq = fmq_next;
+ }
+
+ (session->mac->fragment_messages_out_count)--;
+ session->fragment_messages_out_count--;
+ plugin->pending_Fragment_Messages--;
+ GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending fragments"),
+ plugin->pending_Fragment_Messages, GNUNET_NO);
+ GNUNET_CONTAINER_DLL_remove (endpoint->sending_messages_head,
+ endpoint->sending_messages_tail, fm);
+ GNUNET_FRAGMENT_context_destroy (fm->fragcontext);
+ if (fm->timeout_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (fm->timeout_task);
+ fm->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ GNUNET_free (fm);
+
+ queue_session (plugin, session);
+#if DEBUG_wlan
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Free pending fragment messages %p, session %p\n", fm,
+ session);
+#endif
+}
+
+/**
+ * function to fill the radiotap header
+ * @param plugin pointer to the plugin struct
+ * @param endpoint pointer to the endpoint
+ * @param header pointer to the radiotap header
+ * @return GNUNET_YES at success
+ */
+static int
+getRadiotapHeader (struct Plugin *plugin, struct MacEndpoint *endpoint,
+ struct Radiotap_Send *header)
+{
+
+ if (endpoint != NULL)
+ {
+ header->rate = endpoint->rate;
+ header->tx_power = endpoint->tx_power;
+ header->antenna = endpoint->antenna;
+ }
+ else
+ {
+ header->rate = 255;
+ header->tx_power = 0;
+ header->antenna = 0;
+ }
+
+ return GNUNET_YES;
+}
+
+/**
+ * function to generate the wlan hardware header for one packet
+ * @param Header address to write the header to
+ * @param to_mac_addr address of the recipient
+ * @param plugin pointer to the plugin struct
+ * @param size size of the whole packet, needed to calculate the time to send the packet
+ * @return GNUNET_YES if there was no error
+ */
+static int
+getWlanHeader (struct ieee80211_frame *Header,
+ const struct MacAddress *to_mac_addr, struct Plugin *plugin,
+ unsigned int size)
+{
+ uint16_t *tmp16;
+ const int rate = 11000000;
+
+ Header->i_fc[0] = IEEE80211_FC0_TYPE_DATA;
+ Header->i_fc[1] = 0x00;
+ memcpy (&Header->i_addr3, &mac_bssid, sizeof (mac_bssid));
+ memcpy (&Header->i_addr2, plugin->mac_address.mac,
+ sizeof (plugin->mac_address));
+ memcpy (&Header->i_addr1, to_mac_addr, sizeof (struct MacAddress));
+
+ tmp16 = (uint16_t *) Header->i_dur;
+ *tmp16 = (uint16_t) htole16 ((size * 1000000) / rate + 290);
+ Header->llc[0] = WLAN_LLC_DSAP_FIELD;
+ Header->llc[1] = WLAN_LLC_SSAP_FIELD;
+
+#if DEBUG_wlan_ip_udp_packets_on_air > 1
+ uint crc = 0;
+ uint16_t *x;
+ int count;
+
+ Header->ip.ip_dst.s_addr = *((uint32_t *) & to_mac_addr->mac[2]);
+ Header->ip.ip_src.s_addr = *((uint32_t *) & plugin->mac_address.mac[2]);
+ Header->ip.ip_v = 4;
+ Header->ip.ip_hl = 5;
+ Header->ip.ip_p = 17;
+ Header->ip.ip_ttl = 1;
+ Header->ip.ip_len = htons (size + 8);
+ Header->ip.ip_sum = 0;
+ x = (uint16_t *) & Header->ip;
+ count = sizeof (struct iph);
+ while (count > 1)
+ {
+ /* This is the inner loop */
+ crc += (unsigned short) *x++;
+ count -= 2;
+ }
+ /* Add left-over byte, if any */
+ if (count > 0)
+ crc += *(unsigned char *) x;
+ crc = (crc & 0xffff) + (crc >> 16);
+ Header->ip.ip_sum = htons (~(unsigned short) crc);
+ Header->udp.len = htons (size - sizeof (struct ieee80211_frame));
+
+#endif
+
+ return GNUNET_YES;
+}
+
+/**
+ * 32bit CRC
+ *
+ * @param msgbuf pointer tor the data
+ * @param msgbuf_size size of the data
+ *
+ * @return 32bit crc value
+ */
+
+uint32_t
+getcrc32 (const char *msgbuf, size_t msgbuf_size)
+{
+
+ return GNUNET_CRYPTO_crc32_n (msgbuf, msgbuf_size);;
+}
+
+/**
+ * 16bit CRC
+ *
+ * @param msgbuf pointer tor the data
+ * @param msgbuf_size size of the data
+ *
+ * @return 16bit crc value
+ */
+
+uint16_t
+getcrc16 (const char *msgbuf, size_t msgbuf_size)
+{
+ //TODO calc some crc
+ return 0;
+}
+
+/**
+ * function to add a fragment of a message to send
+ * @param cls FragmentMessage this message belongs to
+ * @param hdr pointer to the start of the message
+ */
+
+void
+add_message_for_send (void *cls, const struct GNUNET_MessageHeader *hdr)
+{
+
+ struct FragmentMessage *fm = cls;
+ struct FragmentMessage_queue *fmqueue;
+
+ GNUNET_assert (cls != NULL);
+ GNUNET_assert (fm->frag == NULL);
+ struct MacEndpoint *endpoint = fm->session->mac;
+ struct Plugin *plugin = endpoint->plugin;
+ struct GNUNET_MessageHeader *msgheader;
+ struct GNUNET_MessageHeader *msgheader2;
+ uint16_t size;
+
+#if DEBUG_wlan_retransmission > 1
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Adding fragment of message %p to send, session %p, endpoint %p, type %u\n",
+ fm, fm->session, endpoint, hdr->type);
+#endif
+
+ size =
+ sizeof (struct GNUNET_MessageHeader) + sizeof (struct Radiotap_Send) +
+ sizeof (struct ieee80211_frame) + ntohs (hdr->size);
+ fm->frag = GNUNET_malloc (size);
+ fm->size = size;
+
+ msgheader = (struct GNUNET_MessageHeader *) fm->frag;
+ msgheader->size = htons (size);
+ msgheader->type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA);
+
+ fm->radioHeader = (struct Radiotap_Send *) &msgheader[1];
+ fm->ieeewlanheader = (struct ieee80211_frame *) &fm->radioHeader[1];
+ msgheader2 = (struct GNUNET_MessageHeader *) &fm->ieeewlanheader[1];
+ memcpy (msgheader2, hdr, ntohs (hdr->size));
+
+ fmqueue = GNUNET_malloc (sizeof (struct FragmentMessage_queue));
+ fmqueue->content = fm;
+
+ GNUNET_CONTAINER_DLL_insert_tail (plugin->sending_messages_head,
+ plugin->sending_messages_tail, fmqueue);
+ set_next_send (plugin);
+}
+
+
+/**
+ * We have been notified that wlan-helper has written something to stdout.
+ * Handle the output, then reschedule this function to be called again once
+ * more is available.
+ *
+ * @param cls the plugin handle
+ * @param tc the scheduling context
+ */
+static void
+wlan_plugin_helper_read (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct Plugin *plugin = cls;
+
+ plugin->server_read_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
+
+ char mybuf[WLAN_MTU + sizeof (struct GNUNET_MessageHeader)];
+ ssize_t bytes;
+
+ bytes =
+ GNUNET_DISK_file_read (plugin->server_stdout_handle, mybuf,
+ sizeof (mybuf));
+ if (bytes <= 0)
+ {
+#if DEBUG_wlan
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ _
+ ("Finished reading from wlan-helper stdout with code: %d\n"),
+ bytes);
+#endif
+ return;
+ }
+ GNUNET_SERVER_mst_receive (plugin->suid_tokenizer, NULL, mybuf, bytes,
+ GNUNET_NO, GNUNET_NO);
+
+ GNUNET_assert (plugin->server_read_task == GNUNET_SCHEDULER_NO_TASK);
+ plugin->server_read_task =
+ GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
+ plugin->server_stdout_handle,
+ &wlan_plugin_helper_read, plugin);
+}
+
+/**
+ * Start the gnunet-wlan-helper process.
+ *
+ * @param plugin the transport plugin
+ * @return GNUNET_YES if process was started, GNUNET_SYSERR on error
+ */
+static int
+wlan_transport_start_wlan_helper (struct Plugin *plugin)
+{
+ const char *filenamehw = "gnunet-transport-wlan-helper";
+ char *filenameloopback = "gnunet-transport-wlan-helper-dummy";
+ char *absolute_filename = NULL;
+
+ plugin->server_stdout = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_NO, GNUNET_YES);
+ if (plugin->server_stdout == NULL)
+ return GNUNET_SYSERR;
+
+ plugin->server_stdin = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO);
+ if (plugin->server_stdin == NULL)
+ return GNUNET_SYSERR;
+
+ if ((plugin->testmode == 1) || (plugin->testmode == 2))
+ {
+ if (GNUNET_OS_check_helper_binary (filenameloopback) == GNUNET_YES)
+ {
+ absolute_filename = strdup (filenameloopback);
+ }
+ else
+ {
+ char cwd[FILENAME_MAX];
+
+ GNUNET_assert (getcwd (cwd, sizeof (cwd)) != NULL);
+
+ GNUNET_asprintf (&absolute_filename, "%s%s%s", cwd, DIR_SEPARATOR_STR,
+ filenameloopback);
+
+ if (GNUNET_DISK_file_test (filenameloopback) != GNUNET_YES)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME,
+ "Helper `%s' not found! %i\n", absolute_filename);
+ GNUNET_break (0);
+ }
+ }
+ }
+
+ /* Start the server process */
+
+ if (plugin->testmode == 0)
+ {
+
+#if DEBUG_wlan
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Starting gnunet-wlan-helper process cmd: %s %s %i\n",
+ filenamehw, plugin->interface, plugin->testmode);
+#endif
+
+ if (GNUNET_OS_check_helper_binary (filenamehw) == GNUNET_YES)
+ {
+ plugin->server_proc =
+ GNUNET_OS_start_process (plugin->server_stdin, plugin->server_stdout,
+ filenamehw, filenamehw, plugin->interface,
+ NULL);
+ }
+ else if (GNUNET_OS_check_helper_binary (filenamehw) == GNUNET_NO)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME,
+ "gnunet-transport-wlan-helper is not suid, please change it or look at the doku\n");
+ GNUNET_break (0);
+ }
+ else
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME,
+ "gnunet-transport-wlan-helper not found, please look if it exists and is the $PATH variable!\n");
+ GNUNET_break (0);
+ }
+
+ }
+ else if (plugin->testmode == 1)
+ {
+
+#if DEBUG_wlan
+ GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, PLUGIN_LOG_NAME,
+ "Starting gnunet-wlan-helper loopback 1 process cmd: %s %s %i\n",
+ absolute_filename, plugin->interface, plugin->testmode);
+#endif
+ plugin->server_proc =
+ GNUNET_OS_start_process (plugin->server_stdin, plugin->server_stdout,
+ absolute_filename, absolute_filename, "1",
+ NULL);
+ if (plugin->server_proc == NULL)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME,
+ "`%s' not found, please look if it exists and is in the $PATH variable!\n",
+ absolute_filename);
+ GNUNET_break (0);
+ }
+ }
+ else if (plugin->testmode == 2)
+ {
+#if DEBUG_wlan
+ GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, PLUGIN_LOG_NAME,
+ "Starting gnunet-wlan-helper loopback 2 process cmd: %s %s %i\n",
+ absolute_filename, plugin->interface, plugin->testmode);
+#endif
+
+ plugin->server_proc =
+ GNUNET_OS_start_process (plugin->server_stdin, plugin->server_stdout,
+ absolute_filename, absolute_filename, "2",
+ NULL);
+ if (plugin->server_proc == NULL)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME,
+ "`%s' not found, please look if it exists and is in the $PATH variable!\n",
+ absolute_filename);
+ GNUNET_break (0);
+ }
+ }
+ if (absolute_filename != NULL)
+ GNUNET_free (absolute_filename);
+ if (plugin->server_proc == NULL)
+ {
+#if DEBUG_wlan
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Failed to start gnunet-wlan-helper process\n");
+#endif
+ return GNUNET_SYSERR;
+ }
+
+
+
+ /* Close the write end of the read pipe */
+ GNUNET_DISK_pipe_close_end (plugin->server_stdout,
+ GNUNET_DISK_PIPE_END_WRITE);
+
+ /* Close the read end of the write pipe */
+ GNUNET_DISK_pipe_close_end (plugin->server_stdin, GNUNET_DISK_PIPE_END_READ);
+
+ plugin->server_stdout_handle =
+ GNUNET_DISK_pipe_handle (plugin->server_stdout,
+ GNUNET_DISK_PIPE_END_READ);
+ plugin->server_stdin_handle =
+ GNUNET_DISK_pipe_handle (plugin->server_stdin,
+ GNUNET_DISK_PIPE_END_WRITE);
+
+ GNUNET_assert (plugin->server_read_task == GNUNET_SCHEDULER_NO_TASK);
+
+#if DEBUG_wlan
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Adding server_read_task for the wlan-helper\n");
+#endif
+
+ plugin->server_read_task =
+ GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
+ plugin->server_stdout_handle,
+ &wlan_plugin_helper_read, plugin);
+
+ return GNUNET_YES;
+}
+
+/**
+ * Stops the gnunet-wlan-helper process.
+ *
+ * @param plugin the transport plugin
+ * @return GNUNET_YES if process was started, GNUNET_SYSERR on error
+ */
+static int
+wlan_transport_stop_wlan_helper (struct Plugin *plugin)
+{
+#if DEBUG_wlan
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Stoping WLAN helper process\n");
+#endif
+
+ if (plugin->server_write_delay_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (plugin->server_write_delay_task);
+ plugin->server_write_delay_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ if (plugin->server_write_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (plugin->server_write_task);
+ plugin->server_write_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ if (plugin->server_read_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (plugin->server_read_task);
+ plugin->server_read_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ GNUNET_DISK_pipe_close (plugin->server_stdout);
+ GNUNET_DISK_pipe_close (plugin->server_stdin);
+ GNUNET_OS_process_kill (plugin->server_proc, SIGKILL);
+ GNUNET_OS_process_wait (plugin->server_proc);
+ GNUNET_OS_process_close (plugin->server_proc);
+
+ return GNUNET_YES;
+}
+
+/**
+ * function for delayed restart of the helper process
+ * @param cls Finish_send struct if message should be finished
+ * @param tc TaskContext
+ */
+static void
+delay_restart_helper (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct Finish_send *finish = cls;
+ struct Plugin *plugin;
+
+ plugin = finish->plugin;
+
+ plugin->server_write_task = GNUNET_SCHEDULER_NO_TASK;
+ if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
+ {
+ GNUNET_free_non_null (finish->msgstart);
+ GNUNET_free (finish);
+ return;
+ }
+
+ wlan_transport_start_wlan_helper (plugin);
+
+ if (finish->size != 0)
+ {
+ plugin->server_write_task =
+ GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL,
+ plugin->server_stdin_handle,
+ &finish_sending, finish);
+ }
+ else
+ {
+ set_next_send (plugin);
+ GNUNET_free_non_null (finish->msgstart);
+ GNUNET_free (finish);
+ }
+
+}
+
+/**
+ * Function to restart the helper
+ * @param plugin pointer to the global plugin struct
+ * @param finish pointer to the Finish_send struct to finish
+ */
+static void
+restart_helper (struct Plugin *plugin, struct Finish_send *finish)
+{
+ static struct GNUNET_TIME_Relative next_try = { 1000 };
+ GNUNET_assert (finish != NULL);
+
+ wlan_transport_stop_wlan_helper (plugin);
+ plugin->server_write_task =
+ GNUNET_SCHEDULER_add_delayed (next_try, &delay_restart_helper, finish);
+ GNUNET_TIME_relative_multiply (next_try, HELPER_RESTART_SCALING_FACTOR);
+
+}
+
+/**
+ * function to finish a sending if not all could have been writen befor
+ * @param cls pointer to the Finish_send struct
+ * @param tc TaskContext
+ */
+static void
+finish_sending (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct Finish_send *finish = cls;
+ struct Plugin *plugin;
+ ssize_t bytes;
+
+ plugin = finish->plugin;
+ plugin->server_write_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
+ {
+ GNUNET_free (finish->msgstart);
+ GNUNET_free (finish);
+ return;
+ }
+ bytes =
+ GNUNET_DISK_file_write (plugin->server_stdin_handle,
+ finish->head_of_next_write, finish->size);
+
+ if (bytes != finish->size)
+ {
+ if (bytes != GNUNET_SYSERR)
+ {
+ finish->head_of_next_write += bytes;
+ finish->size -= bytes;
+ plugin->server_write_task =
+ GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL,
+ plugin->server_stdin_handle,
+ &finish_sending, finish);
+ }
+ else
+ {
+ restart_helper (plugin, finish);
+ }
+ }
+ else
+ {
+ GNUNET_free (finish->msgstart);
+ GNUNET_free (finish);
+ set_next_send (plugin);
+ }
+}
+
+/**
+ * function to send a hello beacon
+ * @param plugin pointer to the plugin struct
+ */
+static void
+send_hello_beacon (struct Plugin *plugin)
+{
+
+#if DEBUG_wlan
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Sending hello beacon\n");
+#endif
+
+ uint16_t size;
+ ssize_t bytes;
+ uint16_t hello_size;
+ struct GNUNET_MessageHeader *msgheader;
+ struct ieee80211_frame *ieeewlanheader;
+ struct Radiotap_Send *radioHeader;
+ struct GNUNET_MessageHeader *msgheader2;
+ const struct GNUNET_MessageHeader *hello;
+ struct Finish_send *finish;
+
+ GNUNET_assert (plugin != NULL);
+
+ GNUNET_STATISTICS_update (plugin->env->stats, _("# wlan hello beacons send"),
+ 1, GNUNET_NO);
+
+ hello = plugin->env->get_our_hello ();
+ hello_size = GNUNET_HELLO_size ((struct GNUNET_HELLO_Message *) hello);
+ GNUNET_assert (sizeof (struct WlanHeader) + hello_size <= WLAN_MTU);
+ size =
+ sizeof (struct GNUNET_MessageHeader) + sizeof (struct Radiotap_Send) +
+ sizeof (struct ieee80211_frame) + hello_size;
+
+ msgheader = GNUNET_malloc (size);
+ msgheader->size = htons (size);
+ msgheader->type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA);
+
+ radioHeader = (struct Radiotap_Send *) &msgheader[1];
+ getRadiotapHeader (plugin, NULL, radioHeader);
+ ieeewlanheader = (struct ieee80211_frame *) &radioHeader[1];
+ getWlanHeader (ieeewlanheader, &bc_all_mac, plugin, size);
+
+ msgheader2 = (struct GNUNET_MessageHeader *) &ieeewlanheader[1];
+ /*msgheader2->size =
+ * htons (GNUNET_HELLO_size ((struct GNUNET_HELLO_Message *) hello) +
+ * sizeof (struct GNUNET_MessageHeader));
+ *
+ * msgheader2->type = htons (GNUNET_MESSAGE_TYPE_WLAN_ADVERTISEMENT); */
+ memcpy (msgheader2, hello, hello_size);
+
+ bytes = GNUNET_DISK_file_write (plugin->server_stdin_handle, msgheader, size);
+
+ if (bytes == GNUNET_SYSERR)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME,
+ _
+ ("Error writing to wlan healper. errno == %d, ERROR: %s\n"),
+ errno, strerror (errno));
+ finish = GNUNET_malloc (sizeof (struct Finish_send));
+ finish->plugin = plugin;
+ finish->head_of_next_write = NULL;
+ finish->size = 0;
+ finish->msgstart = NULL;
+ restart_helper (plugin, finish);
+
+ set_next_beacon_time (plugin);
+
+ }
+ else
+ {
+ GNUNET_assert (bytes == size);
+ set_next_beacon_time (plugin);
+ set_next_send (plugin);
+ }
+ GNUNET_free (msgheader);
+
+
+}
+
+/**
+ * function to add an ack to send it for a received fragment
+ * @param cls MacEndpoint this ack belongs to
+ * @param msg_id id of the message
+ * @param hdr pointer to the hdr where the ack is stored
+ *
+ */
+
+static void
+add_ack_for_send (void *cls, uint32_t msg_id,
+ const struct GNUNET_MessageHeader *hdr)
+{
+
+ struct AckSendQueue *ack;
+
+ GNUNET_assert (cls != NULL);
+ struct MacEndpoint *endpoint = cls;
+ struct Plugin *plugin = endpoint->plugin;
+ struct GNUNET_MessageHeader *msgheader;
+ struct GNUNET_MessageHeader *msgheader2;
+ uint16_t size;
+
+ size =
+ sizeof (struct GNUNET_MessageHeader) + sizeof (struct Radiotap_Send) +
+ sizeof (struct ieee80211_frame) + ntohs (hdr->size) +
+ sizeof (struct AckSendQueue);
+
+ ack = GNUNET_malloc (size);
+ ack->message_id = msg_id;
+ ack->endpoint = endpoint;
+
+ size =
+ sizeof (struct GNUNET_MessageHeader) + sizeof (struct Radiotap_Send) +
+ sizeof (struct ieee80211_frame) + ntohs (hdr->size);
+
+ msgheader = (struct GNUNET_MessageHeader *) &ack[1];
+ ack->hdr = (struct GNUNET_MessageHeader *) &ack[1];
+ msgheader->size = htons (size);
+ msgheader->type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA);
+
+ ack->radioHeader = (struct Radiotap_Send *) &msgheader[1];
+ ack->ieeewlanheader = (struct ieee80211_frame *) &(ack->radioHeader)[1];
+ msgheader2 = (struct GNUNET_MessageHeader *) &(ack->ieeewlanheader)[1];
+ memcpy (msgheader2, hdr, ntohs (hdr->size));
+
+ GNUNET_CONTAINER_DLL_insert_tail (plugin->ack_send_queue_head,
+ plugin->ack_send_queue_tail, ack);
+
+#if DEBUG_wlan_retransmission > 1
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Adding ack with message id %u to send, AckSendQueue %p, endpoint %p\n",
+ msg_id, ack, endpoint);
+#endif
+
+ set_next_send (plugin);
+}
+
+/**
+ * Function for the scheduler if a FragmentMessage times out
+ * @param cls pointer to the FragmentMessage
+ * @param tc pointer to the GNUNET_SCHEDULER_TaskContext
+ */
+static void
+fragmentmessage_timeout (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct FragmentMessage *fm = cls;
+
+ GNUNET_assert (fm != NULL);
+ fm->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
+ {
+ return;
+ }
+ free_fragment_message (fm->session->mac->plugin, fm);
+}
+
+/**
+ * Function to check if there is some space in the fragment queue
+ * inserts a message if space is available
+ * @param plugin the plugin struct
+ */
+
+static void
+check_fragment_queue (struct Plugin *plugin)
+{
+ struct Session *session;
+ struct FragmentMessage *fm;
+ struct GNUNET_PeerIdentity pid;
+
+ struct PendingMessage *pm;
+
+ if (plugin->pending_Fragment_Messages < FRAGMENT_QUEUE_SIZE)
+ {
+ session = get_next_queue_session (plugin);
+ if (session != NULL)
+ {
+ pm = session->pending_message_head;
+ GNUNET_assert (pm != NULL);
+ GNUNET_CONTAINER_DLL_remove (session->pending_message_head,
+ session->pending_message_tail, pm);
+ session->mac->fragment_messages_out_count++;
+ session->fragment_messages_out_count++;
+ plugin->pending_Fragment_Messages++;
+ GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending fragments"),
+ plugin->pending_Fragment_Messages, GNUNET_NO);
+
+ fm = GNUNET_malloc (sizeof (struct FragmentMessage));
+ fm->session = session;
+ fm->timeout.abs_value = pm->timeout.abs_value;
+ fm->frag = NULL;
+ fm->fragcontext =
+ GNUNET_FRAGMENT_context_create (plugin->env->stats, WLAN_MTU,
+ &plugin->tracker,
+ GNUNET_TIME_UNIT_SECONDS,
+ &(pm->msg->header),
+ &add_message_for_send, fm);
+ fm->timeout_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
+ (fm->timeout), fragmentmessage_timeout,
+ fm);
+ GNUNET_CONTAINER_DLL_insert_tail (session->mac->sending_messages_head,
+ session->mac->sending_messages_tail,
+ fm);
+
+ if (pm->transmit_cont != NULL)
+ {
+ pid = session->target;
+ pm->transmit_cont (pm->transmit_cont_cls, &pid, GNUNET_OK);
+#if DEBUG_wlan
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "called pm->transmit_cont for %p\n", session);
+#endif
+ }
+ else
+ {
+#if DEBUG_wlan
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "no pm->transmit_cont for %p\n", session);
+#endif
+ }
+ GNUNET_free (pm);
+
+ if (session->pending_message_head != NULL)
+ {
+ //requeue session
+ queue_session (plugin, session);
+ }
+
+ }
+ }
+
+ //check if timeout changed
+ set_next_send (plugin);
+}
+
+/**
+ * Function to send an ack, does not free the ack
+ * @param plugin pointer to the plugin
+ */
+static void
+send_ack (struct Plugin *plugin)
+{
+
+ ssize_t bytes;
+ struct AckSendQueue *ack;
+ struct Finish_send *finish;
+
+ ack = plugin->ack_send_queue_head;
+
+
+#if DEBUG_wlan
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Sending ack for message_id %u for mac endpoint %p, size %u\n",
+ ack->message_id, ack->endpoint,
+ ntohs (ack->hdr->size) - sizeof (struct Radiotap_Send));
+#endif
+
+ GNUNET_assert (plugin != NULL);
+ GNUNET_STATISTICS_update (plugin->env->stats, _("# wlan acks send"), 1,
+ GNUNET_NO);
+
+ getRadiotapHeader (plugin, ack->endpoint, ack->radioHeader);
+ getWlanHeader (ack->ieeewlanheader, &ack->endpoint->addr, plugin,
+ ntohs (ack->hdr->size));
+
+ bytes =
+ GNUNET_DISK_file_write (plugin->server_stdin_handle, ack->hdr,
+ ntohs (ack->hdr->size));
+ if (bytes == GNUNET_SYSERR)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME,
+ _
+ ("Error writing to wlan healper. errno == %d, ERROR: %s\n"),
+ errno, strerror (errno));
+ finish = GNUNET_malloc (sizeof (struct Finish_send));
+ finish->plugin = plugin;
+ finish->head_of_next_write = NULL;
+ finish->size = 0;
+ finish->msgstart = NULL;
+ restart_helper (plugin, finish);
+ }
+ else
+ {
+ GNUNET_assert (bytes == ntohs (ack->hdr->size));
+ GNUNET_CONTAINER_DLL_remove (plugin->ack_send_queue_head,
+ plugin->ack_send_queue_tail, ack);
+ GNUNET_free (ack);
+ set_next_send (plugin);
+ }
+}
+
+/**
+ * Function called when wlan helper is ready to get some data
+ *
+ * @param cls closure
+ * @param tc GNUNET_SCHEDULER_TaskContext
+ */
+static void
+do_transmit (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct Plugin *plugin = cls;
+
+ GNUNET_assert (plugin != NULL);
+
+ plugin->server_write_task = GNUNET_SCHEDULER_NO_TASK;
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
+
+ struct Session *session;
+ struct FragmentMessage *fm;
+ struct Finish_send *finish;
+ struct FragmentMessage_queue *fmq;
+ ssize_t bytes;
+
+ if (plugin->ack_send_queue_head != NULL)
+ {
+ send_ack (plugin);
+ return;
+ }
+
+ //test if a "hello-beacon" has to be send
+ if (GNUNET_TIME_absolute_get_remaining (plugin->beacon_time).rel_value == 0)
+ {
+ send_hello_beacon (plugin);
+ return;
+ }
+
+ if (plugin->sending_messages_head != NULL)
+ {
+ GNUNET_STATISTICS_update (plugin->env->stats, _("# wlan fragments send"), 1,
+ GNUNET_NO);
+
+ fmq = plugin->sending_messages_head;
+ fm = fmq->content;
+ GNUNET_CONTAINER_DLL_remove (plugin->sending_messages_head,
+ plugin->sending_messages_tail, fmq);
+ GNUNET_free (fmq);
+
+ session = fm->session;
+ GNUNET_assert (session != NULL);
+
+#if DEBUG_wlan
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Sending GNUNET_MESSAGE_TYPE_WLAN_FRAGMENT for fragment message %p, size: %u\n",
+ fm, fm->size);
+#endif
+
+ getRadiotapHeader (plugin, session->mac, fm->radioHeader);
+ getWlanHeader (fm->ieeewlanheader, &(fm->session->mac->addr), plugin,
+ fm->size);
+
+ bytes =
+ GNUNET_DISK_file_write (plugin->server_stdin_handle, fm->frag,
+ fm->size);
+
+
+ if (bytes != fm->size)
+ {
+ finish = GNUNET_malloc (sizeof (struct Finish_send));
+ finish->plugin = plugin;
+ finish->msgstart = (struct GNUNET_MessageHeader *) fm->frag;
+ GNUNET_assert (plugin->server_write_task == GNUNET_SCHEDULER_NO_TASK);
+
+ if (bytes == GNUNET_SYSERR)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME,
+ _
+ ("Error writing to wlan healper. errno == %d, ERROR: %s\n"),
+ errno, strerror (errno));
+
+ finish->head_of_next_write = fm->frag;
+ finish->size = fm->size;
+ restart_helper (plugin, finish);
+ }
+ else
+ {
+ finish->head_of_next_write = fm->frag + bytes;
+ finish->size = fm->size - bytes;
+ plugin->server_write_task =
+ GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL,
+ plugin->server_stdin_handle,
+ &finish_sending, finish);
+ }
+
+ fm->frag = NULL;
+ }
+ else
+ {
+ GNUNET_free (fm->frag);
+ fm->frag = NULL;
+ set_next_send (plugin);
+ }
+ GNUNET_FRAGMENT_context_transmission_done (fm->fragcontext);
+ return;
+ }
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, PLUGIN_LOG_NAME,
+ "do_transmit did nothing, should not happen!\n");
+}
+
+/**
+ * Another peer has suggested an address for this
+ * peer and transport plugin. Check that this could be a valid
+ * address. If so, consider adding it to the list
+ * of addresses.
+ *
+ * @param cls closure
+ * @param addr pointer to the address
+ * @param addrlen length of addr
+ * @return GNUNET_OK if this is a plausible address for this peer
+ * and transport
+ */
+static int
+wlan_plugin_address_suggested (void *cls, const void *addr, size_t addrlen)
+{
+ //struct Plugin *plugin = cls;
+
+ /* check if the address is plausible; if so,
+ * add it to our list! */
+
+ GNUNET_assert (cls != NULL);
+ //FIXME mitm is not checked
+ //Mac Address has 6 bytes
+ if (addrlen == 6)
+ {
+ /* TODO check for bad addresses like multicast, broadcast, etc */
+#if DEBUG_wlan
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "wlan_plugin_address_suggested got good address, size %u!\n",
+ addrlen);
+#endif
+ return GNUNET_OK;
+ }
+#if DEBUG_wlan
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "wlan_plugin_address_suggested got bad address, size %u!\n",
+ addrlen);
+#endif
+ return GNUNET_SYSERR;
+}
+
+/**
+ * Function that can be used by the transport service to transmit
+ * a message using the plugin.
+ *
+ * @param cls closure
+ * @param target who should receive this message
+ * @param priority how important is the message
+ * @param msgbuf the message to transmit
+ * @param msgbuf_size number of bytes in 'msgbuf'
+ * @param timeout when should we time out
+ * @param session which session must be used (or NULL for "any")
+ * @param addr the address to use (can be NULL if the plugin
+ * is "on its own" (i.e. re-use existing TCP connection))
+ * @param addrlen length of the address in bytes
+ * @param force_address GNUNET_YES if the plugin MUST use the given address,
+ * otherwise the plugin may use other addresses or
+ * existing connections (if available)
+ * @param cont continuation to call once the message has
+ * been transmitted (or if the transport is ready
+ * for the next transmission call; or if the
+ * peer disconnected...)
+ * @param cont_cls closure for cont
+ * @return number of bytes used (on the physical network, with overheads);
+ * -1 on hard errors (i.e. address invalid); 0 is a legal value
+ * and does NOT mean that the message was not transmitted (DV)
+ */
+static ssize_t
+wlan_plugin_send (void *cls, const struct GNUNET_PeerIdentity *target,
+ const char *msgbuf, size_t msgbuf_size, unsigned int priority,
+ struct GNUNET_TIME_Relative timeout, struct Session *session,
+ const void *addr, size_t addrlen, int force_address,
+ GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
+{
+ struct Plugin *plugin = cls;
+ struct PendingMessage *newmsg;
+ struct WlanHeader *wlanheader;
+
+ GNUNET_assert (plugin != NULL);
+ //check if msglen > 0
+ GNUNET_assert (msgbuf_size > 0);
+
+ //get session if needed
+ if (session == NULL)
+ {
+ if (wlan_plugin_address_suggested (plugin, addr, addrlen) == GNUNET_OK)
+ {
+ session = get_session (plugin, addr, target);
+ }
+ else
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME,
+ _("Wlan Address len %d is wrong\n"), addrlen);
+ return -1;
+ }
+ }
+
+ GNUNET_STATISTICS_update (plugin->env->stats, _("# wlan messages queued"), 1,
+ GNUNET_NO);
+
+ //queue message:
+
+ //queue message in session
+ //test if there is no other message in the "queue"
+ //FIXME: to many send requests
+ if (session->pending_message_head != NULL)
+ {
+ newmsg = session->pending_message_head;
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "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",
+ GNUNET_TIME_absolute_get_remaining (newmsg->
+ timeout).rel_value,
+ session->mac->fragment_messages_out_count);
+ }
+
+ newmsg = GNUNET_malloc (sizeof (struct PendingMessage));
+ newmsg->msg = GNUNET_malloc (msgbuf_size + sizeof (struct WlanHeader));
+ wlanheader = newmsg->msg;
+ //copy msg to buffer, not fragmented / segmented yet, but with message header
+ wlanheader->header.size = htons (msgbuf_size + sizeof (struct WlanHeader));
+ wlanheader->header.type = htons (GNUNET_MESSAGE_TYPE_WLAN_DATA);
+ memcpy (&(wlanheader->target), target, sizeof (struct GNUNET_PeerIdentity));
+ memcpy (&(wlanheader->source), plugin->env->my_identity,
+ sizeof (struct GNUNET_PeerIdentity));
+ wlanheader->crc = 0;
+ memcpy (&wlanheader[1], msgbuf, msgbuf_size);
+ wlanheader->crc =
+ htonl (getcrc32
+ ((char *) wlanheader, msgbuf_size + sizeof (struct WlanHeader)));
+ //GNUNET_log_from(GNUNET_ERROR_TYPE_INFO, PLUGIN_LOG_NAME, "Wlan message Header crc: %u, %u\n",getcrc32((char*) wlanheader, msgbuf_size + sizeof(struct WlanHeader)), wlanheader->crc);
+ //hexdump(newmsg->msg, msgbuf_size + sizeof(struct WlanHeader));
+
+ newmsg->transmit_cont = cont;
+ newmsg->transmit_cont_cls = cont_cls;
+ newmsg->timeout = GNUNET_TIME_relative_to_absolute (timeout);
+
+ newmsg->timeout.abs_value = newmsg->timeout.abs_value - 500;
+
+ newmsg->message_size = msgbuf_size + sizeof (struct WlanHeader);
+
+ GNUNET_CONTAINER_DLL_insert_tail (session->pending_message_head,
+ session->pending_message_tail, newmsg);
+
+#if DEBUG_wlan
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "New message for %p with size (incl wlan header) %u added\n",
+ session, newmsg->message_size);
+#endif
+#if DEBUG_wlan_msg_dump > 1
+ hexdump (msgbuf, GNUNET_MIN (msgbuf_size, 256));
+#endif
+ //queue session
+ queue_session (plugin, session);
+
+ check_fragment_queue (plugin);
+ //FIXME not the correct size
+ return msgbuf_size;
+
+}
+
+/**
+ * function to free a mac endpoint
+ * @param plugin pointer to the plugin struct
+ * @param endpoint pointer to the MacEndpoint to free
+ */
+static void
+free_macendpoint (struct Plugin *plugin, struct MacEndpoint *endpoint)
+{
+ struct Sessionqueue *sessions;
+ struct Sessionqueue *sessions_next;
+
+ GNUNET_assert (endpoint != NULL);
+
+ sessions = endpoint->sessions_head;
+ while (sessions != NULL)
+ {
+ sessions_next = sessions->next;
+ free_session (plugin, sessions, GNUNET_NO);
+ sessions = sessions_next;
+ }
+
+ GNUNET_CONTAINER_DLL_remove (plugin->mac_head, plugin->mac_tail, endpoint);
+ if (endpoint->timeout_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (endpoint->timeout_task);
+ endpoint->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ plugin->mac_count--;
+ GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan mac endpoints"),
+ plugin->mac_count, GNUNET_NO);
+ GNUNET_free (endpoint);
+
+}
+
+/**
+ * function to free a session
+ * @param plugin pointer to the plugin
+ * @param queue pointer to the sessionqueue element to free
+ * @param free_macendpoint if GNUNET_YES and mac endpoint would be empty, free mac endpoint
+ */
+static void
+free_session (struct Plugin *plugin, struct Sessionqueue *queue,
+ int do_free_macendpoint)
+{
+ struct Sessionqueue *pendingsession;
+ struct Sessionqueue *pendingsession_tmp;
+ struct PendingMessage *pm;
+ struct MacEndpoint *endpoint;
+ struct FragmentMessage *fm;
+ struct FragmentMessage *fmnext;
+ int check = 0;
+
+ GNUNET_assert (plugin != NULL);
+ GNUNET_assert (queue != NULL);
+ GNUNET_assert (queue->content != NULL);
+
+ //session found
+ //is this session pending for send
+ pendingsession = plugin->pending_Sessions_head;
+ while (pendingsession != NULL)
+ {
+ pendingsession_tmp = pendingsession;
+ pendingsession = pendingsession->next;
+ GNUNET_assert (pendingsession_tmp->content != NULL);
+ if (pendingsession_tmp->content == queue->content)
+ {
+ plugin->pendingsessions--;
+ GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending sessions"),
+ plugin->pendingsessions, GNUNET_NO);
+ GNUNET_CONTAINER_DLL_remove (plugin->pending_Sessions_head,
+ plugin->pending_Sessions_tail,
+ pendingsession_tmp);
+ GNUNET_free (pendingsession_tmp);
+
+ GNUNET_assert (check == 0);
+ check = 1;
+ }
+ }
+
+ endpoint = queue->content->mac;
+ fm = endpoint->sending_messages_head;
+ while (fm != NULL)
+ {
+ fmnext = fm->next;
+ if (fm->session == queue->content)
+ {
+ free_fragment_message (plugin, fm);
+ }
+ fm = fmnext;
+ }
+
+ // remove PendingMessage
+ pm = queue->content->pending_message_head;
+ while (pm != NULL)
+ {
+ GNUNET_CONTAINER_DLL_remove (queue->content->pending_message_head,
+ queue->content->pending_message_tail, pm);
+ GNUNET_free (pm->msg);
+ GNUNET_free (pm);
+ pm = queue->content->pending_message_head;
+ }
+
+ GNUNET_CONTAINER_DLL_remove (endpoint->sessions_head, endpoint->sessions_tail,
+ queue);
+ //Check that no ohter session on this endpoint for this session exits
+ GNUNET_assert (search_session (plugin, endpoint, &queue->content->target) ==
+ NULL);
+ if (endpoint->sessions_head == NULL && do_free_macendpoint == GNUNET_YES)
+ {
+ free_macendpoint (plugin, endpoint);
+ //check if no endpoint with the same address exists
+ GNUNET_assert (get_macendpoint (plugin, &endpoint->addr, GNUNET_NO) ==
+ NULL);
+ }
+
+ if (queue->content->timeout_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (queue->content->timeout_task);
+ queue->content->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ GNUNET_free (queue);
+
+ check_fragment_queue (plugin);
+}
+
+/**
+ * Function that can be used to force the plugin to disconnect
+ * from the given peer and cancel all previous transmissions
+ * (and their continuation).
+ *
+ * @param cls closure
+ * @param target peer from which to disconnect
+ */
+static void
+wlan_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target)
+{
+ struct Plugin *plugin = cls;
+ struct Sessionqueue *queue;
+ struct Sessionqueue *queue_next;
+ struct MacEndpoint *endpoint = plugin->mac_head;
+ struct MacEndpoint *endpoint_next;
+
+ // just look at all the session for the needed one
+ while (endpoint != NULL)
+ {
+ queue = endpoint->sessions_head;
+ endpoint_next = endpoint->next;
+ while (queue != NULL)
+ {
+ // content is never NULL
+ GNUNET_assert (queue->content != NULL);
+ queue_next = queue->next;
+ if (memcmp
+ (target, &(queue->content->target),
+ sizeof (struct GNUNET_PeerIdentity)) == 0)
+ {
+ free_session (plugin, queue, GNUNET_YES);
+ }
+ // try next
+ queue = queue_next;
+ }
+ endpoint = endpoint_next;
+ }
+}
+
+/**
+ * Convert the transports address to a nice, human-readable
+ * format.
+ *
+ * @param cls closure
+ * @param type name of the transport that generated the address
+ * @param addr one of the addresses of the host, NULL for the last address
+ * the specific address format depends on the transport
+ * @param addrlen length of the address
+ * @param numeric should (IP) addresses be displayed in numeric form?
+ * @param timeout after how long should we give up?
+ * @param asc function to call on each string
+ * @param asc_cls closure for asc
+ */
+static void
+wlan_plugin_address_pretty_printer (void *cls, const char *type,
+ const void *addr, size_t addrlen,
+ int numeric,
+ struct GNUNET_TIME_Relative timeout,
+ GNUNET_TRANSPORT_AddressStringCallback asc,
+ void *asc_cls)
+{
+ char *ret;
+ const unsigned char *input;
+
+ //GNUNET_assert(cls !=NULL);
+ if (addrlen != sizeof (struct MacAddress))
+ {
+ /* invalid address (MAC addresses have 6 bytes) */
+ //GNUNET_break (0);
+#if DEBUG_wlan
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Func wlan_plugin_address_pretty_printer got size: %u, worng size!\n",
+ addrlen);
+#endif
+ asc (asc_cls, NULL);
+ return;
+ }
+ input = (const unsigned char *) addr;
+ GNUNET_asprintf (&ret,
+ "Transport %s: %s Mac-Address %.2X:%.2X:%.2X:%.2X:%.2X:%.2X",
+ type, PROTOCOL_PREFIX, input[0], input[1], input[2],
+ input[3], input[4], input[5]);
+#if DEBUG_wlan
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Func wlan_plugin_address_pretty_printer got size: %u, nummeric %u, type %s; made string: %s\n",
+ addrlen, numeric, type, ret);
+#endif
+ asc (asc_cls, ret);
+ //only one mac address per plugin
+ asc (asc_cls, NULL);
+}
+
+
+
+/**
+ * handels the data after all fragments are put together
+ * @param cls macendpoint this messages belongs to
+ * @param hdr pointer to the data
+ */
+static void
+wlan_data_message_handler (void *cls, const struct GNUNET_MessageHeader *hdr)
+{
+ struct MacEndpoint *endpoint = (struct MacEndpoint *) cls;
+ struct Plugin *plugin = endpoint->plugin;
+ struct WlanHeader *wlanheader;
+ struct Session *session;
+
+ const struct GNUNET_MessageHeader *temp_hdr;
+ struct GNUNET_PeerIdentity tmpsource;
+ int crc;
+
+ GNUNET_assert (plugin != NULL);