/** * 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); }
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; } }
void VBoxNetLwipNAT::onLwipTcpIpInit(void* arg) { AssertPtrReturnVoid(arg); VBoxNetLwipNAT *pNat = static_cast<VBoxNetLwipNAT *>(arg); HRESULT hrc = com::Initialize(); Assert(!FAILED(hrc)); proxy_arp_hook = pxremap_proxy_arp; proxy_ip4_divert_hook = pxremap_ip4_divert; proxy_na_hook = pxremap_proxy_na; proxy_ip6_divert_hook = pxremap_ip6_divert; /* lwip thread */ RTNETADDRIPV4 network; RTNETADDRIPV4 address = g_pLwipNat->getIpv4Address(); RTNETADDRIPV4 netmask = g_pLwipNat->getIpv4Netmask(); network.u = address.u & netmask.u; ip_addr LwipIpAddr, LwipIpNetMask, LwipIpNetwork; memcpy(&LwipIpAddr, &address, sizeof(ip_addr)); memcpy(&LwipIpNetMask, &netmask, sizeof(ip_addr)); memcpy(&LwipIpNetwork, &network, sizeof(ip_addr)); netif *pNetif = netif_add(&g_pLwipNat->m_LwipNetIf /* Lwip Interface */, &LwipIpAddr /* IP address*/, &LwipIpNetMask /* Network mask */, &LwipIpAddr /* gateway address, @todo: is self IP acceptable? */, g_pLwipNat /* state */, VBoxNetLwipNAT::netifInit /* netif_init_fn */, tcpip_input /* netif_input_fn */); AssertPtrReturnVoid(pNetif); LogRel(("netif %c%c%d: mac %RTmac\n", pNetif->name[0], pNetif->name[1], pNetif->num, pNetif->hwaddr)); LogRel(("netif %c%c%d: inet %RTnaipv4 netmask %RTnaipv4\n", pNetif->name[0], pNetif->name[1], pNetif->num, pNetif->ip_addr, pNetif->netmask)); for (int i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) { if (!ip6_addr_isinvalid(netif_ip6_addr_state(pNetif, i))) { LogRel(("netif %c%c%d: inet6 %RTnaipv6\n", pNetif->name[0], pNetif->name[1], pNetif->num, netif_ip6_addr(pNetif, i))); } } netif_set_up(pNetif); netif_set_link_up(pNetif); if (pNat->m_ProxyOptions.ipv6_enabled) { /* * XXX: lwIP currently only ever calls mld6_joingroup() in * nd6_tmr() for fresh tentative addresses, which is a wrong place * to do it - but I'm not keen on fixing this properly for now * (with correct handling of interface up and down transitions, * etc). So stick it here as a kludge. */ for (int i = 0; i <= 1; ++i) { ip6_addr_t *paddr = netif_ip6_addr(pNetif, i); ip6_addr_t solicited_node_multicast_address; ip6_addr_set_solicitednode(&solicited_node_multicast_address, paddr->addr[3]); mld6_joingroup(paddr, &solicited_node_multicast_address); } /* * XXX: We must join the solicited-node multicast for the * addresses we do IPv6 NA-proxy for. We map IPv6 loopback to * proxy address + 1. We only need the low 24 bits, and those are * fixed. */ { ip6_addr_t solicited_node_multicast_address; ip6_addr_set_solicitednode(&solicited_node_multicast_address, /* last 24 bits of the address */ PP_HTONL(0x00000002)); mld6_netif_joingroup(pNetif, &solicited_node_multicast_address); } } proxy_init(&g_pLwipNat->m_LwipNetIf, &g_pLwipNat->m_ProxyOptions); natServiceProcessRegisteredPf(g_pLwipNat->m_vecPortForwardRule4); natServiceProcessRegisteredPf(g_pLwipNat->m_vecPortForwardRule6); }
/** * 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; }