/*
   This file is part of GNUnet.
   Copyright (C) 2010, 2011, 2012 GNUnet e.V.
   Copyright (C) 2007, 2008, Andy Green <andy@warmcat.com>
   Copyright (C) 2009 Thomas d'Otreppe

   GNUnet is free software: you can redistribute it and/or modify it
   under the terms of the GNU Affero General Public License as published
   by the Free Software Foundation, either version 3 of the License,
   or (at your option) any later version.

   GNUnet is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.

     SPDX-License-Identifier: AGPL3.0-or-later
 */
#include "platform.h"
#include "gnunet_private_config.h"

#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#include <bluetooth/rfcomm.h>
#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>
#include <errno.h>
#include <linux/if.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include "plugin_transport_wlan.h"
#include "gnunet_protocols.h"


/**
 * Maximum number of ports assignable for RFCOMMM protocol.
 */
#define MAX_PORTS 30

/**
 * Maximum size of a message allowed in either direction
 * (used for our receive and sent buffers).
 */
#define MAXLINE 4096


/**
 * Maximum number of loops without inquiring for new devices.
 */
#define MAX_LOOPS 5

/**
 * In bluez library, the maximum name length of a device is 8
 */
#define BLUEZ_DEVNAME_SIZE  8

/**
 * struct for storing the information of the hardware.  There is only
 * one of these.
 */
struct HardwareInfos
{
  /**
   * Name of the interface, not necessarily 0-terminated (!).
   */
  char iface[IFNAMSIZ];

  /**
   * file descriptor for the rfcomm socket
   */
  int fd_rfcomm;

  /**
   * MAC address of our own bluetooth interface.
   */
  struct GNUNET_TRANSPORT_WLAN_MacAddress pl_mac;

  /**
   * SDP session
   */
  sdp_session_t *session;
};

/**
 * IO buffer used for buffering data in transit (to wireless or to stdout).
 */
struct SendBuffer
{
  /**
   * How many bytes of data are stored in 'buf' for transmission right now?
   * Data always starts at offset 0 and extends to 'size'.
   */
  size_t size;

  /**
   * How many bytes that were stored in 'buf' did we already write to the
   * destination?  Always smaller than 'size'.
   */
  size_t pos;

  /**
   * Buffered data; twice the maximum allowed message size as we add some
   * headers.
   */
  char buf[MAXLINE * 2];
};

#ifdef __linux__
/**
 * Devices buffer used to keep a list with all the discoverable devices in
 * order to send them HELLO messages one by one when it receive a broadcast message.
 */
struct BroadcastMessages
{
  /* List with the discoverable devices' addresses */
  bdaddr_t devices[MAX_PORTS];

  /* List with the open sockets */
  int fds[MAX_PORTS];


  /* The number of the devices */
  int size;

  /* The current position */
  int pos;

  /* The device id */
  int dev_id;
};

/**
 * Address used to identify the broadcast messages.
 */
static struct GNUNET_TRANSPORT_WLAN_MacAddress broadcast_address = { { 255, 255,
                                                                       255, 255,
                                                                       255,
                                                                       255 } };

/**
 * Buffer with the discoverable devices.
 */
static struct BroadcastMessages neighbours;

static int searching_devices_count = 0;
#endif

/**
 * Buffer for data read from stdin to be transmitted to the bluetooth device
 */
static struct SendBuffer write_pout;

/**
 * Buffer for data read from the bluetooth device to be transmitted to stdout.
 */
static struct SendBuffer write_std;


/* ****** this are the same functions as the ones used in gnunet-helper-transport-wlan.c ****** */

/**
 * To what multiple do we align messages?  8 byte should suffice for everyone
 * for now.
 */
#define ALIGN_FACTOR 8

/**
 * Smallest supported message.
 */
#define MIN_BUFFER_SIZE sizeof(struct GNUNET_MessageHeader)


/**
 * Functions with this signature are called whenever a
 * complete message is received by the tokenizer.
 *
 * @param cls closure
 * @param message the actual message
 */
typedef void (*MessageTokenizerCallback) (void *cls,
                                          const struct
                                          GNUNET_MessageHeader *
                                          message);

/**
 * Handle to a message stream tokenizer.
 */
struct MessageStreamTokenizer
{
  /**
   * Function to call on completed messages.
   */
  MessageTokenizerCallback cb;

  /**
   * Closure for cb.
   */
  void *cb_cls;

  /**
   * Size of the buffer (starting at 'hdr').
   */
  size_t curr_buf;

  /**
   * How many bytes in buffer have we already processed?
   */
  size_t off;

  /**
   * How many bytes in buffer are valid right now?
   */
  size_t pos;

  /**
   * Beginning of the buffer.  Typed like this to force alignment.
   */
  struct GNUNET_MessageHeader *hdr;
};


/**
 * Create a message stream tokenizer.
 *
 * @param cb function to call on completed messages
 * @param cb_cls closure for cb
 * @return handle to tokenizer
 */
static struct MessageStreamTokenizer *
mst_create (MessageTokenizerCallback cb,
            void *cb_cls)
{
  struct MessageStreamTokenizer *ret;

  ret = malloc (sizeof(struct MessageStreamTokenizer));
  if (NULL == ret)
  {
    fprintf (stderr, "Failed to allocate buffer for tokenizer\n");
    exit (1);
  }
  ret->hdr = malloc (MIN_BUFFER_SIZE);
  if (NULL == ret->hdr)
  {
    fprintf (stderr, "Failed to allocate buffer for alignment\n");
    exit (1);
  }
  ret->curr_buf = MIN_BUFFER_SIZE;
  ret->cb = cb;
  ret->cb_cls = cb_cls;
  ret->pos = 0;

  return ret;
}


/**
 * Add incoming data to the receive buffer and call the
 * callback for all complete messages.
 *
 * @param mst tokenizer to use
 * @param buf input data to add
 * @param size number of bytes in buf
 * @return GNUNET_OK if we are done processing (need more data)
 *         GNUNET_SYSERR if the data stream is corrupt
 */
static int
mst_receive (struct MessageStreamTokenizer *mst,
             const char *buf, size_t size)
{
  const struct GNUNET_MessageHeader *hdr;
  size_t delta;
  uint16_t want;
  char *ibuf;
  int need_align;
  unsigned long offset;
  int ret;

  ret = GNUNET_OK;
  ibuf = (char *) mst->hdr;
  while (mst->pos > 0)
  {
do_align:
    if (mst->pos < mst->off)
    {
      // fprintf (stderr, "We processed too many bytes!\n");
      return GNUNET_SYSERR;
    }
    if ((mst->curr_buf - mst->off < sizeof(struct GNUNET_MessageHeader)) ||
        (0 != (mst->off % ALIGN_FACTOR)))
    {
      /* need to align or need more space */
      mst->pos -= mst->off;
      memmove (ibuf, &ibuf[mst->off], mst->pos);
      mst->off = 0;
    }
    if (mst->pos - mst->off < sizeof(struct GNUNET_MessageHeader))
    {
      delta =
        GNUNET_MIN (sizeof(struct GNUNET_MessageHeader)
                    - (mst->pos - mst->off), size);
      GNUNET_memcpy (&ibuf[mst->pos], buf, delta);
      mst->pos += delta;
      buf += delta;
      size -= delta;
    }
    if (mst->pos - mst->off < sizeof(struct GNUNET_MessageHeader))
    {
      // FIXME should I reset ??
      // mst->off = 0;
      // mst->pos = 0;
      return GNUNET_OK;
    }
    hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
    want = ntohs (hdr->size);
    if (want < sizeof(struct GNUNET_MessageHeader))
    {
      fprintf (stderr,
               "Received invalid message from stdin\n");
      return GNUNET_SYSERR;
    }
    if ((mst->curr_buf - mst->off < want) &&
        (mst->off > 0))
    {
      /* need more space */
      mst->pos -= mst->off;
      memmove (ibuf, &ibuf[mst->off], mst->pos);
      mst->off = 0;
    }
    if (want > mst->curr_buf)
    {
      if (mst->off != 0)
      {
        fprintf (stderr, "Error! We should proceeded 0 bytes\n");
        return GNUNET_SYSERR;
      }
      mst->hdr = realloc (mst->hdr, want);
      if (NULL == mst->hdr)
      {
        fprintf (stderr, "Failed to allocate buffer for alignment\n");
        exit (1);
      }
      ibuf = (char *) mst->hdr;
      mst->curr_buf = want;
    }
    hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
    if (mst->pos - mst->off < want)
    {
      delta = GNUNET_MIN (want - (mst->pos - mst->off), size);
      if (mst->pos + delta > mst->curr_buf)
      {
        fprintf (stderr, "The size of the buffer will be exceeded!\n");
        return GNUNET_SYSERR;
      }
      GNUNET_memcpy (&ibuf[mst->pos], buf, delta);
      mst->pos += delta;
      buf += delta;
      size -= delta;
    }
    if (mst->pos - mst->off < want)
    {
      // FIXME should I use this?
      // mst->off = 0;
      // mst->pos = 0;
      return GNUNET_OK;
    }
    mst->cb (mst->cb_cls, hdr);
    mst->off += want;
    if (mst->off == mst->pos)
    {
      /* reset to beginning of buffer, it's free right now! */
      mst->off = 0;
      mst->pos = 0;
    }
  }
  if (0 != mst->pos)
  {
    fprintf (stderr,
             "There should some valid bytes in the buffer on this stage\n");
    return GNUNET_SYSERR;
  }
  while (size > 0)
  {
    if (size < sizeof(struct GNUNET_MessageHeader))
      break;
    offset = (unsigned long) buf;
    need_align = (0 != offset % ALIGN_FACTOR) ? GNUNET_YES : GNUNET_NO;
    if (GNUNET_NO == need_align)
    {
      /* can try to do zero-copy and process directly from original buffer */
      hdr = (const struct GNUNET_MessageHeader *) buf;
      want = ntohs (hdr->size);
      if (want < sizeof(struct GNUNET_MessageHeader))
      {
        fprintf (stderr,
                 "Received invalid message from stdin\n");
        // exit (1);
        mst->off = 0;
        return GNUNET_SYSERR;
      }
      if (size < want)
        break;                  /* or not, buffer incomplete, so copy to private buffer... */
      mst->cb (mst->cb_cls, hdr);
      buf += want;
      size -= want;
    }
    else
    {
      /* need to copy to private buffer to align;
       * yes, we go a bit more spaghetti than usual here */
      goto do_align;
    }
  }
  if (size > 0)
  {
    if (size + mst->pos > mst->curr_buf)
    {
      mst->hdr = realloc (mst->hdr, size + mst->pos);
      if (NULL == mst->hdr)
      {
        fprintf (stderr, "Failed to allocate buffer for alignment\n");
        exit (1);
      }
      ibuf = (char *) mst->hdr;
      mst->curr_buf = size + mst->pos;
    }
    if (mst->pos + size > mst->curr_buf)
    {
      fprintf (stderr,
               "Assertion failed\n");
      exit (1);
    }
    GNUNET_memcpy (&ibuf[mst->pos], buf, size);
    mst->pos += size;
  }
  return ret;
}


/**
 * Destroys a tokenizer.
 *
 * @param mst tokenizer to destroy
 */
static void
mst_destroy (struct MessageStreamTokenizer *mst)
{
  free (mst->hdr);
  free (mst);
}


/**
 * Calculate crc32, the start of the calculation
 *
 * @param buf buffer to calc the crc
 * @param len len of the buffer
 * @return crc sum
 */
static unsigned long
calc_crc_osdep (const unsigned char *buf, size_t len)
{
  static const unsigned long int crc_tbl_osdep[256] = {
    0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
    0xE963A535, 0x9E6495A3,
    0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
    0xE7B82D07, 0x90BF1D91,
    0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB,
    0xF4D4B551, 0x83D385C7,
    0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
    0xFA0F3D63, 0x8D080DF5,
    0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447,
    0xD20D85FD, 0xA50AB56B,
    0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75,
    0xDCD60DCF, 0xABD13D59,
    0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
    0xCFBA9599, 0xB8BDA50F,
    0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11,
    0xC1611DAB, 0xB6662D3D,
    0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F,
    0x9FBFE4A5, 0xE8B8D433,
    0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
    0x91646C97, 0xE6635C01,
    0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B,
    0x8208F4C1, 0xF50FC457,
    0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49,
    0x8CD37CF3, 0xFBD44C65,
    0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
    0xA4D1C46D, 0xD3D6F4FB,
    0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5,
    0xAA0A4C5F, 0xDD0D7CC9,
    0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3,
    0xB966D409, 0xCE61E49F,
    0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
    0xB7BD5C3B, 0xC0BA6CAD,
    0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF,
    0x04DB2615, 0x73DC1683,
    0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
    0x0A00AE27, 0x7D079EB1,
    0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
    0x196C3671, 0x6E6B06E7,
    0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9,
    0x17B7BE43, 0x60B08ED5,
    0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767,
    0x3FB506DD, 0x48B2364B,
    0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
    0x316E8EEF, 0x4669BE79,
    0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703,
    0x220216B9, 0x5505262F,
    0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31,
    0x2CD99E8B, 0x5BDEAE1D,
    0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
    0x72076785, 0x05005713,
    0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
    0x7CDCEFB7, 0x0BDBDF21,
    0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B,
    0x6FB077E1, 0x18B74777,
    0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
    0x616BFFD3, 0x166CCF45,
    0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7,
    0x4969474D, 0x3E6E77DB,
    0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5,
    0x47B2CF7F, 0x30B5FFE9,
    0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
    0x54DE5729, 0x23D967BF,
    0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1,
    0x5A05DF1B, 0x2D02EF8D
  };

  unsigned long crc = 0xFFFFFFFF;

  for (; len > 0; len--, buf++)
    crc = crc_tbl_osdep[(crc ^ *buf) & 0xFF] ^ (crc >> 8);
  return(~crc);
}


/**
 * Calculate and check crc of the bluetooth packet
 *
 * @param buf buffer of the packet, with len + 4 bytes of data,
 *            the last 4 bytes being the checksum
 * @param len length of the payload in data
 * @return 0 on success (checksum matches), 1 on error
 */
static int
check_crc_buf_osdep (const unsigned char *buf, size_t len)
{
  unsigned long crc;

  crc = calc_crc_osdep (buf, len);
  buf += len;
  if ((((crc) & 0xFF) == buf[0]) && (((crc >> 8) & 0xFF) == buf[1]) &&
      ( ((crc >> 16) & 0xFF) == buf[2]) && ( ((crc >> 24) & 0xFF) == buf[3]) )
    return 0;
  return 1;
}


/* ************** end of clone  ***************** */
#ifdef __linux__
/**
 * Function for assigning a port number
 *
 * @param socket the socket used to bind
 * @param addr pointer to the rfcomm address
 * @return 0 on success
 */
static int
bind_socket (int socket, struct sockaddr_rc *addr)
{
  int port, status;

  /* Bind every possible port (from 0 to 30) and stop when binding doesn't fail */
  // FIXME : it should start from port 1, but on my computer it doesn't work :)
  for (port = 3; port <= 30; port++)
  {
    addr->rc_channel = port;
    status = bind (socket, (struct sockaddr *) addr, sizeof(struct
                                                            sockaddr_rc));
    if (status == 0)
      return 0;
  }

  return -1;
}


#endif

/**
 * Function used for creating the service record and registering it.
 *
 * @param dev pointer to the device struct
 * @param rc_channel the rfcomm channel
 * @return 0 on success
 */
static int
register_service (struct HardwareInfos *dev, int rc_channel)
{
  /**
   * 1. initializations
   * 2. set the service ID, class, profile information
   * 3. make the service record publicly browsable
   * 4. register the RFCOMM channel
   * 5. set the name, provider and description
   * 6. register the service record to the local SDP server
   * 7. cleanup
   */uint8_t svc_uuid_int[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                             dev->pl_mac.mac[5], dev->pl_mac.mac[4],
                             dev->pl_mac.mac[3],
                             dev->pl_mac.mac[2], dev->pl_mac.mac[1],
                             dev->pl_mac.mac[0] };
  const char *service_dsc = "Bluetooth plugin services";
  const char *service_prov = "GNUnet provider";
  uuid_t root_uuid, rfcomm_uuid, svc_uuid;
  sdp_list_t *root_list = 0, *rfcomm_list = 0, *proto_list = 0,
             *access_proto_list = 0, *svc_list = 0;
  sdp_record_t *record = 0;
  sdp_data_t *channel = 0;

  record = sdp_record_alloc ();

  /* Set the general service ID */
  sdp_uuid128_create (&svc_uuid, &svc_uuid_int);
  svc_list = sdp_list_append (0, &svc_uuid);
  sdp_set_service_classes (record, svc_list);
  sdp_set_service_id (record, svc_uuid);

  /* Make the service record publicly browsable */
  sdp_uuid16_create (&root_uuid, PUBLIC_BROWSE_GROUP);
  root_list = sdp_list_append (0, &root_uuid);
  sdp_set_browse_groups (record, root_list);

  /* Register the RFCOMM channel */
  sdp_uuid16_create (&rfcomm_uuid, RFCOMM_UUID);
  channel = sdp_data_alloc (SDP_UINT8, &rc_channel);
  rfcomm_list = sdp_list_append (0, &rfcomm_uuid);
  sdp_list_append (rfcomm_list, channel);
  proto_list = sdp_list_append (0, rfcomm_list);

  /* Set protocol information */
  access_proto_list = sdp_list_append (0, proto_list);
  sdp_set_access_protos (record, access_proto_list);

  /* Set the name, provider, and description */
  sdp_set_info_attr (record, dev->iface, service_prov, service_dsc);

  /* Connect to the local SDP server */
  dev->session = sdp_connect (BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY);

  if (! dev->session)
  {
    fprintf (stderr,
             "Failed to connect to the SDP server on interface `%.*s': %s\n",
             IFNAMSIZ, dev->iface, strerror (errno));
    // FIXME exit?
    return 1;
  }

  /* Register the service record */
  if (sdp_record_register (dev->session, record, 0) < 0)
  {
    fprintf (stderr,
             "Failed to register a service record on interface `%.*s': %s\n",
             IFNAMSIZ, dev->iface, strerror (errno));
    // FIXME exit?
    return 1;
  }

  /* Cleanup */
  sdp_data_free (channel);
  sdp_list_free (root_list, 0);
  sdp_list_free (rfcomm_list, 0);
  sdp_list_free (proto_list, 0);
  sdp_list_free (access_proto_list, 0);
  sdp_list_free (svc_list, 0);
  sdp_record_free (record);

  return 0;
}


/**
 * Function used for searching and browsing for a service. This will return the
 * port number on which the service is running.
 *
 * @param dev pointer to the device struct
 * @param dest target address
 * @return channel
 */
static int
get_channel (struct HardwareInfos *dev, bdaddr_t dest)
{
  /**
   * 1. detect all nearby devices
   * 2. for each device:
   * 2.1. connect to the SDP server running
   * 2.2. get a list of service records with the specific UUID
   * 2.3. for each service record get a list of the protocol sequences and get
   *       the port number
   */uint8_t svc_uuid_int[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                             dest.b[5], dest.b[4], dest.b[3],
                             dest.b[2], dest.b[1], dest.b[0] };
  sdp_session_t *session = 0;
  sdp_list_t *search_list = 0, *attrid_list = 0, *response_list = 0, *it = 0;
  uuid_t svc_uuid;
  uint32_t range = 0x0000ffff;
  int channel = -1;

  /* Connect to the local SDP server */
  session = sdp_connect (BDADDR_ANY, &dest, 0);
  if (! session)
  {
    fprintf (stderr,
             "Failed to connect to the SDP server on interface `%.*s': %s\n",
             IFNAMSIZ, dev->iface, strerror (errno));
    return -1;
  }

  sdp_uuid128_create (&svc_uuid, &svc_uuid_int);
  search_list = sdp_list_append (0, &svc_uuid);
  attrid_list = sdp_list_append (0, &range);

  if (sdp_service_search_attr_req (session, search_list,
                                   SDP_ATTR_REQ_RANGE, attrid_list,
                                   &response_list) == 0)
  {
    for (it = response_list; it; it = it->next)
    {
      sdp_record_t *record = (sdp_record_t *) it->data;
      sdp_list_t *proto_list = 0;
      if (sdp_get_access_protos (record, &proto_list) == 0)
      {
        channel = sdp_get_proto_port (proto_list, RFCOMM_UUID);
        sdp_list_free (proto_list, 0);
      }
      sdp_record_free (record);
    }
  }

  sdp_list_free (search_list, 0);
  sdp_list_free (attrid_list, 0);
  sdp_list_free (response_list, 0);

  sdp_close (session);

  if (-1 == channel)
    fprintf (stderr,
             "Failed to find the listening channel for interface `%.*s': %s\n",
             IFNAMSIZ,
             dev->iface,
             strerror (errno));

  return channel;
}


/**
 * Read from the socket and put the result into the buffer for transmission to 'stdout'.
 *
 * @param sock file descriptor for reading
 * @param buf buffer to read to; first bytes will be the 'struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame',
 *            followed by the actual payload
 * @param buf_size size of the buffer
 * @param ri where to write radiotap_rx info
 * @return number of bytes written to 'buf'
 */
static ssize_t
read_from_the_socket (void *sock,
                      unsigned char *buf, size_t buf_size,
                      struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *ri)
{
  unsigned char tmpbuf[buf_size];
  ssize_t count;
  count = read (*((int *) sock), tmpbuf, buf_size);

  if (0 > count)
  {
    if (EAGAIN == errno)
      return 0;

    fprintf (stderr, "Failed to read from the HCI socket: %s\n", strerror (
               errno));

    return -1;
  }

  #ifdef __linux__
  /* Get the channel used */
  int len;
  struct sockaddr_rc rc_addr = { 0 };

  memset (&rc_addr, 0, sizeof(rc_addr));
  len = sizeof(rc_addr);
  if (0 > getsockname (*((int *) sock), (struct sockaddr *) &rc_addr,
                       (socklen_t *) &len))
  {
    fprintf (stderr, "getsockname() call failed : %s\n", strerror (errno));
    return -1;
  }

  memset (ri, 0, sizeof(*ri));
  ri->ri_channel = rc_addr.rc_channel;
  #endif

  /* Detect CRC32 at the end */
  if (0 == check_crc_buf_osdep (tmpbuf, count - sizeof(uint32_t)))
  {
    count -= sizeof(uint32_t);
  }

  GNUNET_memcpy (buf, tmpbuf, count);

  return count;
}


/**
 * Open the bluetooth interface for reading/writing
 *
 * @param dev pointer to the device struct
 * @return 0 on success, non-zero on error
 */
static int
open_device (struct HardwareInfos *dev)
{
  int i, dev_id = -1, fd_hci;
  struct
  {
    struct hci_dev_list_req list;
    struct hci_dev_req dev[HCI_MAX_DEV];
  } request;                                // used for detecting the local devices
  struct sockaddr_rc rc_addr = { 0 };      // used for binding

  /* Initialize the neighbour structure */
  neighbours.dev_id = -1;
  for (i = 0; i < MAX_PORTS; i++)
    neighbours.fds[i] = -1;

  /* Open a HCI socket */
  fd_hci = socket (AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);

  if (fd_hci < 0)
  {
    fprintf (stderr,
             "Failed to create HCI socket: %s\n",
             strerror (errno));
    return -1;
  }

  memset (&request, 0, sizeof(request));
  request.list.dev_num = HCI_MAX_DEV;

  if (ioctl (fd_hci, HCIGETDEVLIST, (void *) &request) < 0)
  {
    fprintf (stderr,
             "ioctl(HCIGETDEVLIST) on interface `%.*s' failed: %s\n",
             IFNAMSIZ,
             dev->iface,
             strerror (errno));
    (void) close (fd_hci);
    return 1;
  }

  /* Search for a device with dev->iface name */
  for (i = 0; i < request.list.dev_num; i++)
  {
    struct hci_dev_info dev_info;

    memset (&dev_info, 0, sizeof(struct hci_dev_info));
    dev_info.dev_id = request.dev[i].dev_id;
    strncpy (dev_info.name, dev->iface, BLUEZ_DEVNAME_SIZE);

    if (ioctl (fd_hci, HCIGETDEVINFO, (void *) &dev_info))
    {
      fprintf (stderr,
               "ioctl(HCIGETDEVINFO) on interface `%.*s' failed: %s\n",
               IFNAMSIZ,
               dev->iface,
               strerror (errno));
      (void) close (fd_hci);
      return 1;
    }

    if (strncmp (dev_info.name, dev->iface, BLUEZ_DEVNAME_SIZE) == 0)
    {
      dev_id = dev_info.dev_id;     // the device was found
      /**
       * Copy the MAC address to the device structure
       */
      GNUNET_memcpy (&dev->pl_mac, &dev_info.bdaddr, sizeof(bdaddr_t));

      /* Check if the interface is up */
      if (hci_test_bit (HCI_UP, (void *) &dev_info.flags) == 0)
      {
        /* Bring the interface up */
        if (ioctl (fd_hci, HCIDEVUP, dev_info.dev_id))
        {
          fprintf (stderr,
                   "ioctl(HCIDEVUP) on interface `%.*s' failed: %s\n",
                   IFNAMSIZ,
                   dev->iface,
                   strerror (errno));
          (void) close (fd_hci);
          return 1;
        }
      }

      /* Check if the device is discoverable */
      if ((hci_test_bit (HCI_PSCAN, (void *) &dev_info.flags) == 0) ||
          (hci_test_bit (HCI_ISCAN, (void *) &dev_info.flags) == 0) )
      {
        /* Set interface Page Scan and Inqury Scan ON */
        struct hci_dev_req dev_req;

        memset (&dev_req, 0, sizeof(dev_req));
        dev_req.dev_id = dev_info.dev_id;
        dev_req.dev_opt = SCAN_PAGE | SCAN_INQUIRY;

        if (ioctl (fd_hci, HCISETSCAN, (unsigned long) &dev_req))
        {
          fprintf (stderr,
                   "ioctl(HCISETSCAN) on interface `%.*s' failed: %s\n",
                   IFNAMSIZ,
                   dev->iface,
                   strerror (errno));
          (void) close (fd_hci);
          return 1;
        }
      }
      break;
    }
  }

  /* Check if the interface was not found */
  if (-1 == dev_id)
  {
    fprintf (stderr,
             "The interface %s was not found\n",
             dev->iface);
    (void) close (fd_hci);
    return 1;
  }

  /* Close the hci socket */
  (void) close (fd_hci);


  /* Bind the rfcomm socket to the interface */
  memset (&rc_addr, 0, sizeof(rc_addr));
  rc_addr.rc_family = AF_BLUETOOTH;
  rc_addr.rc_bdaddr = *BDADDR_ANY;

  if (bind_socket (dev->fd_rfcomm, &rc_addr) != 0)
  {
    fprintf (stderr,
             "Failed to bind interface `%.*s': %s\n",
             IFNAMSIZ,
             dev->iface,
             strerror (errno));
    return 1;
  }

  /* Register a SDP service */
  if (register_service (dev, rc_addr.rc_channel) != 0)
  {
    fprintf (stderr,
             "Failed to register a service on interface `%.*s': %s\n",
             IFNAMSIZ,
             dev->iface, strerror (errno));
    return 1;
  }

  /* Switch socket in listening mode */
  if (listen (dev->fd_rfcomm, 5) == -1)    // FIXME: probably we need a bigger number
  {
    fprintf (stderr, "Failed to listen on socket for interface `%.*s': %s\n",
             IFNAMSIZ,
             dev->iface, strerror (errno));
    return 1;
  }

  return 0;
}


/**
 * Set the header to sane values to make attacks more difficult
 *
 * @param taIeeeHeader pointer to the header of the packet
 * @param dev pointer to the Hardware_Infos struct
 *
 **** copy from gnunet-helper-transport-wlan.c ****
 */
static void
mac_set (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *taIeeeHeader,
         const struct HardwareInfos *dev)
{
  taIeeeHeader->frame_control = htons (IEEE80211_FC0_TYPE_DATA);
  taIeeeHeader->addr3 = mac_bssid_gnunet;
  taIeeeHeader->addr2 = dev->pl_mac;
}


#ifdef __linux__
/**
 * Test if the given interface name really corresponds to a bluetooth
 * device.
 *
 * @param iface name of the interface
 * @return 0 on success, 1 on error
 **** similar with the one from gnunet-helper-transport-wlan.c ****
 */
static int
test_bluetooth_interface (const char *iface)
{
  char strbuf[512];
  struct stat sbuf;
  int ret;

  ret = snprintf (strbuf, sizeof(strbuf),
                  "/sys/class/bluetooth/%s/subsystem",
                  iface);
  if ((ret < 0) || (ret >= sizeof(strbuf)) || (0 != stat (strbuf, &sbuf)))
  {
    fprintf (stderr,
             "Did not find 802.15.1 interface `%s'. Exiting.\n",
             iface);
    exit (1);
  }
  return 0;
}


#endif

/**
 * Test incoming packets mac for being our own.
 *
 * @param taIeeeHeader buffer of the packet
 * @param dev the Hardware_Infos struct
 * @return 0 if mac belongs to us, 1 if mac is for another target
 *
 **** same as the one from gnunet-helper-transport-wlan.c ****
 */
static int
mac_test (const struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *taIeeeHeader,
          const struct HardwareInfos *dev)
{
  static struct GNUNET_TRANSPORT_WLAN_MacAddress all_zeros;

  if ((0 == memcmp (&taIeeeHeader->addr3, &all_zeros, MAC_ADDR_SIZE)) ||
      (0 == memcmp (&taIeeeHeader->addr1, &all_zeros, MAC_ADDR_SIZE)))
    return 0; /* some drivers set no Macs, then assume it is all for us! */

  if (0 != memcmp (&taIeeeHeader->addr3, &mac_bssid_gnunet, MAC_ADDR_SIZE))
    return 1; /* not a GNUnet ad-hoc package */
  if ((0 == memcmp (&taIeeeHeader->addr1, &dev->pl_mac, MAC_ADDR_SIZE)) ||
      (0 == memcmp (&taIeeeHeader->addr1, &bc_all_mac, MAC_ADDR_SIZE)))
    return 0; /* for us, or broadcast */
  return 1; /* not for us */
}


/**
 * Process data from the stdin. Takes the message, forces the sender MAC to be correct
 * and puts it into our buffer for transmission to the receiver.
 *
 * @param cls pointer to the device struct ('struct HardwareInfos*')
 * @param hdr pointer to the start of the packet
 *
 **** same as the one from gnunet-helper-transport-wlan.c ****
 */
static void
stdin_send_hw (void *cls, const struct GNUNET_MessageHeader *hdr)
{
  struct HardwareInfos *dev = cls;
  const struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *header;
  struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *blueheader;
  size_t sendsize;

  sendsize = ntohs (hdr->size);
  if ((sendsize <
       sizeof(struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage)) ||
      (GNUNET_MESSAGE_TYPE_WLAN_DATA_TO_HELPER != ntohs (hdr->type)))
  {
    fprintf (stderr, "Received malformed message\n");
    exit (1);
  }
  sendsize -= (sizeof(struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage)
               - sizeof(struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame));
  if (MAXLINE < sendsize)
  {
    fprintf (stderr, "Packet too big for buffer\n");
    exit (1);
  }
  header = (const struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *) hdr;
  GNUNET_memcpy (&write_pout.buf, &header->frame, sendsize);
  blueheader = (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *) &write_pout.buf;

  /* payload contains MAC address, but we don't trust it, so we'll
   * overwrite it with OUR MAC address to prevent mischief */
  mac_set (blueheader, dev);
  GNUNET_memcpy (&blueheader->addr1, &header->frame.addr1,
                 sizeof(struct GNUNET_TRANSPORT_WLAN_MacAddress));
  write_pout.size = sendsize;
}


#ifdef __linux__
/**
 * Broadcast a HELLO message for peer discovery
 *
 * @param dev pointer to the device struct
 * @param dev pointer to the socket which was added to the set
 * @return 0 on success
 */
static int
send_broadcast (struct HardwareInfos *dev, int *sendsocket)
{
  int new_device = 0;
  int loops = 0;

search_for_devices:
  if (((neighbours.size == neighbours.pos) && (new_device == 1)) ||
      (neighbours.size == 0) )
  {
inquiry_devices:      // skip the conditions and force a inquiry for new devices
    {
      /**
       * It means that I sent HELLO messages to all the devices from the list and I should search
       * for new ones or that this is the first time when I do a search.
       */
      inquiry_info *devices = NULL;
      int i, responses, max_responses = MAX_PORTS;

      /* sanity checks */
      if (neighbours.size >= MAX_PORTS)
      {
        fprintf (stderr,
                 "%.*s reached the top limit for the discovarable devices\n",
                 IFNAMSIZ,
                 dev->iface);
        return 2;
      }

      /* Get the device id */
      if (neighbours.dev_id == -1)
      {
        char addr[19] = { 0 };     // the device MAC address

        ba2str ((bdaddr_t *) &dev->pl_mac, addr);
        neighbours.dev_id = hci_devid (addr);
        if (neighbours.dev_id < 0)
        {
          fprintf (stderr,
                   "Failed to get the device id for interface %.*s : %s\n",
                   IFNAMSIZ,
                   dev->iface, strerror (errno));
          return 1;
        }
      }

      devices = malloc (max_responses * sizeof(inquiry_info));
      if (devices == NULL)
      {
        fprintf (stderr,
                 "Failed to allocate memory for inquiry info list on interface %.*s\n",
                 IFNAMSIZ,
                 dev->iface);
        return 1;
      }

      responses = hci_inquiry (neighbours.dev_id, 8, max_responses, NULL,
                               &devices, IREQ_CACHE_FLUSH);
      if (responses < 0)
      {
        fprintf (stderr, "Failed to inquiry on interface %.*s\n", IFNAMSIZ,
                 dev->iface);
        return 1;
      }

      fprintf (stderr, "LOG : Found %d devices\n", responses);  // FIXME delete it after debugging stage

      if (responses == 0)
      {
        fprintf (stderr, "LOG : No devices discoverable\n");
        return 1;
      }

      for (i = 0; i < responses; i++)
      {
        int j;
        int found = 0;

        /* sanity check */
        if (i >= MAX_PORTS)
        {
          fprintf (stderr,
                   "%.*s reached the top limit for the discoverable devices (after inquiry)\n",
                   IFNAMSIZ,
                   dev->iface);
          return 2;
        }

        /* Search if the address already exists on the list */
        for (j = 0; j < neighbours.size; j++)
        {
          if (memcmp (&(devices + i)->bdaddr, &(neighbours.devices[j]),
                      sizeof(bdaddr_t)) == 0)
          {
            found = 1;
            fprintf (stderr, "LOG : the device already exists on the list\n");        // FIXME debugging message
            break;
          }
        }

        if (found == 0)
        {
          char addr[19] = { 0 };

          ba2str (&(devices + i)->bdaddr, addr);
          fprintf (stderr, "LOG : %s was added to the list\n", addr);      // FIXME debugging message
          GNUNET_memcpy (&(neighbours.devices[neighbours.size++]), &(devices
                                                                     + i)->
                         bdaddr, sizeof(bdaddr_t));
        }
      }

      free (devices);
    }
  }

  int connection_successful = 0;
  struct sockaddr_rc addr_rc = { 0 };
  int errno_copy = 0;
  addr_rc.rc_family = AF_BLUETOOTH;

  /* Try to connect to a new device from the list */
  while (neighbours.pos < neighbours.size)
  {
    /* Check if we are already connected to this device */
    if (neighbours.fds[neighbours.pos] == -1)
    {
      memset (&addr_rc.rc_bdaddr, 0, sizeof(addr_rc.rc_bdaddr));
      GNUNET_memcpy (&addr_rc.rc_bdaddr, &(neighbours.devices[neighbours.pos]),
                     sizeof(addr_rc.rc_bdaddr));

      addr_rc.rc_channel = get_channel (dev, addr_rc.rc_bdaddr);

      *sendsocket = socket (AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
      if ((-1 < *sendsocket) &&
          (0 == connect (*sendsocket,
                         (struct sockaddr *) &addr_rc,
                         sizeof(addr_rc))))
      {
        neighbours.fds[neighbours.pos++] = *sendsocket;
        connection_successful = 1;
        char addr[19] = { 0 };
        ba2str (&(neighbours.devices[neighbours.pos - 1]), addr);
        fprintf (stderr, "LOG : Connected to %s\n", addr);
        break;
      }
      else
      {
        char addr[19] = { 0 };
        errno_copy = errno;       // Save a copy for later

        if (-1 != *sendsocket)
        {
          (void) close (*sendsocket);
          *sendsocket = -1;
        }
        ba2str (&(neighbours.devices[neighbours.pos]), addr);
        fprintf (stderr,
                 "LOG : Couldn't connect on device %s, error : %s\n",
                 addr,
                 strerror (errno));
        if (errno != ECONNREFUSED)       // FIXME be sure that this works
        {
          fprintf (stderr, "LOG : Removes %d device from the list\n",
                   neighbours.pos);
          /* Remove the device from the list */
          GNUNET_memcpy (&neighbours.devices[neighbours.pos],
                         &neighbours.devices[neighbours.size - 1],
                         sizeof(bdaddr_t));
          memset (&neighbours.devices[neighbours.size - 1], 0,
                  sizeof(bdaddr_t));
          neighbours.fds[neighbours.pos] = neighbours.fds[neighbours.size - 1];
          neighbours.fds[neighbours.size - 1] = -1;
          neighbours.size -= 1;
        }

        neighbours.pos += 1;

        if (neighbours.pos >= neighbours.size)
          neighbours.pos = 0;

        loops += 1;

        if (loops == MAX_LOOPS)       // don't get stuck trying to connect to one device
          return 1;
      }
    }
    else
    {
      fprintf (stderr, "LOG : Search for a new device\n");    // FIXME debugging message
      neighbours.pos += 1;
    }
  }

  /* Cycle on the list */
  if (neighbours.pos == neighbours.size)
  {
    neighbours.pos = 0;
    searching_devices_count += 1;

    if (searching_devices_count == MAX_LOOPS)
    {
      fprintf (stderr, "LOG : Force to inquiry for new devices\n");
      searching_devices_count = 0;
      goto inquiry_devices;
    }
  }
  /* If a new device wasn't found, search an old one */
  if (connection_successful == 0)
  {
    int loop_check = neighbours.pos;
    while (neighbours.fds[neighbours.pos] == -1)
    {
      if (neighbours.pos == neighbours.size)
        neighbours.pos = 0;

      if (neighbours.pos == loop_check)
      {
        if (errno_copy == ECONNREFUSED)
        {
          fprintf (stderr, "LOG : No device found. Go back and search again\n");        // FIXME debugging message
          new_device = 1;
          loops += 1;
          goto search_for_devices;
        }
        else
        {
          return 1;         // Skip the broadcast message
        }
      }

      neighbours.pos += 1;
    }

    *sendsocket = neighbours.fds[neighbours.pos++];
  }

  return 0;
}


#endif

/**
 * Main function of the helper.  This code accesses a bluetooth interface
 * forwards traffic in both directions between the bluetooth interface and
 * stdin/stdout of this process.  Error messages are written to stderr.
 *
 * @param argc number of arguments, must be 2
 * @param argv arguments only argument is the name of the interface (e.g. 'hci0')
 * @return 0 on success (never happens, as we don't return unless aborted), 1 on error
 *
 **** similar to gnunet-helper-transport-wlan.c ****
 */
int
main (int argc, char *argv[])
{
#ifdef __linux__
  struct HardwareInfos dev;
  char readbuf[MAXLINE];
  int maxfd;
  fd_set rfds;
  fd_set wfds;
  int stdin_open;
  struct MessageStreamTokenizer *stdin_mst;
  int raw_eno, i;
  int crt_rfds = 0, rfds_list[MAX_PORTS];
  int broadcast, sendsocket;

  /* Assert privs so we can modify the firewall rules! */
  {
#ifdef HAVE_SETRESUID
    uid_t uid = getuid ();

    if (0 != setresuid (uid, 0, 0))
    {
      fprintf (stderr,
               "Failed to setresuid to root: %s\n",
               strerror (errno));
      return 254;
    }
#else
    if (0 != seteuid (0))
    {
      fprintf (stderr,
               "Failed to seteuid back to root: %s\n", strerror (errno));
      return 254;
    }
#endif
  }

  /* Make use of SGID capabilities on POSIX */
  memset (&dev, 0, sizeof(dev));
  dev.fd_rfcomm = socket (AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
  raw_eno = errno;   /* remember for later */

  /* Now that we've dropped root rights, we can do error checking */
  if (2 != argc)
  {
    fprintf (stderr,
             "You must specify the name of the interface as the first \
                        and only argument to this program.\n");
    if (-1 != dev.fd_rfcomm)
      (void) close (dev.fd_rfcomm);
    return 1;
  }

  if (-1 == dev.fd_rfcomm)
  {
    fprintf (stderr, "Failed to create a RFCOMM socket: %s\n", strerror (
               raw_eno));
    return 1;
  }
  if (dev.fd_rfcomm >= FD_SETSIZE)
  {
    fprintf (stderr, "File descriptor too large for select (%d > %d)\n",
             dev.fd_rfcomm, FD_SETSIZE);
    (void) close (dev.fd_rfcomm);
    return 1;
  }
  if (0 != test_bluetooth_interface (argv[1]))
  {
    (void) close (dev.fd_rfcomm);
    return 1;
  }
  strncpy (dev.iface, argv[1], IFNAMSIZ);
  if (0 != open_device (&dev))
  {
    (void) close (dev.fd_rfcomm);
    return 1;
  }

  /* Drop privs */
  {
    uid_t uid = getuid ();
  #ifdef HAVE_SETRESUID
    if (0 != setresuid (uid, uid, uid))
    {
      fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno));
      if (-1 != dev.fd_rfcomm)
        (void) close (dev.fd_rfcomm);
      return 1;
    }
  #else
    if (0 != (setuid (uid) | seteuid (uid)))
    {
      fprintf (stderr, "Failed to setuid: %s\n", strerror (errno));
      if (-1 != dev.fd_rfcomm)
        (void) close (dev.fd_rfcomm);
      return 1;
    }
  #endif
  }

  /* Send MAC address of the bluetooth interface to STDOUT first */
  {
    struct GNUNET_TRANSPORT_WLAN_HelperControlMessage macmsg;

    macmsg.hdr.size = htons (sizeof(macmsg));
    macmsg.hdr.type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL);
    GNUNET_memcpy (&macmsg.mac, &dev.pl_mac, sizeof(struct
                                                    GNUNET_TRANSPORT_WLAN_MacAddress));
    GNUNET_memcpy (write_std.buf, &macmsg, sizeof(macmsg));
    write_std.size = sizeof(macmsg);
  }


  stdin_mst = mst_create (&stdin_send_hw, &dev);
  stdin_open = 1;

  /**
   * TODO : I should make the time out of a mac endpoint smaller and check if the rate
   * from get_wlan_header (plugin_transport_bluetooth.c) is correct.
   */
  while (1)
  {
    maxfd = -1;
    broadcast = 0;
    sendsocket = -1;

    FD_ZERO (&rfds);
    if ((0 == write_pout.size) && (1 == stdin_open))
    {
      FD_SET (STDIN_FILENO, &rfds);
      maxfd = MAX (maxfd, STDIN_FILENO);
    }
    if (0 == write_std.size)
    {
      FD_SET (dev.fd_rfcomm, &rfds);
      maxfd = MAX (maxfd, dev.fd_rfcomm);
    }

    for (i = 0; i < crt_rfds; i++)    // it can receive messages from multiple devices
    {
      FD_SET (rfds_list[i], &rfds);
      maxfd = MAX (maxfd, rfds_list[i]);
    }
    FD_ZERO (&wfds);
    if (0 < write_std.size)
    {
      FD_SET (STDOUT_FILENO, &wfds);
      maxfd = MAX (maxfd, STDOUT_FILENO);
    }
    if (0 < write_pout.size)   // it can send messages only to one device per loop
    {
      struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *frame;
      /* Get the destination address */
      frame = (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *) write_pout.buf;

      if (memcmp (&frame->addr1, &dev.pl_mac,
                  sizeof(struct GNUNET_TRANSPORT_WLAN_MacAddress)) == 0)
      {
        broadcast = 1;
        memset (&write_pout, 0, sizeof(write_pout));      // clear the buffer
      }
      else if (memcmp (&frame->addr1, &broadcast_address,
                       sizeof(struct GNUNET_TRANSPORT_WLAN_MacAddress)) == 0)
      {
        fprintf (stderr, "LOG : %s has a broadcast message (pos %d, size %d)\n",
                 dev.iface, neighbours.pos, neighbours.size);                                                                      // FIXME: debugging message

        if (send_broadcast (&dev, &sendsocket) != 0)      // if the searching wasn't successful don't get stuck on the select stage
        {
          broadcast = 1;
          memset (&write_pout, 0, sizeof(write_pout));        // remove the message
          fprintf (stderr,
                   "LOG : Skipping the broadcast message (pos %d, size %d)\n",
                   neighbours.pos, neighbours.size);
        }
        else
        {
          FD_SET (sendsocket, &wfds);
          maxfd = MAX (maxfd, sendsocket);
        }
      }
      else
      {
        int found = 0;
        int pos = 0;
        /* Search if the address already exists on the list */
        for (i = 0; i < neighbours.size; i++)
        {
          if (memcmp (&frame->addr1, &(neighbours.devices[i]),
                      sizeof(bdaddr_t)) == 0)
          {
            pos = i;
            if (neighbours.fds[i] != -1)
            {
              found = 1;             // save the position where it was found
              FD_SET (neighbours.fds[i], &wfds);
              maxfd = MAX (maxfd, neighbours.fds[i]);
              sendsocket = neighbours.fds[i];
              fprintf (stderr, "LOG: the address was found in the list\n");
              break;
            }
          }
        }
        if (found == 0)
        {
          int status;
          struct sockaddr_rc addr = { 0 };

          fprintf (stderr,
                   "LOG : %s has a new message for %.2X:%.2X:%.2X:%.2X:%.2X:%.2X which isn't on the broadcast list\n",
                   dev.iface,
                   frame->addr1.mac[5], frame->addr1.mac[4],
                   frame->addr1.mac[3],
                   frame->addr1.mac[2], frame->addr1.mac[1],
                   frame->addr1.mac[0]);                                                  // FIXME: debugging message

          sendsocket = socket (AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);

          if (sendsocket < 0)
          {
            fprintf (stderr,
                     "Failed to create a RFCOMM socket (sending stage): %s\n",
                     strerror (errno));
            return -1;
          }

          GNUNET_memcpy (&addr.rc_bdaddr, &frame->addr1, sizeof(bdaddr_t));
          addr.rc_family = AF_BLUETOOTH;
          addr.rc_channel = get_channel (&dev, addr.rc_bdaddr);

          int tries = 0;
connect_retry:
          status = connect (sendsocket, (struct sockaddr *) &addr,
                            sizeof(addr));
          if ((0 != status) && (errno != EAGAIN) )
          {
            if ((errno == ECONNREFUSED) && (tries < 2) )
            {
              fprintf (stderr, "LOG : %.*s failed to connect. Trying again!\n",
                       IFNAMSIZ, dev.iface);
              tries++;
              goto connect_retry;
            }
            else if (errno == EBADF)
            {
              fprintf (stderr, "LOG : %s failed to connect : %s. Skip it!\n",
                       dev.iface, strerror (errno));
              memset (&write_pout, 0, sizeof(write_pout));
              broadcast = 1;
            }
            else
            {
              fprintf (stderr,
                       "LOG : %s failed to connect : %s. Try again later!\n",
                       dev.iface,
                       strerror (errno));
              memset (&write_pout, 0, sizeof(write_pout));
              broadcast = 1;
            }
          }
          else
          {
            FD_SET (sendsocket, &wfds);
            maxfd = MAX (maxfd, sendsocket);
            fprintf (stderr, "LOG : Connection successful\n");
            if (pos != 0)           // save the socket
            {
              neighbours.fds[pos] = sendsocket;
            }
            else
            {
              /* Add the new device to the discovered devices list */
              if (neighbours.size < MAX_PORTS)
              {
                neighbours.fds[neighbours.size] = sendsocket;
                GNUNET_memcpy (&(neighbours.devices[neighbours.size++]),
                               &addr.rc_bdaddr, sizeof(bdaddr_t));
              }
              else
              {
                fprintf (stderr,
                         "The top limit for the discovarable devices' list was reached\n");
              }
            }
          }
        }
      }
    }

    if (broadcast == 0)
    {
      /* Select a fd which is ready for action :) */
      {
        int retval = select (maxfd + 1, &rfds, &wfds, NULL, NULL);
        if ((-1 == retval) && (EINTR == errno))
          continue;
        if ((0 > retval) && (errno != EBADF) ) // we handle BADF errors later
        {
          fprintf (stderr, "select failed: %s\n", strerror (errno));
          break;
        }
      }
      if (FD_ISSET (STDOUT_FILENO, &wfds))
      {
        ssize_t ret =
          write (STDOUT_FILENO, write_std.buf + write_std.pos,
                 write_std.size - write_std.pos);
        if (0 > ret)
        {
          fprintf (stderr, "Failed to write to STDOUT: %s\n", strerror (errno));
          break;
        }
        write_std.pos += ret;
        if (write_std.pos == write_std.size)
        {
          write_std.pos = 0;
          write_std.size = 0;
        }
        fprintf (stderr, "LOG : %s sends a message to STDOUT\n", dev.iface);      // FIXME: debugging message
      }
      if (-1 != sendsocket)
      {
        if (FD_ISSET (sendsocket, &wfds))
        {
          ssize_t ret = write (sendsocket,
                               write_pout.buf + write_std.pos,
                               write_pout.size - write_pout.pos);
          if (0 > ret)         // FIXME should I first check the error type?
          {
            fprintf (stderr,
                     "Failed to write to bluetooth device: %s. Closing the socket!\n",
                     strerror (errno));
            for (i = 0; i < neighbours.size; i++)
            {
              if (neighbours.fds[i] == sendsocket)
              {
                (void) close (sendsocket);
                neighbours.fds[i] = -1;
                break;
              }
            }
            /* Remove the message */
            memset (&write_pout.buf + write_std.pos, 0, (write_pout.size
                                                         - write_pout.pos));
            write_pout.pos = 0;
            write_pout.size = 0;
          }
          else
          {
            write_pout.pos += ret;
            if ((write_pout.pos != write_pout.size) && (0 != ret))
            {
              /* We should not get partial sends with packet-oriented devices... */
              fprintf (stderr, "Write error, partial send: %u/%u\n",
                       (unsigned int) write_pout.pos,
                       (unsigned int) write_pout.size);
              break;
            }

            if (write_pout.pos == write_pout.size)
            {
              write_pout.pos = 0;
              write_pout.size = 0;
            }
            fprintf (stderr, "LOG : %s sends a message to a DEVICE\n",
                     dev.iface);                                                            // FIXME: debugging message
          }
        }
      }
      for (i = 0; i <= maxfd; i++)
      {
        if (FD_ISSET (i, &rfds))
        {
          if (i == STDIN_FILENO)
          {
            ssize_t ret =
              read (i, readbuf, sizeof(readbuf));
            if (0 > ret)
            {
              fprintf (stderr,
                       "Read error from STDIN: %s\n",
                       strerror (errno));
              break;
            }
            if (0 == ret)
            {
              /* stop reading... */
              stdin_open = 0;
            }
            else
            {
              mst_receive (stdin_mst, readbuf, ret);
              fprintf (stderr, "LOG : %s receives a message from STDIN\n",
                       dev.iface);                                                                // FIXME: debugging message
            }
          }
          else if (i == dev.fd_rfcomm)
          {
            int readsocket;
            struct sockaddr_rc addr = { 0 };
            unsigned int opt = sizeof(addr);

            readsocket = accept (dev.fd_rfcomm, (struct sockaddr *) &addr,
                                 &opt);
            fprintf (stderr, "LOG : %s accepts a message\n", dev.iface);          // FIXME: debugging message
            if (readsocket == -1)
            {
              fprintf (stderr,
                       "Failed to accept a connection on interface: %.*s\n",
                       IFNAMSIZ,
                       strerror (errno));
              break;
            }
            else
            {
              FD_SET (readsocket, &rfds);
              maxfd = MAX (maxfd, readsocket);

              if (crt_rfds < MAX_PORTS)
                rfds_list[crt_rfds++] = readsocket;
              else
              {
                fprintf (stderr,
                         "The limit for the read file descriptors list was \
                                  reached\n");
                break;
              }
            }
          }
          else
          {
            struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *rrm;
            ssize_t ret;
            fprintf (stderr, "LOG : %s reads something from the socket\n",
                     dev.iface);                                                               // FIXME : debugging message
            rrm = (struct
                   GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *) write_std.buf;
            ret =
              read_from_the_socket ((void *) &i, (unsigned char *) &rrm->frame,
                                    sizeof(write_std.buf)
                                    - sizeof(struct
                                             GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)
                                    + sizeof(struct
                                             GNUNET_TRANSPORT_WLAN_Ieee80211Frame),
                                    rrm);
            if (0 >= ret)
            {
              int j;
              FD_CLR (i, &rfds);
              close (i);
              /* Remove the socket from the list */
              for (j = 0; j < crt_rfds; j++)
              {
                if (rfds_list[j] == i)
                {
                  rfds_list[j] ^= rfds_list[crt_rfds - 1];
                  rfds_list[crt_rfds - 1] ^= rfds_list[j];
                  rfds_list[j] ^= rfds_list[crt_rfds - 1];
                  crt_rfds -= 1;
                  break;
                }
              }

              fprintf (stderr, "Read error from raw socket: %s\n", strerror (
                         errno));
              break;
            }
            if ((0 < ret) && (0 == mac_test (&rrm->frame, &dev)))
            {
              write_std.size = ret
                               + sizeof(struct
                                        GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)
                               - sizeof(struct
                                        GNUNET_TRANSPORT_WLAN_Ieee80211Frame);
              rrm->header.size = htons (write_std.size);
              rrm->header.type = htons (
                GNUNET_MESSAGE_TYPE_WLAN_DATA_FROM_HELPER);
            }
          }
        }
      }
    }
  }
  /* Error handling, try to clean up a bit at least */
  mst_destroy (stdin_mst);
  stdin_mst = NULL;
  sdp_close (dev.session);
  (void) close (dev.fd_rfcomm);
  if (-1 != sendsocket)
    (void) close (sendsocket);

  for (i = 0; i < crt_rfds; i++)
    (void) close (rfds_list[i]);

  for (i = 0; i < neighbours.size; i++)
    (void) close (neighbours.fds[i]);
  #else
  struct HardwareInfos dev;
  struct GNUNET_NETWORK_Handle *sendsocket;
  struct GNUNET_NETWORK_FDSet *rfds;
  struct GNUNET_NETWORK_FDSet *wfds;
  struct GNUNET_NETWORK_Handle *rfds_list[MAX_PORTS];
  char readbuf[MAXLINE] = { 0 };
  SOCKADDR_BTH acc_addr = { 0 };
  int addr_len = sizeof(SOCKADDR_BTH);
  int broadcast, i, stdin_open, crt_rfds = 0;
  HANDLE stdin_handle = GetStdHandle (STD_INPUT_HANDLE);
  HANDLE stdout_handle = GetStdHandle (STD_OUTPUT_HANDLE);
  struct MessageStreamTokenizer *stdin_mst;

  /* check the handles */
  if (stdin_handle == INVALID_HANDLE_VALUE)
  {
    fprintf (stderr, "Failed to get the stdin handle\n");
    ExitProcess (2);
  }

  if (stdout_handle == INVALID_HANDLE_VALUE)
  {
    fprintf (stderr, "Failed to get the stdout handle\n");
    ExitProcess (2);
  }

  /* initialize windows sockets */
  initialize_windows_sockets ();

  // /* test bluetooth socket family support */ --> it return false because the GNUNET_NETWORK_test_pf should also receive the type of socket (BTHPROTO_RFCOMM)
  // if (GNUNET_NETWORK_test_pf (AF_BTH) != GNUNET_OK)
  // {
  //   fprintf (stderr, "AF_BTH family is not supported\n");
  //   ExitProcess (2);
  // }

  /* create the socket */
  dev.handle = GNUNET_NETWORK_socket_create (AF_BTH, SOCK_STREAM,
                                             BTHPROTO_RFCOMM);
  if (dev.handle == NULL)
  {
    fprintf (stderr, "Failed to create RFCOMM socket: ");
    print_last_error ();
    ExitProcess (2);
  }


  if (open_device (&dev) == -1)
  {
    fprintf (stderr, "Failed to open the device\n");
    print_last_error ();
    if (GNUNET_NETWORK_socket_close (dev.handle) != GNUNET_OK)
    {
      fprintf (stderr, "Failed to close the socket!\n");
      print_last_error ();
    }
    ExitProcess (2);
  }

  if (GNUNET_OK != GNUNET_NETWORK_socket_set_blocking (dev.handle, 1))
  {
    fprintf (stderr, "Failed to change the socket mode\n");
    ExitProcess (2);
  }

  memset (&write_std, 0, sizeof(write_std));
  memset (&write_pout, 0, sizeof(write_pout));
  stdin_open = 1;

  rfds = GNUNET_NETWORK_fdset_create ();
  wfds = GNUNET_NETWORK_fdset_create ();

  /* Send MAC address of the bluetooth interface to STDOUT first */
  {
    struct GNUNET_TRANSPORT_WLAN_HelperControlMessage macmsg;

    macmsg.hdr.size = htons (sizeof(macmsg));
    macmsg.hdr.type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL);
    GNUNET_memcpy (&macmsg.mac, &dev.pl_mac, sizeof(struct
                                                    GNUNET_TRANSPORT_WLAN_MacAddress_Copy));
    GNUNET_memcpy (write_std.buf, &macmsg, sizeof(macmsg));
    write_std.size = sizeof(macmsg);
  }


  stdin_mst = mst_create (&stdin_send_hw, &dev);
  stdin_open = 1;

  int pos = 0;
  int stdin_pos = -1;
  int stdout_pos = -1;
  while (1)
  {
    broadcast = 0;
    pos = 0;
    stdin_pos = -1;
    stdout_pos = -1;
    sendsocket = NULL;   // FIXME ???memleaks

    GNUNET_NETWORK_fdset_zero (rfds);
    if ((0 == write_pout.size) && (1 == stdin_open))
    {
      stdin_pos = pos;
      pos += 1;
      GNUNET_NETWORK_fdset_handle_set (rfds, (struct
                                              GNUNET_DISK_FileHandle*) &
                                       stdin_handle);
    }

    if (0 == write_std.size)
    {
      pos += 1;
      GNUNET_NETWORK_fdset_set (rfds, dev.handle);
    }

    for (i = 0; i < crt_rfds; i++)
    {
      pos += 1;
      GNUNET_NETWORK_fdset_set (rfds, rfds_list[i]);
    }

    GNUNET_NETWORK_fdset_zero (wfds);
    if (0 < write_std.size)
    {
      stdout_pos = pos;
      GNUNET_NETWORK_fdset_handle_set (wfds, (struct
                                              GNUNET_DISK_FileHandle*) &
                                       stdout_handle);
      // printf ("%s\n", write_std.buf);
      // memset (write_std.buf, 0, write_std.size);
      // write_std.size = 0;
    }

    if (0 < write_pout.size)
    {
      if (strcmp (argv[1], "ff:ff:ff:ff:ff:ff") == 0)
      {
        fprintf (stderr, "LOG: BROADCAST! Skipping the message\n");
        // skip the message
        broadcast = 1;
        memset (write_pout.buf, 0, write_pout.size);
        write_pout.size = 0;
      }
      else
      {
        SOCKADDR_BTH addr;
        fprintf (stderr, "LOG : has a new message for %s\n", argv[1]);
        sendsocket = GNUNET_NETWORK_socket_create (AF_BTH, SOCK_STREAM,
                                                   BTHPROTO_RFCOMM);

        if (sendsocket == NULL)
        {
          fprintf (stderr, "Failed to create RFCOMM socket: \n");
          print_last_error ();
          ExitProcess (2);
        }

        memset (&addr, 0, sizeof(addr));
        // addr.addressFamily = AF_BTH;
        if (SOCKET_ERROR ==
            WSAStringToAddress (argv[1], AF_BTH, NULL, (LPSOCKADDR) &addr,
                                &addr_len))
        {
          fprintf (stderr, "Failed to translate the address: ");
          print_last_error ();
          ExitProcess (2);
        }
        addr.port = get_channel (argv[1]);
        if (addr.port == -1)
        {
          fprintf (stderr,
                   "Couldn't find the sdp service for the address: %s\n",
                   argv[1]);
          memset (write_pout.buf, 0, write_pout.size);
          write_pout.size = 0;
          broadcast = 1;         // skipping the select part
        }
        else
        {
          if (GNUNET_OK != GNUNET_NETWORK_socket_connect (sendsocket,
                                                          (LPSOCKADDR) &addr,
                                                          addr_len))
          {
            fprintf (stderr, "Failed to connect: ");
            print_last_error ();
            ExitProcess (2);
          }

          if (GNUNET_OK != GNUNET_NETWORK_socket_set_blocking (sendsocket, 1))
          {
            fprintf (stderr, "Failed to change the socket mode\n");
            ExitProcess (2);
          }

          GNUNET_NETWORK_fdset_set (wfds, sendsocket);
        }
      }
    }

    if (broadcast == 0)
    {
      int retval = GNUNET_NETWORK_socket_select (rfds, wfds, NULL,
                                                 GNUNET_TIME_relative_get_forever_ ());
      if (retval < 0)
      {
        fprintf (stderr, "Select error\n");
        ExitProcess (2);
      }
      // if (GNUNET_NETWORK_fdset_isset (wfds, (struct GNUNET_NETWORK_Handle*)&stdout_handle))
      if (retval == stdout_pos)
      {
        fprintf (stderr, "LOG : sends a message to STDOUT\n");      // FIXME: debugging message
        // ssize_t ret;
        // ret = GNUNET_NETWORK_socket_send ((struct GNUNET_NETWORK_Handle *)&stdout_handle,  write_std.buf + write_std.pos, write_std.size - write_std.pos);
        // ret = write (STDOUT_FILENO, write_std.buf + write_std.pos,  write_std.size - write_std.pos);
        DWORD ret;
        if (FALSE == WriteFile (stdout_handle, write_std.buf + write_std.pos,
                                write_std.size - write_std.pos, &ret, NULL))
        {
          fprintf (stderr, "Failed to write to STDOUT: ");
          print_last_error ();
          break;
        }

        if (ret <= 0)
        {
          fprintf (stderr, "Failed to write to STDOUT\n");
          ExitProcess (2);
        }

        write_std.pos += ret;
        if (write_std.pos == write_std.size)
        {
          write_std.pos = 0;
          write_std.size = 0;
        }
      }
      if (sendsocket != NULL)
      {
        if (GNUNET_NETWORK_fdset_isset (wfds, sendsocket))
        {
          ssize_t ret;
          ret = GNUNET_NETWORK_socket_send (sendsocket, write_pout.buf
                                            + write_pout.pos,
                                            write_pout.size - write_pout.pos);

          if (GNUNET_SYSERR == ret)
          {
            fprintf (stderr,
                     "Failed to send to the socket. Closing the socket. Error: \n");
            print_last_error ();
            if (GNUNET_NETWORK_socket_close (sendsocket) != GNUNET_OK)
            {
              fprintf (stderr, "Failed to close the sendsocket!\n");
              print_last_error ();
            }
            ExitProcess (2);
          }
          else
          {
            write_pout.pos += ret;
            if ((write_pout.pos != write_pout.size) && (0 != ret))
            {
              /* we should not get partial sends with packet-oriented devices... */
              fprintf (stderr, "Write error, partial send: %u/%u\n",
                       (unsigned int) write_pout.pos,
                       (unsigned int) write_pout.size);
              break;
            }

            if (write_pout.pos == write_pout.size)
            {
              write_pout.pos = 0;
              write_pout.size = 0;
            }
            fprintf (stderr, "LOG : sends a message to a DEVICE\n");          // FIXME: debugging message
          }
        }
      }

      // if (GNUNET_NETWORK_fdset_isset (rfds, (struct GNUNET_NETWORK_Handle*)&stdin_handle))
      if (retval == stdin_pos)
      {
        // ssize_t ret;
        // ret = GNUNET_NETWORK_socket_recv ((struct GNUNET_NETWORK_Handle *)&stdin_handle, readbuf, sizeof (write_pout.buf));
        // ret = read (STDIN_FILENO, readbuf, sizeof (readbuf));
        DWORD ret;
        if (FALSE == ReadFile (stdin_handle, readbuf, sizeof(readbuf), &ret,
                               NULL))                                                    /* do nothing asynchronous */
        {
          fprintf (stderr, "Read error from STDIN: ");
          print_last_error ();
          break;
        }
        if (0 == ret)
        {
          /* stop reading... */
          stdin_open = 0;
        }
        else
        {
          mst_receive (stdin_mst, readbuf, ret);
          fprintf (stderr, "LOG : receives a message from STDIN\n");        // FIXME: debugging message
        }
      }
      else if (GNUNET_NETWORK_fdset_isset (rfds, dev.handle))
      {
        fprintf (stderr, "LOG: accepting connection\n");
        struct GNUNET_NETWORK_Handle *readsocket;
        readsocket = GNUNET_NETWORK_socket_accept (dev.handle,
                                                   (LPSOCKADDR) &acc_addr,
                                                   &addr_len);
        if (readsocket == NULL)
        {
          fprintf (stderr, "Accept error %d: ", GetLastError ());
          print_last_error ();
          ExitProcess (2);
        }
        else
        {
          if (GNUNET_OK != GNUNET_NETWORK_socket_set_blocking (readsocket, 1))
          {
            fprintf (stderr, "Failed to change the socket mode\n");
            ExitProcess (2);
          }
          GNUNET_NETWORK_fdset_set (rfds, readsocket);

          if (crt_rfds < MAX_PORTS)
            rfds_list[crt_rfds++] = readsocket;
          else
          {
            fprintf (stderr,
                     "The limit for the read file descriptors list was reached\n");
            break;
          }
        }
      }
      else
        for (i = 0; i < crt_rfds; i++)
        {
          if (GNUNET_NETWORK_fdset_isset (rfds, rfds_list[i]))
          {
            struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *rrm;
            ssize_t ret;
            fprintf (stderr, "LOG: reading something from the socket\n");       // FIXME : debugging message
            rrm = (struct
                   GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *) write_std.buf;
            ret = read_from_the_socket (rfds_list[i], (unsigned
                                                       char *) &rrm->frame,
                                        sizeof(write_std.buf)
                                        - sizeof(struct
                                                 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)
                                        + sizeof(struct
                                                 GNUNET_TRANSPORT_WLAN_Ieee80211Frame),
                                        rrm);
            if (0 >= ret)
            {
              // TODO remove the socket from the list
              if (GNUNET_NETWORK_socket_close (rfds_list[i]) != GNUNET_OK)
              {
                fprintf (stderr, "Failed to close the sendsocket!\n");
                print_last_error ();
              }

              fprintf (stderr, "Read error from raw socket: ");
              print_last_error ();
              break;
            }
            if ((0 < ret) && (0 == mac_test (&rrm->frame, &dev)))
            {
              write_std.size = ret
                               + sizeof(struct
                                        GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)
                               - sizeof(struct
                                        GNUNET_TRANSPORT_WLAN_Ieee80211Frame);
              rrm->header.size = htons (write_std.size);
              rrm->header.type = htons (
                GNUNET_MESSAGE_TYPE_WLAN_DATA_FROM_HELPER);
            }
            break;
          }
        }
    }
  }

  mst_destroy (stdin_mst);
  stdin_mst = NULL;

  if (GNUNET_NETWORK_socket_close (dev.handle) != GNUNET_OK)
  {
    fprintf (stderr, "Failed to close the socket!\n");
    print_last_error ();
  }

  for (i = 0; i < crt_rfds; i++)
  {
    if (GNUNET_NETWORK_socket_close (rfds_list[i]) != GNUNET_OK)
    {
      fprintf (stderr, "Failed to close the socket!\n");
      print_last_error ();
    }
  }

  WSACleanup ();
  #endif
  return 1;                     /* we never exit 'normally' */
}
