void net_context_put(struct net_context *context) { if (!context) { return; } nano_sem_take(&contexts_lock, TICKS_UNLIMITED); if (context->tuple.ip_proto == IPPROTO_UDP) { if (net_context_get_receiver_registered(context)) { struct simple_udp_connection *udp = net_context_get_udp_connection(context); simple_udp_unregister(udp); } } #ifdef CONFIG_NETWORKING_WITH_TCP if (context->tcp_type == NET_TCP_TYPE_SERVER) { tcp_unlisten(UIP_HTONS(context->tuple.local_port), &context->tcp); } #endif memset(&context->tuple, 0, sizeof(context->tuple)); memset(&context->udp, 0, sizeof(context->udp)); context->receiver_registered = false; context_sem_give(&contexts_lock); }
/*---------------------------------------------------------------------------*/ static int prepare_and_send_buf(coap_context_t *ctx, session_t *session, uint8_t *data, size_t len) { struct net_buf *buf; int max_data_len; /* This net_buf gets sent to network, so it is not released * by this function unless there was an error and buf was * not actually sent. */ buf = ip_buf_get_tx(ctx->net_ctx); if (!buf) { len = -ENOBUFS; goto out; } max_data_len = IP_BUF_MAX_DATA - UIP_IPUDPH_LEN; PRINTF("%s: reply to peer data %p len %d\n", __FUNCTION__, data, len); if (len > max_data_len) { PRINTF("%s: too much (%d bytes) data to send (max %d bytes)\n", __FUNCTION__, len, max_data_len); ip_buf_unref(buf); len = -EINVAL; goto out; } /* Note that we have reversed the addresses here * because net_reply() will reverse them again. */ #ifdef CONFIG_NETWORKING_WITH_IPV6 uip_ip6addr_copy(&NET_BUF_IP(buf)->destipaddr, (uip_ip6addr_t *)&ctx->my_addr.in6_addr); uip_ip6addr_copy(&NET_BUF_IP(buf)->srcipaddr, (uip_ip6addr_t *)&session->addr.ipaddr); #else uip_ip4addr_copy(&NET_BUF_IP(buf)->destipaddr, (uip_ip4addr_t *)&ctx->my_addr.in_addr); uip_ip4addr_copy(&NET_BUF_IP(buf)->srcipaddr, (uip_ip4addr_t *)&session->addr.ipaddr); #endif NET_BUF_UDP(buf)->destport = uip_ntohs(ctx->my_port); NET_BUF_UDP(buf)->srcport = session->addr.port; uip_set_udp_conn(buf) = net_context_get_udp_connection(ctx->net_ctx); memcpy(net_buf_add(buf, len), data, len); ip_buf_appdatalen(buf) = len; ip_buf_appdata(buf) = buf->data + ip_buf_reserve(buf); if (net_reply(ctx->net_ctx, buf)) { ip_buf_unref(buf); } out: return len; }
/* Internal function to send network data to uIP stack */ static int check_and_send_packet(struct net_buf *buf) { struct net_tuple *tuple; struct simple_udp_connection *udp; int ret = 0; if (!netdev.drv) { return -EINVAL; } tuple = net_context_get_tuple(buf->context); if (!tuple) { return -EINVAL; } switch (tuple->ip_proto) { case IPPROTO_UDP: udp = net_context_get_udp_connection(buf->context); if (!net_context_get_receiver_registered(buf->context)) { ret = simple_udp_register(udp, tuple->local_port, #ifdef CONFIG_NETWORKING_WITH_IPV6 (uip_ip6addr_t *)&tuple->remote_addr->in6_addr, #else (uip_ip4addr_t *)&tuple->remote_addr->in_addr, #endif tuple->remote_port, udp_packet_reply, buf); if (!ret) { NET_DBG("UDP connection creation failed\n"); ret = -ENOENT; break; } net_context_set_receiver_registered(buf->context); } simple_udp_send(buf, udp, buf->data, buf->len); ret = 0; break; case IPPROTO_TCP: NET_DBG("TCP not yet supported\n"); ret = -EINVAL; break; case IPPROTO_ICMPV6: NET_DBG("ICMPv6 not yet supported\n"); ret = -EINVAL; break; } return ret; }
/* Called by application when it wants to receive network data */ struct net_buf *net_receive(struct net_context *context) { struct nano_fifo *rx_queue = net_context_get_queue(context); struct net_tuple *tuple; int ret = 0; tuple = net_context_get_tuple(context); if (!tuple) { return NULL; } switch (tuple->ip_proto) { case IPPROTO_UDP: if (!net_context_get_receiver_registered(context)) { struct simple_udp_connection *udp = net_context_get_udp_connection(context); ret = simple_udp_register(udp, tuple->local_port, #ifdef CONFIG_NETWORKING_WITH_IPV6 (uip_ip6addr_t *)&tuple->remote_addr->in6_addr, #else (uip_ip4addr_t *)&tuple->remote_addr->in_addr, #endif tuple->remote_port, udp_packet_receive, context); if (!ret) { NET_DBG("UDP connection listener failed\n"); ret = -ENOENT; break; } } net_context_set_receiver_registered(context); ret = 0; break; case IPPROTO_TCP: NET_DBG("TCP not yet supported\n"); ret = -EINVAL; break; case IPPROTO_ICMPV6: NET_DBG("ICMPv6 not yet supported\n"); ret = -EINVAL; break; } return nano_fifo_get(rx_queue); }
/* Switch the ports and addresses and set route and neighbor cache. * Returns 1 if packet was sent properly, in this case it is the caller * that needs to release the net_buf. If 0 is returned, then uIP stack * has released the net_buf already because there was an some net related * error when sending the buffer. */ static inline int udp_prepare_and_send(struct net_context *context, struct net_buf *buf) { #ifdef CONFIG_NETWORKING_WITH_IPV6 uip_ds6_route_t *route_old, *route_new = NULL; uip_ds6_nbr_t *nbr; #endif uip_ipaddr_t tmp; uint16_t port; uint8_t ret; if (uip_len(buf) == 0) { /* This is expected as uIP will typically set the * packet length to 0 after receiving it. So we need * to fix the length here. The protocol specific * part is added also here. */ uip_len(buf) = uip_slen(buf) = uip_appdatalen(buf); buf->data = buf->buf + UIP_IPUDPH_LEN; } port = UIP_UDP_BUF(buf)->srcport; UIP_UDP_BUF(buf)->srcport = UIP_UDP_BUF(buf)->destport; UIP_UDP_BUF(buf)->destport = port; uip_ipaddr_copy(&tmp, &UIP_IP_BUF(buf)->srcipaddr); uip_ipaddr_copy(&UIP_IP_BUF(buf)->srcipaddr, &UIP_IP_BUF(buf)->destipaddr); uip_ipaddr_copy(&UIP_IP_BUF(buf)->destipaddr, &tmp); #ifdef CONFIG_NETWORKING_WITH_IPV6 /* The peer needs to be in neighbor cache before route can be added. */ nbr = uip_ds6_nbr_lookup((uip_ipaddr_t *)&UIP_IP_BUF(buf)->destipaddr); if (!nbr) { const uip_lladdr_t *lladdr = (const uip_lladdr_t *)&buf->src; nbr = uip_ds6_nbr_add( (uip_ipaddr_t *)&UIP_IP_BUF(buf)->destipaddr, lladdr, 0, NBR_REACHABLE); if (!nbr) { NET_DBG("Cannot add peer "); PRINT6ADDR(&UIP_IP_BUF(buf)->destipaddr); PRINT(" to neighbor cache\n"); } } /* Temporarily add route to peer, delete the route after * sending the packet. Check if there was already a * route and do not remove it if there was existing * route to this peer. */ route_old = uip_ds6_route_lookup(&UIP_IP_BUF(buf)->destipaddr); if (!route_old) { route_new = uip_ds6_route_add(&UIP_IP_BUF(buf)->destipaddr, 128, &UIP_IP_BUF(buf)->destipaddr); if (!route_new) { NET_DBG("Cannot add route to peer "); PRINT6ADDR(&UIP_IP_BUF(buf)->destipaddr); PRINT("\n"); } } #endif ret = simple_udp_sendto_port(buf, net_context_get_udp_connection(context), buf->data, buf->len, &UIP_IP_BUF(buf)->destipaddr, uip_ntohs(UIP_UDP_BUF(buf)->destport)); if (!ret) { NET_DBG("Packet could not be sent properly.\n"); } #ifdef CONFIG_NETWORKING_WITH_IPV6 if (!route_old && route_new) { /* This will also remove the neighbor cache entry */ uip_ds6_route_rm(route_new); } #endif return ret; }