示例#1
0
文件: api_msg.c 项目: mtharp/lwip
/**
 * Join multicast groups for UDP netconns.
 * Called from netconn_join_leave_group
 *
 * @param msg the api_msg_msg pointing to the connection
 */
void
lwip_netconn_do_join_leave_group(struct api_msg_msg *msg)
{ 
  if (ERR_IS_FATAL(msg->conn->last_err)) {
    msg->err = msg->conn->last_err;
  } else {
    if (msg->conn->pcb.tcp != NULL) {
      if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
#if LWIP_UDP
#if LWIP_IPV6 && LWIP_IPV6_MLD
        if (PCB_ISIPV6(msg->conn->pcb.udp)) {
          if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
            msg->err = mld6_joingroup(ipX_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)),
              ipX_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
          } else {
            msg->err = mld6_leavegroup(ipX_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)),
              ipX_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr)));
          }
        }
        else
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
        {
#if LWIP_IGMP
          if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
            msg->err = igmp_joingroup(ipX_2_ip(API_EXPR_REF(msg->msg.jl.netif_addr)),
              ipX_2_ip(API_EXPR_REF(msg->msg.jl.multiaddr)));
          } else {
            msg->err = igmp_leavegroup(ipX_2_ip(API_EXPR_REF(msg->msg.jl.netif_addr)),
              ipX_2_ip(API_EXPR_REF(msg->msg.jl.multiaddr)));
          }
#endif /* LWIP_IGMP */
        }
#endif /* LWIP_UDP */
#if (LWIP_TCP || LWIP_RAW)
      } else {
        msg->err = ERR_VAL;
#endif /* (LWIP_TCP || LWIP_RAW) */
      }
    } else {
      msg->err = ERR_CONN;
    }
  }
  TCPIP_APIMSG_ACK(msg);
}
示例#2
0
static nsapi_error_t mbed_lwip_setsockopt(nsapi_stack_t *stack, nsapi_socket_t handle, int level, int optname, const void *optval, unsigned optlen)
{
    struct lwip_socket *s = (struct lwip_socket *)handle;

    switch (optname) {
#if LWIP_TCP
        case NSAPI_KEEPALIVE:
            if (optlen != sizeof(int) || s->conn->type != NETCONN_TCP) {
                return NSAPI_ERROR_UNSUPPORTED;
            }

            s->conn->pcb.tcp->so_options |= SOF_KEEPALIVE;
            return 0;

        case NSAPI_KEEPIDLE:
            if (optlen != sizeof(int) || s->conn->type != NETCONN_TCP) {
                return NSAPI_ERROR_UNSUPPORTED;
            }

            s->conn->pcb.tcp->keep_idle = *(int*)optval;
            return 0;

        case NSAPI_KEEPINTVL:
            if (optlen != sizeof(int) || s->conn->type != NETCONN_TCP) {
                return NSAPI_ERROR_UNSUPPORTED;
            }

            s->conn->pcb.tcp->keep_intvl = *(int*)optval;
            return 0;
#endif

        case NSAPI_REUSEADDR:
            if (optlen != sizeof(int)) {
                return NSAPI_ERROR_UNSUPPORTED;
            }

            if (*(int *)optval) {
                ip_set_option(s->conn->pcb.ip, SOF_REUSEADDR);
            } else {
                ip_reset_option(s->conn->pcb.ip, SOF_REUSEADDR);
            }
            return 0;

        case NSAPI_ADD_MEMBERSHIP:
        case NSAPI_DROP_MEMBERSHIP: {
            if (optlen != sizeof(nsapi_ip_mreq_t)) {
                return NSAPI_ERROR_PARAMETER;
            }
            err_t igmp_err;
            const nsapi_ip_mreq_t *imr = optval;

            /* Check interface address type matches group, or is unspecified */
            if (imr->imr_interface.version != NSAPI_UNSPEC && imr->imr_interface.version != imr->imr_multiaddr.version) {
                return NSAPI_ERROR_PARAMETER;
            }

            ip_addr_t if_addr;
            ip_addr_t multi_addr;

            /* Convert the group address */
            if (!convert_mbed_addr_to_lwip(&multi_addr, &imr->imr_multiaddr)) {
                return NSAPI_ERROR_PARAMETER;
            }

            /* Convert the interface address, or make sure it's the correct sort of "any" */
            if (imr->imr_interface.version != NSAPI_UNSPEC) {
                if (!convert_mbed_addr_to_lwip(&if_addr, &imr->imr_interface)) {
                    return NSAPI_ERROR_PARAMETER;
                }
            } else {
                ip_addr_set_any(IP_IS_V6(&if_addr), &if_addr);
            }

            igmp_err = ERR_USE; // Maps to NSAPI_ERROR_UNSUPPORTED
            int32_t member_pair_index = find_multicast_member(s, imr);

            if (optname == NSAPI_ADD_MEMBERSHIP) {
                if (!s->multicast_memberships) {
                    // First multicast join on this socket, allocate space for membership tracking
                    s->multicast_memberships = malloc(sizeof(nsapi_ip_mreq_t) * LWIP_SOCKET_MAX_MEMBERSHIPS);
                    if (!s->multicast_memberships) {
                        return NSAPI_ERROR_NO_MEMORY;
                    }
                } else if(s->multicast_memberships_count == LWIP_SOCKET_MAX_MEMBERSHIPS) {
                    return NSAPI_ERROR_NO_MEMORY;
                }

                if (member_pair_index != -1) {
                    return NSAPI_ERROR_ADDRESS_IN_USE;
                }

                member_pair_index = next_free_multicast_member(s, 0);

                sys_prot_t prot = sys_arch_protect();

                #if LWIP_IPV4
                if (IP_IS_V4(&if_addr)) {
                    igmp_err = igmp_joingroup(ip_2_ip4(&if_addr), ip_2_ip4(&multi_addr));
                }
                #endif
                #if LWIP_IPV6
                if (IP_IS_V6(&if_addr)) {
                    igmp_err = mld6_joingroup(ip_2_ip6(&if_addr), ip_2_ip6(&multi_addr));
                }
                #endif

                sys_arch_unprotect(prot);

                if (igmp_err == ERR_OK) {
                    set_multicast_member_registry_bit(s, member_pair_index);
                    s->multicast_memberships[member_pair_index] = *imr;
                    s->multicast_memberships_count++;
                }
            } else {
                if (member_pair_index == -1) {
                    return NSAPI_ERROR_NO_ADDRESS;
                }

                clear_multicast_member_registry_bit(s, member_pair_index);
                s->multicast_memberships_count--;

                sys_prot_t prot = sys_arch_protect();

                #if LWIP_IPV4
                if (IP_IS_V4(&if_addr)) {
                    igmp_err = igmp_leavegroup(ip_2_ip4(&if_addr), ip_2_ip4(&multi_addr));
                }
                #endif
                #if LWIP_IPV6
                if (IP_IS_V6(&if_addr)) {
                    igmp_err = mld6_leavegroup(ip_2_ip6(&if_addr), ip_2_ip6(&multi_addr));
                }
                #endif

                sys_arch_unprotect(prot);
            }

            return mbed_lwip_err_remap(igmp_err);
         }

        default:
            return NSAPI_ERROR_UNSUPPORTED;
    }
}
/**
 * Initialize DHCP6 server.
 *
 * Join DHCP6 multicast groups.
 * Create and bind server pcb.
 * Prebuild fixed parts of reply.
 */
err_t
dhcp6ds_init(struct netif *proxy_netif)
{
    ip6_addr_t *pxaddr, *pxaddr_nonlocal;
    int i;
    err_t error;

    LWIP_ASSERT1(proxy_netif != NULL);
    LWIP_ASSERT1(proxy_netif->hwaddr_len == 6); /* ethernet */

    pxaddr = netif_ip6_addr(proxy_netif, 0); /* link local */

    /*
     * XXX: TODO: This is a leftover from testing with IPv6 mapped
     * loopback with a special IPv6->IPv4 mapping hack in pxudp.c
     */
    /* advertise ourself as DNS resolver - will be proxied to host */
    pxaddr_nonlocal = NULL;
    for (i = 1; i < LWIP_IPV6_NUM_ADDRESSES; ++i) {
        if (ip6_addr_ispreferred(netif_ip6_addr_state(proxy_netif, i))
            && !ip6_addr_islinklocal(netif_ip6_addr(proxy_netif, i)))
        {
            pxaddr_nonlocal = netif_ip6_addr(proxy_netif, i);
            break;
        }
    }
    LWIP_ASSERT1(pxaddr_nonlocal != NULL); /* must be configured on the netif */


    error = mld6_joingroup(pxaddr, &all_dhcp_relays_and_servers);
    if (error != ERR_OK) {
        DPRINTF0(("%s: failed to join All_DHCP_Relay_Agents_and_Servers: %s\n",
                  __func__, proxy_lwip_strerr(error)));
        goto err;
    }

    error = mld6_joingroup(pxaddr, &all_dhcp_servers);
    if (error != ERR_OK) {
        DPRINTF0(("%s: failed to join All_DHCP_Servers: %s\n",
                  __func__, proxy_lwip_strerr(error)));
        goto err1;
    }


    dhcp6ds_pcb = udp_new_ip6();
    if (dhcp6ds_pcb == NULL) {
        DPRINTF0(("%s: failed to allocate PCB\n", __func__));
        error = ERR_MEM;
        goto err2;
    }

    udp_recv_ip6(dhcp6ds_pcb, dhcp6ds_recv, NULL);

    error = udp_bind_ip6(dhcp6ds_pcb, pxaddr, DHCP6_SERVER_PORT);
    if (error != ERR_OK) {
        DPRINTF0(("%s: failed to bind PCB\n", __func__));
        goto err3;
    }


#define OPT_SET(buf, off, c) do {                       \
        u16_t _s = PP_HTONS(c);                         \
        memcpy(&(buf)[off], &_s, sizeof(u16_t));        \
    } while (0)

#define SERVERID_SET(off, c)    OPT_SET(dhcp6ds_serverid, (off), (c))
#define DNSSRV_SET(off, c)      OPT_SET(dhcp6ds_dns, (off), (c))

    SERVERID_SET(0, DHCP6_OPTION_SERVERID);
    SERVERID_SET(2, DUID_LL_LEN);
    SERVERID_SET(4, DHCP6_DUID_LL);
    SERVERID_SET(6, ARES_HRD_ETHERNET);
    memcpy(&dhcp6ds_serverid[8], proxy_netif->hwaddr, 6);

    DNSSRV_SET(0, DHCP6_OPTION_DNS_SERVERS);
    DNSSRV_SET(2, 16);          /* one IPv6 address */
    /*
     * XXX: TODO: This is a leftover from testing with IPv6 mapped
     * loopback with a special IPv6->IPv4 mapping hack in pxudp.c
     */
    memcpy(&dhcp6ds_dns[4], pxaddr_nonlocal, sizeof(ip6_addr_t));

#undef SERVERID_SET
#undef DNSSRV_SET

    return ERR_OK;


  err3:
    udp_remove(dhcp6ds_pcb);
    dhcp6ds_pcb = NULL;
  err2:
    mld6_leavegroup(pxaddr, &all_dhcp_servers);
  err1:
    mld6_leavegroup(pxaddr, &all_dhcp_relays_and_servers);
  err:
    return error;
}