static int net_multicastJoinLeave( lua_State *L, int join) { size_t il; ip_addr_t multicast_addr; ip_addr_t if_addr; const char *multicast_ip; const char *if_ip; NODE_DBG("net_multicastJoin is called.\n"); if(! lua_isstring(L,1) ) return luaL_error( L, "wrong arg type" ); if_ip = luaL_checklstring( L, 1, &il ); if (if_ip != NULL) if ( if_ip[0] == '\0' || stricmp(if_ip,"any") == 0) { if_ip = "0.0.0.0"; il = 7; } if (if_ip == NULL || il > 15 || il < 7) return luaL_error( L, "invalid if ip" ); if_addr.addr = ipaddr_addr(if_ip); if(! lua_isstring(L,2) ) return luaL_error( L, "wrong arg type" ); multicast_ip = luaL_checklstring( L, 2, &il ); if (multicast_ip == NULL || il > 15 || il < 7) return luaL_error( L, "invalid multicast ip" ); multicast_addr.addr = ipaddr_addr(multicast_ip); if (join) { igmp_joingroup(&if_addr, &multicast_addr); } else { igmp_leavegroup(&if_addr, &multicast_addr); } return 0; }
/** * Join multicast groups for UDP netconns. * Called from netconn_join_leave_group * * @param msg the api_msg_msg pointing to the connection */ void 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 (msg->msg.jl.join_or_leave == NETCONN_JOIN) { msg->err = igmp_joingroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr); } else { msg->err = igmp_leavegroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr); } #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); }
err_t simple_discovery_init(struct netif *netif) { err_t ret; struct udp_pcb *pcb = udp_new(); if (pcb == NULL) return ERR_MEM; #if LWIP_IGMP struct ip_addr ipgroup; IP4_ADDR(&ipgroup, 224, 0, 0, 178); if ((ret = igmp_joingroup(IP_ADDR_ANY, &ipgroup)) != ERR_OK) goto error_exit; #endif if ((ret = udp_bind(pcb, IP_ADDR_ANY, SIMPLE_DISCOVERY_PORT)) != ERR_OK) goto error_exit; udp_recv(pcb, recv, netif); return ERR_OK; error_exit: udp_remove(pcb); return ret; }
NetUdpSocketErr LwipNetUdpSocket::bind(const Host& me) { err_t err; if(!m_pPcb) return NETUDPSOCKET_MEM; //NetUdpSocket was not properly initialised, should destroy it & retry #if LWIP_IGMP //Multicast support enabled if(me.getIp().isMulticast()) { DBG("This is a multicast addr, joining multicast group\r\n"); m_multicastGroup = me.getIp(); ip_addr_t multicastGroupAddr = m_multicastGroup.getStruct(); err = igmp_joingroup(IP_ADDR_ANY, &multicastGroupAddr); if(err) return NETUDPSOCKET_IF; //Could not find or create group } #endif err = udp_bind( (udp_pcb*) m_pPcb, IP_ADDR_ANY, me.getPort()); //IP_ADDR_ANY : Bind the connection to all local addresses if(err) return NETUDPSOCKET_INUSE; //Setup callback udp_recv( (udp_pcb*) m_pPcb, LwipNetUdpSocket::sRecvCb, (void*) this ); return NETUDPSOCKET_OK; }
/****************************************************************************** * FunctionName : espconn_igmp_join * Description : join a multicast group * Parameters : host_ip -- the ip address of udp server * multicast_ip -- multicast ip given by user * Returns : none *******************************************************************************/ sint8 ICACHE_FLASH_ATTR espconn_igmp_join(ip_addr_t *host_ip, ip_addr_t *multicast_ip) { if (igmp_joingroup(host_ip, multicast_ip) != ERR_OK) { LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("udp_join_multigrup failed!\n")); return -1; }; /* join to any IP address at the port */ return ESPCONN_OK; }
err_t mdns_responder_init(const struct mdns_service *services, int num_services, const char *txt_records[]) { err_t ret; memset(&mdns_state, 0, sizeof(mdns_state)); mdns_state.netif = &gs_net_if; setup_hostnames(&mdns_state, &gs_net_if); setup_txt_records(&mdns_state, txt_records); mdns_state.services = services; mdns_state.num_services = num_services; struct ip_addr ipgroup; IP4_ADDR(&ipgroup, 224, 0, 0, 251); mdns_state.sendpcb = udp_new(); if (mdns_state.sendpcb == NULL) return ERR_MEM; struct udp_pcb *pcb = udp_new(); if (pcb == NULL) { udp_remove(mdns_state.sendpcb); return ERR_MEM; } if ((ret = igmp_joingroup(IP_ADDR_ANY, &ipgroup)) != ERR_OK) return ret; ip_set_option(pcb, SOF_REUSEADDR); ip_set_option(mdns_state.sendpcb, SOF_REUSEADDR); if ((ret = udp_bind(pcb, IP_ADDR_ANY, MDNS_PORT)) != ERR_OK) goto error_exit; udp_recv(pcb, recv, &mdns_state); if ((ret = udp_bind(mdns_state.sendpcb, 0, MDNS_PORT)) != ERR_OK) goto error_exit; if ((ret = udp_connect(mdns_state.sendpcb, &ipgroup, MDNS_PORT)) != ERR_OK) goto error_exit; return ERR_OK; error_exit: udp_remove(pcb); udp_remove(mdns_state.sendpcb); return ret; }
STATIC mp_obj_t lwip_socket_setsockopt(size_t n_args, const mp_obj_t *args) { (void)n_args; // always 4 lwip_socket_obj_t *socket = args[0]; int opt = mp_obj_get_int(args[2]); if (opt == 20) { if (args[3] == mp_const_none) { socket->callback = MP_OBJ_NULL; } else { socket->callback = args[3]; } return mp_const_none; } switch (opt) { // level: SOL_SOCKET case SOF_REUSEADDR: { mp_int_t val = mp_obj_get_int(args[3]); // Options are common for UDP and TCP pcb's. if (val) { ip_set_option(socket->pcb.tcp, SOF_REUSEADDR); } else { ip_reset_option(socket->pcb.tcp, SOF_REUSEADDR); } break; } // level: IPPROTO_IP case IP_ADD_MEMBERSHIP: { mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ); if (bufinfo.len != sizeof(ip_addr_t) * 2) { mp_raise_ValueError(NULL); } // POSIX setsockopt has order: group addr, if addr, lwIP has it vice-versa err_t err = igmp_joingroup((ip_addr_t*)bufinfo.buf + 1, bufinfo.buf); if (err != ERR_OK) { mp_raise_OSError(error_lookup_table[-err]); } break; } default: printf("Warning: lwip.setsockopt() not implemented\n"); } return mp_const_none; }
int netx_change_group(struct netxsocket_s *rlpsock, ip4addr_t localGroup, int operation) { struct ip_addr addr; UNUSED_ARG(rlpsock); if (!is_multicast(localGroup)) return -1; /* result = ERR_OK which is defined as zero so return value is consistent */ addr.addr = localGroup; if (operation == NETI_JOINGROUP) return igmp_joingroup(&netxf_default->ip_addr, &addr); else return igmp_leavegroup(&netxf_default->ip_addr, &addr); }
static int netdev_imsfioctl(FAR struct socket *psock, int cmd, struct ip_msfilter *imsf) { FAR struct uip_driver_s *dev; int ret = OK; nvdbg("cmd: %d\n", cmd); /* Find the network device associated with the device name * in the request data. */ dev = netdev_findbyname(imsf->imsf_name); if (!dev) { ret = -EINVAL; goto errout; } /* Execute the command */ switch (cmd) { case SIOCSIPMSFILTER: /* Set source filter content */ { if (imsf->imsf_fmode == MCAST_INCLUDE) { ret = igmp_joingroup(dev, &imsf->imsf_multiaddr); } else { DEBUGASSERT(imsf->imsf_fmode == MCAST_EXCLUDE); ret = igmp_leavegroup(dev, &imsf->imsf_multiaddr); } } break; case SIOCGIPMSFILTER: /* Retrieve source filter addresses */ default: ret = -EINVAL; break; } errout: return ret; }
bool MDNSResponder::begin(const char* hostname){ // Open the MDNS socket if it isn't already open. size_t n = strlen(hostname); if (n > 63) { // max size for a single label. return false; } // Copy in hostname characters as lowercase _hostName = hostname; _hostName.toLowerCase(); // If instance name is not already set copy hostname to instance name if (_instanceName.equals("") ) _instanceName=hostname; // Open the MDNS socket if it isn't already open. if (!_conn) { uint32_t ourIp = _getOurIp(); if(ourIp == 0){ return false; } ip_addr_t ifaddr; ifaddr.addr = ourIp; ip_addr_t multicast_addr; multicast_addr.addr = (uint32_t) MDNS_MULTICAST_ADDR; if (igmp_joingroup(&ifaddr, &multicast_addr)!= ERR_OK) { return false; } _conn = new UdpContext; _conn->ref(); if (!_conn->listen(*IP_ADDR_ANY, MDNS_PORT)) { return false; } _conn->setMulticastInterface(ifaddr); _conn->setMulticastTTL(MDNS_MULTICAST_TTL); _conn->onRx(std::bind(&MDNSResponder::update, this)); _conn->connect(multicast_addr, MDNS_PORT); } return true; }
/** * 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); }
bool MDNSResponder::begin(const char* domain){ // Open the MDNS socket if it isn't already open. size_t n = strlen(domain); if (n > 255) { // Can only handle domains that are 255 chars in length. return false; } // Copy in domain characters as lowercase for (int i = 0; i < n; ++i) _hostName[i] = tolower(domain[i]); _hostName[n] = '\0'; os_strcpy(_boardName, ARDUINO_BOARD); // Open the MDNS socket if it isn't already open. if (!_conn) { uint32_t ourIp = _getOurIp(); if(ourIp == 0){ return false; } ip_addr_t ifaddr; ifaddr.addr = ourIp; ip_addr_t multicast_addr; multicast_addr.addr = (uint32_t) MDNS_MULTICAST_ADDR; if (igmp_joingroup(&ifaddr, &multicast_addr)!= ERR_OK) { return false; } _conn = new UdpContext; _conn->ref(); if (!_conn->listen(*IP_ADDR_ANY, MDNS_PORT)) { return false; } _conn->setMulticastInterface(ifaddr); _conn->setMulticastTTL(MDNS_MULTICAST_TTL); _conn->onRx(std::bind(&MDNSResponder::update, this)); _conn->connect(multicast_addr, MDNS_PORT); } return true; }
uint8_t WiFiUDP::beginMulticast(IPAddress interfaceAddr, IPAddress multicast, uint16_t port) { if (_ctx) { _ctx->unref(); _ctx = 0; } if (igmp_joingroup(interfaceAddr, multicast)!= ERR_OK) { return 0; } _ctx = new UdpContext; _ctx->ref(); ip_addr_t addr = IPADDR4_INIT(INADDR_ANY); if (!_ctx->listen(&addr, port)) { return 0; } return 1; }
bool LLMNRResponder::_restart() { if (_conn) { _conn->unref(); _conn = 0; } ip_addr_t multicast_addr; multicast_addr.addr = (uint32_t)LLMNR_MULTICAST_ADDR; if (igmp_joingroup(IP_ADDR_ANY, &multicast_addr) != ERR_OK) return false; _conn = new UdpContext; _conn->ref(); if (!_conn->listen(*IP_ADDR_ANY, LLMNR_PORT)) return false; _conn->setMulticastTTL(LLMNR_MULTICAST_TTL); _conn->onRx(std::bind(&LLMNRResponder::_process_packet, this)); _conn->connect(multicast_addr, LLMNR_PORT); }
STATIC mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) { (void)n_args; // always 4 socket_obj_t *self = MP_OBJ_TO_PTR(args[0]); int opt = mp_obj_get_int(args[2]); switch (opt) { // level: SOL_SOCKET case SO_REUSEADDR: { int val = mp_obj_get_int(args[3]); int ret = lwip_setsockopt_r(self->fd, SOL_SOCKET, opt, &val, sizeof(int)); if (ret != 0) { exception_from_errno(errno); } break; } // level: IPPROTO_IP case IP_ADD_MEMBERSHIP: { mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ); if (bufinfo.len != sizeof(ip4_addr_t) * 2) { mp_raise_ValueError(NULL); } // POSIX setsockopt has order: group addr, if addr, lwIP has it vice-versa err_t err = igmp_joingroup((const ip4_addr_t*)bufinfo.buf + 1, bufinfo.buf); if (err != ERR_OK) { mp_raise_OSError(-err); } break; } default: mp_printf(&mp_plat_print, "Warning: lwip.setsockopt() option not implemented\n"); } return mp_const_none; }
static int netdev_imsfioctl(FAR struct socket *psock, int cmd, FAR struct ip_msfilter *imsf) { FAR struct net_driver_s *dev; int ret = -EINVAL; nvdbg("cmd: %d\n", cmd); /* Execute the command */ switch (cmd) { case SIOCSIPMSFILTER: /* Set source filter content */ { dev = netdev_imsfdev(imsf); if (dev) { if (imsf->imsf_fmode == MCAST_INCLUDE) { ret = igmp_joingroup(dev, &imsf->imsf_multiaddr); } else { DEBUGASSERT(imsf->imsf_fmode == MCAST_EXCLUDE); ret = igmp_leavegroup(dev, &imsf->imsf_multiaddr); } } } break; case SIOCGIPMSFILTER: /* Retrieve source filter addresses */ default: ret = -ENOTTY; break; } return ret; }
uint8_t WiFiUDP::beginMulticast(IPAddress interfaceAddr, IPAddress multicast, uint16_t port) { if (_ctx) { _ctx->unref(); _ctx = 0; } ip_addr_t ifaddr; ifaddr.addr = (uint32_t) interfaceAddr; ip_addr_t multicast_addr; multicast_addr.addr = (uint32_t) multicast; if (igmp_joingroup(&ifaddr, &multicast_addr)!= ERR_OK) { return 0; } _ctx = new UdpContext; _ctx->ref(); if (!_ctx->listen(*IP_ADDR_ANY, port)) { return 0; } return 1; }
bool MDNSResponder::_listen() { // Open the MDNS socket if it isn't already open. if (!_conn) { uint32_t ourIp = _getOurIp(); if (ourIp == 0) { #ifdef MDNS_DEBUG_RX Serial.println("MDNS: no IP address to listen on"); #endif return false; } #ifdef MDNS_DEBUG_RX Serial.print("MDNS listening on IP: "); Serial.println(IPAddress(ourIp)); #endif ip_addr_t ifaddr; ifaddr.addr = ourIp; ip_addr_t multicast_addr; multicast_addr.addr = (uint32_t)MDNS_MULTICAST_ADDR; if (igmp_joingroup(&ifaddr, &multicast_addr) != ERR_OK) { return false; } _conn = new UdpContext; _conn->ref(); if (!_conn->listen(*IP_ADDR_ANY, MDNS_PORT)) { return false; } _conn->setMulticastInterface(ifaddr); _conn->setMulticastTTL(MDNS_MULTICAST_TTL); _conn->onRx(std::bind(&MDNSResponder::update, this)); _conn->connect(multicast_addr, MDNS_PORT); } return true; }
struct in_multi * in_addmulti(ip_addr *ap, struct net *netp, int addrtype) { struct in_multi *inm = (struct in_multi *)NULL; int error; /* check for good addr. */ if ((ap == (ip_addr *)NULL) || (*ap == 0)) return ((struct in_multi *)NULL); ENTER_CRIT_SECTION(netp); /* See if address already in list. */ #ifdef IP_V6 if(addrtype == 6) inm = v6_lookup_mcast((ip6_addr*)ap, netp); #endif #ifdef IP_V4 if(addrtype != 6) inm = lookup_mcast(*ap, netp); #endif if (inm != (struct in_multi *)NULL) { /* Found it; just increment the reference count. */ ++inm->inm_refcount; } else { /* * New address; allocate a new multicast record * and link it into the interface's multicast list. */ inm = (struct in_multi *)INM_ALLOC(sizeof(*inm)); if (inm == (struct in_multi *)NULL) { EXIT_CRIT_SECTION(netp); return ((struct in_multi *)NULL); } #ifdef IP_V6 if(addrtype == 6) IP6CPY(&inm->ip6addr, (struct in6_addr *)ap); #endif #ifdef IP_V4 if(addrtype != 6) inm->inm_addr = *ap; #endif inm->inm_netp = netp; inm->inm_refcount = 1; inm->inm_next = netp->mc_list; netp->mc_list = inm; /* * If net has a multicast address registration routine then ask * the network driver to update its multicast reception * filter appropriately for the new address. */ if(netp->n_mcastlist) error = netp->n_mcastlist(inm); else error = 0; #if defined (IGMP_V1) || defined (IGMP_V2) /* * Let IGMP know that we have joined a new IP multicast group. */ if (inm->inm_addr) igmp_joingroup(inm); #endif } EXIT_CRIT_SECTION(netp); USE_ARG(error); return (inm); }
/** * @brief Start all of the UDP stuff * @param netPath network object * @param ptpClock PTP clock object * @retval Boolean success */ Boolean netInit(NetPath *netPath, PtpClock *ptpClock) { struct ip_addr interfaceAddr; struct in_addr netAddr; char addrStr[NET_ADDRESS_LENGTH]; DBG("netInit\n"); /* find a network interface */ interfaceAddr.addr = findIface(ptpClock->rtOpts->ifaceName, ptpClock->portUuidField, netPath); if (!(interfaceAddr.addr)) { goto fail01; } /* Open lwIP raw udp interfaces for the event port. */ netPath->eventPcb = udp_new(); if (NULL == netPath->eventPcb) { ERROR("netInit: Failed to open Event UDP PCB\n"); goto fail02; } /* Open lwIP raw udp interfaces for the general port. */ netPath->generalPcb = udp_new(); if (NULL == netPath->generalPcb) { ERROR("netInit: Failed to open General UDP PCB\n"); goto fail03; } /* Initialize the buffer queues. */ netQInit(&netPath->eventQ); netQInit(&netPath->generalQ); /* Configure network (broadcast/unicast) addresses. */ netPath->unicastAddr = 0; /* disable unicast */ /*Init General multicast IP address*/ memcpy(addrStr, DEFAULT_PTP_DOMAIN_ADDRESS, NET_ADDRESS_LENGTH); if (!inet_aton(addrStr, &netAddr)) { ERROR("netInit: failed to encode multi-cast address: %s\n", addrStr); goto fail04; } netPath->multicastAddr = netAddr.s_addr; /* join multicast group (for receiving) on specified interface */ igmp_joingroup(&interfaceAddr, (struct ip_addr *)&netAddr); /*Init Peer multicast IP address*/ memcpy(addrStr, PEER_PTP_DOMAIN_ADDRESS, NET_ADDRESS_LENGTH); if (!inet_aton(addrStr, &netAddr)) { ERROR("netInit: failed to encode peer multi-cast address: %s\n", addrStr); goto fail04; } netPath->peerMulticastAddr = netAddr.s_addr; /* join peer multicast group (for receiving) on specified interface */ igmp_joingroup(&interfaceAddr, (struct ip_addr *)&netAddr); /* multicast send only on specified interface */ netPath->eventPcb->multicast_ip.addr = netPath->multicastAddr; netPath->generalPcb->multicast_ip.addr = netPath->multicastAddr; /* Establish the appropriate UDP bindings/connections for events. */ udp_recv(netPath->eventPcb, netRecvEventCallback, netPath); udp_bind(netPath->eventPcb, IP_ADDR_ANY, PTP_EVENT_PORT); /* udp_connect(netPath->eventPcb, &netAddr, PTP_EVENT_PORT); */ /* Establish the appropriate UDP bindings/connections for general. */ udp_recv(netPath->generalPcb, netRecvGeneralCallback, netPath); udp_bind(netPath->generalPcb, IP_ADDR_ANY, PTP_GENERAL_PORT); /* udp_connect(netPath->generalPcb, &netAddr, PTP_GENERAL_PORT); */ /* Return a success code. */ return TRUE; /* fail05: udp_disconnect(netPath->eventPcb); udp_disconnect(netPath->generalPcb); */ fail04: udp_remove(netPath->generalPcb); fail03: udp_remove(netPath->eventPcb); fail02: fail01: return FALSE; }
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; } }