Exemple #1
0
/**
 * Finish a DLEP signal/message
 * @param writer dlep writer
 * @param source logging source for error messages
 * @return -1 if an error happened, 0 otherwise
 */
int
dlep_writer_finish_signal(struct dlep_writer *writer,
    enum oonf_log_source source) {
  size_t length;
  uint16_t tmp16;
  char *dst;

  if (abuf_has_failed(writer->out)) {
    OONF_WARN(source, "Could not build signal: %u",
        writer->signal_type);
    return -1;
  }

  length = abuf_getlen(writer->out) - writer->signal_start;
  if (length > 65535 + 4) {
    OONF_WARN(source, "Signal %u became too long: %" PRINTF_SIZE_T_SPECIFIER,
        writer->signal_type, abuf_getlen(writer->out));
    return -1;
  }

  /* calculate network ordered size */
  tmp16 = htons(length - 4);

  /* put it into the signal */
  dst = abuf_getptr(writer->out);
  memcpy(&dst[writer->signal_start + 2], &tmp16, sizeof(tmp16));

  OONF_DEBUG_HEX(source, &dst[writer->signal_start], length,
      "Finished signal %u:", writer->signal_type);
  return 0;
}
Exemple #2
0
/**
 * Callback to send multicast over interface
 * @param session dlep session
 * @param af_family address family for multicast
 */
static void
_cb_send_multicast(struct dlep_session *session, int af_family) {
  struct dlep_if *interf;

  if (abuf_getlen(session->writer.out) <= sizeof(_DLEP_PREFIX) - 1
      || !netaddr_socket_is_unspec(&session->remote_socket)) {
    return;
  }

  /* get pointer to radio interface */
  interf = container_of(session, struct dlep_if, session);

  if (interf->session_tree.count > 0
      && interf->single_session) {
    /* do not produce UDP traffic as long as we are connected */
    return;
  }

  OONF_DEBUG(session->log_source, "Send multicast %"
      PRINTF_SIZE_T_SPECIFIER " bytes",
      abuf_getlen(session->writer.out));

  oonf_packet_send_managed_multicast(&interf->udp,
      abuf_getptr(session->writer.out), abuf_getlen(session->writer.out),
      af_family);

  abuf_clear(session->writer.out);

  /* add dlep prefix to buffer */
  abuf_memcpy(session->writer.out, _DLEP_PREFIX, sizeof(_DLEP_PREFIX) - 1);
}
Exemple #3
0
/**
 * Start to write a new DLEP signal/message into a buffer
 * @param writer dlep writer
 * @param signal_type signal/message type
 */
void
dlep_writer_start_signal(struct dlep_writer *writer, uint16_t signal_type) {
  writer->signal_type = signal_type;
  writer->signal_start = abuf_getlen(writer->out);

  abuf_append_uint16(writer->out, htons(signal_type));
  abuf_append_uint16(writer->out, 0);
}
Exemple #4
0
/**
 * Send a data packet through a packet socket. The transmission might not
 * be happen synchronously if the socket would block.
 * @param pktsocket pointer to packet socket
 * @param remote ip/address to send packet to
 * @param data pointer to data to be sent
 * @param length length of data
 * @return -1 if an error happened, 0 otherwise
 */
int
oonf_packet_send(struct oonf_packet_socket *pktsocket, union netaddr_socket *remote,
    const void *data, size_t length) {
  int result;
  struct netaddr_str buf;

  if (abuf_getlen(&pktsocket->out) == 0) {
    /* no backlog of outgoing packets, try to send directly */
    result = os_fd_sendto(&pktsocket->scheduler_entry.fd, data, length, remote,
        pktsocket->config.dont_route);
    if (result > 0) {
      /* successful */
      OONF_DEBUG(LOG_PACKET, "Sent %d bytes to %s %s",
          result, netaddr_socket_to_string(&buf, remote),
          pktsocket->os_if != NULL ? pktsocket->os_if->name : "");
      return 0;
    }

    if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK) {
      OONF_WARN(LOG_PACKET, "Cannot send UDP packet to %s: %s (%d)",
          netaddr_socket_to_string(&buf, remote), strerror(errno), errno);
      return -1;
    }
  }

  /* append destination */
  abuf_memcpy(&pktsocket->out, remote, sizeof(*remote));

  /* append data length */
  abuf_append_uint16(&pktsocket->out, length);

  /* append data */
  abuf_memcpy(&pktsocket->out, data, length);

  /* activate outgoing socket scheduler */
  oonf_socket_set_write(&pktsocket->scheduler_entry, true);
  return 0;
}
Exemple #5
0
/**
 * Callback to handle data from the olsr socket scheduler
 * @param fd filedescriptor to read data from
 * @param data custom data pointer
 * @param event_read true if read-event is incoming
 * @param event_write true if write-event is incoming
 */
static void
_cb_packet_event(struct oonf_socket_entry *entry,
    bool multicast __attribute__((unused))) {
  struct oonf_packet_socket *pktsocket;
  union netaddr_socket sock;
  uint16_t length;
  char *pkt;
  ssize_t result;
  struct netaddr_str netbuf;

#ifdef OONF_LOG_DEBUG_INFO
  const char *interf = "";
#endif

  pktsocket = container_of(entry, typeof(*pktsocket), scheduler_entry);

#ifdef OONF_LOG_DEBUG_INFO
  if (pktsocket->os_if) {
    interf = pktsocket->os_if->name;
  }
#endif

  if (oonf_socket_is_read(entry)) {
    uint8_t *buf;

    /* clear recvfrom memory */
    memset(&sock, 0, sizeof(sock));

    /* handle incoming data */
    buf = pktsocket->config.input_buffer;

    result = os_fd_recvfrom(&entry->fd,
        buf, pktsocket->config.input_buffer_length-1, &sock,
        pktsocket->os_if);
    if (result > 0 && pktsocket->config.receive_data != NULL) {
      /* handle raw socket */
      if (pktsocket->protocol) {
        buf = os_fd_skip_rawsocket_prefix(buf, &result, pktsocket->local_socket.std.sa_family);
        if (!buf) {
          OONF_WARN(LOG_PACKET, "Error while skipping IP header for socket %s:",
              netaddr_socket_to_string(&netbuf, &pktsocket->local_socket));
          return;
        }
      }
      /* null terminate it */
      buf[result] = 0;

      /* received valid packet */
      OONF_DEBUG(LOG_PACKET, "Received %"PRINTF_SSIZE_T_SPECIFIER" bytes from %s %s (%s)",
          result, netaddr_socket_to_string(&netbuf, &sock),
          interf, multicast ? "multicast" : "unicast");
      pktsocket->config.receive_data(pktsocket, &sock, buf, result);
    }
    else if (result < 0 && (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK)) {
      OONF_WARN(LOG_PACKET, "Cannot read packet from socket %s: %s (%d)",
          netaddr_socket_to_string(&netbuf, &pktsocket->local_socket), strerror(errno), errno);
    }
  }

  if (oonf_socket_is_write(entry) && abuf_getlen(&pktsocket->out) > 0) {
    /* handle outgoing data */
    pkt = abuf_getptr(&pktsocket->out);

    /* copy remote socket */
    memcpy(&sock, pkt, sizeof(sock));
    pkt += sizeof(sock);

    /* copy length */
    memcpy(&length, pkt, 2);
    pkt += 2;

    /* try to send packet */
    result = os_fd_sendto(&entry->fd, pkt, length, &sock, pktsocket->config.dont_route);
    if (result < 0 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)) {
      /* try again later */
      OONF_DEBUG(LOG_PACKET, "Sending to %s %s could block, try again later",
          netaddr_socket_to_string(&netbuf, &sock), interf);
      return;
    }

    if (result < 0) {
      /* display error message */
      OONF_WARN(LOG_PACKET, "Cannot send UDP packet to %s: %s (%d)",
          netaddr_socket_to_string(&netbuf, &sock), strerror(errno), errno);
    }
    else {
      OONF_DEBUG(LOG_PACKET, "Sent %"PRINTF_SSIZE_T_SPECIFIER" bytes to %s %s",
          result, netaddr_socket_to_string(&netbuf, &sock), interf);
    }
    /* remove data from outgoing buffer (both for success and for final error */
    abuf_pull(&pktsocket->out, sizeof(sock) + 2 + length);
  }

  if (abuf_getlen(&pktsocket->out) == 0) {
    /* nothing left to send, disable outgoing events */
    oonf_socket_set_write(&pktsocket->scheduler_entry, false);
  }
}
Exemple #6
0
/**
 * Callback to receive UDP data through oonf_packet_managed API
 * @param pkt packet socket
 * @param from network socket the packet was received from
 * @param ptr pointer to packet data
 * @param length length of packet data
 */
static void
_cb_receive_udp(struct oonf_packet_socket *pkt,
    union netaddr_socket *from, void *ptr, size_t length) {
  struct dlep_if *interf;
  uint8_t *buffer;
  ssize_t processed;
  struct netaddr_str nbuf;

  interf = pkt->config.user;
  buffer = ptr;

  if (interf->session_tree.count > 0
      && interf->single_session) {
    /* ignore UDP traffic as long as we have a connection */
    return;
  }

  if (length < sizeof(_DLEP_PREFIX) - 1) {
    /* ignore unknown prefix */
    return;
  }

  if (memcmp(buffer, _DLEP_PREFIX, sizeof(_DLEP_PREFIX)-1) != 0) {
    OONF_WARN(interf->session.log_source,
        "Incoming UDP packet with unknown signature");
    return;
  }

  /* advance pointer and fix length */
  buffer += (sizeof(_DLEP_PREFIX) - 1);
  length -= (sizeof(_DLEP_PREFIX) - 1);

  /* copy socket information */
  memcpy(&interf->session.remote_socket, from,
      sizeof(interf->session.remote_socket));

  processed = dlep_session_process_buffer(&interf->session, buffer, length);
  if (processed < 0) {
    return ;
  }

  if ((size_t)processed < length) {
    OONF_WARN(interf->session.log_source,
        "Received malformed or too short UDP packet from %s",
        netaddr_socket_to_string(&nbuf, from));
    /* incomplete or bad packet, just ignore it */
    return;
  }

  if (abuf_getlen(interf->session.writer.out) > sizeof(_DLEP_PREFIX) - 1) {
    /* send an unicast response */
    oonf_packet_send_managed(&interf->udp, from,
        abuf_getptr(interf->session.writer.out),
        abuf_getlen(interf->session.writer.out));
    abuf_clear(interf->session.writer.out);

    /* add dlep prefix to buffer */
    abuf_memcpy(interf->session.writer.out,
        _DLEP_PREFIX, sizeof(_DLEP_PREFIX) - 1);
  }

  netaddr_socket_invalidate(&interf->session.remote_socket);
}