Пример #1
0
/**
 * Join a socket into a multicast group
 * @param sock filedescriptor of socket
 * @param multicast multicast-group to join
 * @param os_if pointer to outgoing interface data for multicast
 * @param log_src logging source for error messages
 * @return -1 if an error happened, 0 otherwise
 */
int
os_fd_generic_join_mcast_recv(struct os_fd *sock,
    const struct netaddr *multicast,
    const struct os_interface *os_if,
    enum oonf_log_source log_src __attribute__((unused))) {
  struct netaddr_str buf1, buf2;
  struct ip_mreq   v4_mreq;
  struct ipv6_mreq v6_mreq;
  const char *ifname = "*";

  if (os_if) {
    ifname = os_if->name;
  }

  if (netaddr_get_address_family(multicast) == AF_INET) {
    const struct netaddr *src;

    src = os_if == NULL ? &NETADDR_IPV4_ANY : os_if->if_v4;

    OONF_DEBUG(log_src,
        "Socket on interface %s joining receiving multicast %s (src %s)\n",
        ifname, netaddr_to_string(&buf2, multicast),
        netaddr_to_string(&buf1, src));

    netaddr_to_binary(&v4_mreq.imr_multiaddr, multicast, 4);
    netaddr_to_binary(&v4_mreq.imr_interface, src, 4);

    if (setsockopt(sock->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
        &v4_mreq, sizeof(v4_mreq)) < 0) {
      OONF_WARN(log_src, "Cannot join multicast group %s (src %s) on interface %s: %s (%d)\n",
          netaddr_to_string(&buf1, multicast),
          netaddr_to_string(&buf2, src),
          ifname, strerror(errno), errno);
      return -1;
    }
  }
  else {
    int if_index;

    if_index = os_if == NULL ? 0 : os_if->index;

    OONF_DEBUG(log_src,
        "Socket on interface %s joining receiving multicast %s (if %d)\n",
        ifname, netaddr_to_string(&buf2, multicast), if_index);

    netaddr_to_binary(&v6_mreq.ipv6mr_multiaddr, multicast, 16);
    v6_mreq.ipv6mr_interface = if_index;

    if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
        &v6_mreq, sizeof(v6_mreq)) < 0) {
      OONF_WARN(log_src, "Cannot join multicast group %s on interface %s: %s (%d)\n",
          netaddr_to_string(&buf1, multicast),
          ifname,
          strerror(errno), errno);
      return -1;
    }
  }
  return 0;
}
Пример #2
0
/**
 * Join a socket into a multicast group
 * @param sock filedescriptor of socket
 * @param multicast multicast ip/port to join
 * @param os_if pointer to outgoing interface data for multicast
 * @param loop true if multicast loop should be activated, false otherwise
 * @param log_src logging source for error messages
 * @return -1 if an error happened, 0 otherwise
 */
int
os_fd_generic_join_mcast_send(struct os_fd *sock,
    const struct netaddr *multicast,
    const struct os_interface *os_if, bool loop,
    enum oonf_log_source log_src __attribute__((unused))) {
  struct netaddr_str buf1, buf2;
  unsigned i;

  if (netaddr_get_address_family(multicast) == AF_INET) {
    OONF_DEBUG(log_src,
        "Socket on interface %s joining sending multicast %s (src %s)\n",
        os_if->name,
        netaddr_to_string(&buf2, multicast),
        netaddr_to_string(&buf1, os_if->if_v4));

    if (setsockopt(sock->fd, IPPROTO_IP, IP_MULTICAST_IF, netaddr_get_binptr(os_if->if_v4), 4) < 0) {
      OONF_WARN(log_src, "Cannot set multicast %s on interface %s (src %s): %s (%d)\n",
          netaddr_to_string(&buf2, multicast),
          os_if->name,
          netaddr_to_string(&buf1, os_if->if_v4),
          strerror(errno), errno);
      return -1;
    }

    i = loop ? 1 : 0;
    if(setsockopt(sock->fd, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&i, sizeof(i)) < 0) {
      OONF_WARN(log_src, "Cannot %sactivate local loop of multicast interface: %s (%d)\n",
          loop ? "" : "de", strerror(errno), errno);
      return -1;
    }
  }
  else {
    OONF_DEBUG(log_src,
        "Socket on interface %s (%d) joining sending multicast %s (src %s)\n",
        os_if->name, os_if->index,
        netaddr_to_string(&buf2, multicast),
        netaddr_to_string(&buf1, os_if->if_linklocal_v6));

    if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
        &os_if->index, sizeof(os_if->index)) < 0) {
      OONF_WARN(log_src, "Cannot set multicast %s on interface %s (src %s): %s (%d)\n",
          netaddr_to_string(&buf2, multicast),
          os_if->name,
          netaddr_to_string(&buf1, os_if->if_linklocal_v6),
          strerror(errno), errno);
      return -1;
    }

    i = loop ? 1 : 0;
    if(setsockopt(sock->fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &i, sizeof(i)) < 0) {
      OONF_WARN(log_src, "Cannot deactivate local loop of multicast interface: %s (%d)\n",
          strerror(errno), errno);
      return -1;
    }
  }
  return 0;
}
Пример #3
0
/**
 * Apply a new configuration to a managed socket. This might close and
 * reopen sockets because of changed binding IPs or ports.
 * @param managed pointer to managed packet socket
 * @param config pointer to new configuration
 * @return -1 if an error happened, 0 otherwise
 */
int
oonf_packet_apply_managed(struct oonf_packet_managed *managed,
    const struct oonf_packet_managed_config *config) {
  bool if_changed;
  int result;

  if_changed = strcmp(config->interface, managed->_managed_config.interface) != 0
      || !list_is_node_added(&managed->_if_listener._node);

  oonf_packet_copy_managed_config(&managed->_managed_config, config);

  /* handle change in interface listener */
  if (if_changed) {
    /* interface changed, remove old listener if necessary */
    os_interface_remove(&managed->_if_listener);

    /* create new interface listener */
    managed->_if_listener.mesh = managed->_managed_config.mesh;
    os_interface_add(&managed->_if_listener);
  }

  OONF_DEBUG(LOG_PACKET, "Apply changes for managed socket (if %s) with port %d/%d",
      config->interface[0] == 0 ? "any" : config->interface,
      config->port, config->multicast_port);

  result = _apply_managed(managed);
  if (result) {
    /* did not work, trigger interface handler to try later again */
    os_interface_trigger_handler(&managed->_if_listener);
  }
  return result;
}
Пример #4
0
/**
 * Send a packet out over one of the managed sockets, depending on the
 * address family type of the remote address
 * @param managed pointer to managed packet socket
 * @param remote pointer to remote socket
 * @param data pointer to data to send
 * @param length length of data
 * @return -1 if an error happened, 0 if packet was sent, 1 if this
 *    type of address was switched off
 */
int
oonf_packet_send_managed(struct oonf_packet_managed *managed,
    union netaddr_socket *remote, const void *data, size_t length) {
#ifdef OONF_LOG_DEBUG_INFO
  struct netaddr_str buf;
#endif

  if (netaddr_socket_get_addressfamily(remote) == AF_UNSPEC) {
    return 0;
  }

  if (list_is_node_added(&managed->socket_v4.scheduler_entry._node)
      && netaddr_socket_get_addressfamily(remote) == AF_INET) {
    return oonf_packet_send(&managed->socket_v4, remote, data, length);
  }
  if (list_is_node_added(&managed->socket_v6.scheduler_entry._node)
      && netaddr_socket_get_addressfamily(remote) == AF_INET6) {
    return oonf_packet_send(&managed->socket_v6, remote, data, length);
  }
  errno = 0;
  OONF_DEBUG(LOG_PACKET,
      "Managed socket did not sent packet to %s because socket was not active",
      netaddr_socket_to_string(&buf, remote));

  return 0;
}
Пример #5
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);
}
Пример #6
0
/**
 * Remove dlep router interface
 * @param interface dlep router interface
 */
void
dlep_if_remove(struct dlep_if *interface) {
  struct dlep_extension *ext;

  OONF_DEBUG(interface->session.log_source,
      "remove session %s", interface->l2_ifname);

  avl_for_each_element(dlep_extension_get_tree(), ext, _node) {
    if (interface->session.radio) {
      if (ext->cb_session_cleanup_radio) {
        ext->cb_session_cleanup_radio(&interface->session);
      }
    }
    else {
      if (ext->cb_session_cleanup_router) {
        ext->cb_session_cleanup_router(&interface->session);
      }
    }
  }

  /* close UDP interface */
  oonf_packet_remove_managed(&interface->udp, true);

  /* kill dlep session */
  dlep_session_remove(&interface->session);
}
Пример #7
0
/**
 * Callback to apply new network settings to a router session
 * @param session dlep session
 */
static void
_cb_apply_router(struct dlep_session *session) {
  OONF_DEBUG(session->log_source, "Initialize base router session");
  if (session->restrict_signal == DLEP_PEER_OFFER) {
    /*
     * we are waiting for a Peer Offer,
     * so we need to send Peer Discovery messages
     */
    session->local_event_timer.class = &_peer_discovery_class;

    OONF_DEBUG(session->log_source, "Activate discovery with interval %"
        PRIu64, session->cfg.discovery_interval);

    /* use the "local event" for the discovery timer */
    oonf_timer_start(&session->local_event_timer,
        session->cfg.discovery_interval);
  }
Пример #8
0
/**
 * Callbacks for events on the interface
 * @param l
 * @return -1 if an error happened, 0 otherwise
 */
static int
_cb_interface_listener(struct os_interface_listener *l) {
  struct oonf_packet_managed *managed;
  int result;

  /* calculate managed socket for this event */
  managed = container_of(l, struct oonf_packet_managed, _if_listener);

  result = _apply_managed(managed);

  OONF_DEBUG(LOG_PACKET,
      "Result from interface triggered socket reconfiguration: %d", result);

  return result;
}
Пример #9
0
/**
 * Process NL80211_CMD_NEW_MPATH message
 * @param interf nl80211 listener interface
 * @param hdr pointer to netlink message header
 */
void
nl80211_process_get_mpp_result(struct nl80211_if *interf,
    struct nlmsghdr *hdr) {
  struct oonf_layer2_destination *l2dst;
  struct oonf_layer2_neigh *l2neigh;
  struct netaddr remote_mac, destination_mac;
#ifdef OONF_LOG_DEBUG_INFO
  struct netaddr_str nbuf1, nbuf2;
#endif

  struct nlattr *tb[NL80211_ATTR_MAX + 1];
  struct genlmsghdr *gnlh;

  gnlh = nlmsg_data(hdr);
  nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
      genlmsg_attrlen(gnlh, 0), NULL);

  if (nl80211_get_if_index(interf) != nla_get_u32(tb[NL80211_ATTR_IFINDEX])) {
    /* wrong interface ? */
    return;
  }

  netaddr_from_binary(&remote_mac,
      nla_data(tb[NL80211_ATTR_MPATH_NEXT_HOP]), 6, AF_MAC48);
  netaddr_from_binary(&destination_mac,
      nla_data(tb[NL80211_ATTR_MAC]), 6, AF_MAC48);

  l2neigh = oonf_layer2_neigh_get(interf->l2net, &remote_mac);
  if (!l2neigh) {
    /* don't create a neighbor, just ignore the MPP data */
    return;
  }

  l2dst = nl80211_add_dst(l2neigh, &destination_mac);
  if (!l2dst) {
    return;
  }

  OONF_DEBUG(LOG_NL80211, "Neighbor %s was proxied by mesh node %s",
      netaddr_to_string(&nbuf1, &destination_mac),
      netaddr_to_string(&nbuf2, &remote_mac));
}
Пример #10
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;
}
Пример #11
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);
  }
}
Пример #12
0
/**
 * Apply new configuration to a managed stream socket
 * @param managed pointer to managed stream
 * @param stream pointer to TCP stream to configure
 * @param bindto local address to bind socket to
 *   set to AF_UNSPEC for simple reinitialization
 * @param port local port number
 * @param dscp dscp value for outgoing traffic
 * @param protocol IP protocol for raw IP socket, 0 otherwise
 * @param data interface data to bind socket to, might be NULL
 * @return -1 if an error happened, 0 if everything is okay,
 *   1 if the socket wasn't touched.
 */
static int
_apply_managed_socket(struct oonf_packet_managed *managed,
    struct oonf_packet_socket *packet,
    const struct netaddr *bindto, int port, uint8_t dscp,
    int protocol, struct os_interface *data) {
  union netaddr_socket sock;
  struct netaddr_str buf;

  /* create binding socket */
  if (netaddr_socket_init(&sock, bindto, port,
      data == NULL ? 0 : data->index)) {
    OONF_WARN(LOG_PACKET, "Cannot create managed socket address: %s/%u",
        netaddr_to_string(&buf, bindto), port);
    return -1;
  }

  if (list_is_node_added(&packet->node)) {
    if (data == packet->os_if
        && memcmp(&sock, &packet->local_socket, sizeof(sock)) == 0
        && protocol == packet->protocol) {
      /* nothing changed */
      return 1;
    }
  }
  else {
    if (data != NULL && !data->flags.up) {
      /* nothing changed */
      return 1;
    }
  }

  /* remove old socket */
  oonf_packet_remove(packet, true);

  if (data != NULL && !data->flags.up) {
    OONF_DEBUG(LOG_PACKET, "Interface %s of socket is down",
        data->name);
    return 0;
  }

  /* copy configuration */
  memcpy(&packet->config, &managed->config, sizeof(packet->config));
  if (packet->config.user == NULL) {
    packet->config.user = managed;
  }

  /* create new socket */
  if (protocol) {
    if (oonf_packet_raw_add(packet, protocol, &sock, data)) {
      return -1;
    }
  }
  else {
    if (oonf_packet_add(packet, &sock, data)) {
      return -1;
    }
  }

  if (os_fd_set_dscp(&packet->scheduler_entry.fd, dscp,
      netaddr_get_address_family(bindto) == AF_INET6)) {
    OONF_WARN(LOG_PACKET, "Could not set DSCP value for socket: %s (%d)",
        strerror(errno), errno);
    oonf_packet_remove(packet, true);
    return -1;
  }
  packet->os_if = data;

  OONF_DEBUG(LOG_PACKET, "Opened new socket and bound it to %s (if %s)",
      netaddr_to_string(&buf, bindto),
      data != NULL ? data->name : "any");
  return 0;
}