/*---------------------------------------------------------------------------*/ static int coap_context_send(coap_context_t *ctx, struct net_buf *buf) { int max_data_len, ret; max_data_len = IP_BUF_MAX_DATA - UIP_IPUDPH_LEN; PRINTF("%s: send to peer data %p len %d\n", __FUNCTION__, ip_buf_appdata(buf), ip_buf_appdatalen(buf)); if (ip_buf_appdatalen(buf) > max_data_len) { PRINTF("%s: too much (%d bytes) data to send (max %d bytes)\n", __FUNCTION__, ip_buf_appdatalen(buf), max_data_len); ip_buf_unref(buf); ret = -EINVAL; goto out; } ret = net_send(buf); if (ret < 0) { PRINT("%s: sending %d bytes failed\n", __FUNCTION__, ip_buf_appdatalen(buf)); ip_buf_unref(buf); } out: return ret; }
static inline bool wait_reply(const char *name, struct net_context *ctx, int ipsum_len, int pos) { struct net_buf *buf; bool fail = false; int expected_len = ipsum_len - pos; /* Wait for the answer */ buf = net_receive(ctx, WAIT_TICKS); if (buf) { if (ip_buf_appdatalen(buf) != expected_len) { PRINT("%s: received %d bytes, expected %d\n", name, ip_buf_appdatalen(buf), expected_len); fail = true; goto free_buf; } /* In this test we reverse the received bytes. * We could just pass the data back as is but * this way it is possible to see how the app * can manipulate the received data. */ reverse(ip_buf_appdata(buf), ip_buf_appdatalen(buf)); /* Did we get all the data back? */ if (memcmp(lorem_ipsum + pos, ip_buf_appdata(buf), expected_len)) { PRINT("%s: received data mismatch.\n", name); fail = true; goto free_buf; } PRINT("%s: received %d bytes\n", __func__, expected_len); free_buf: ip_buf_unref(buf); } else { PRINT("%s: expected data, got none\n", name); fail = true; } return fail; }
/*---------------------------------------------------------------------------*/ 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; }
static struct net_buf *ip_buf_get_reserve(enum ip_buf_type type, uint16_t reserve_head) #endif { struct net_buf *buf = NULL; /* Note that we do not reserve any space in front of the * buffer so buf->data points to first byte of the IP header. * This is done like this so that IP stack works the same * way as BT and 802.15.4 stacks. * * The reserve_head variable in the function will tell * the size of the IP + other headers if there are any. * That variable is only used to calculate the pointer * where the application data starts. */ switch (type) { case IP_BUF_RX: buf = net_buf_get(&free_rx_bufs, 0); dec_free_rx_bufs(buf); break; case IP_BUF_TX: buf = net_buf_get(&free_tx_bufs, 0); dec_free_tx_bufs(buf); break; } if (!buf) { #ifdef DEBUG_IP_BUFS NET_ERR("Failed to get free %s buffer (%s():%d)\n", type2str(type), caller, line); #else NET_ERR("Failed to get free %s buffer\n", type2str(type)); #endif return NULL; } ip_buf_type(buf) = type; ip_buf_appdata(buf) = buf->data + reserve_head; ip_buf_appdatalen(buf) = 0; ip_buf_reserve(buf) = reserve_head; net_buf_add(buf, reserve_head); NET_BUF_CHECK_IF_NOT_IN_USE(buf); #ifdef DEBUG_IP_BUFS NET_DBG("%s [%d] buf %p reserve %u ref %d (%s():%d)\n", type2str(type), get_frees(type), buf, reserve_head, buf->ref, caller, line); #else NET_DBG("%s buf %p reserve %u ref %d\n", type2str(type), buf, reserve_head, buf->ref); #endif return buf; }
/*---------------------------------------------------------------------------*/ int coap_context_wait_data(coap_context_t *coap_ctx, int32_t ticks) { struct net_buf *buf; buf = net_receive(coap_ctx->net_ctx, ticks); if (buf) { session_t session; int ret; uip_ipaddr_copy(&session.addr.ipaddr, &UIP_IP_BUF(buf)->srcipaddr); session.addr.port = UIP_UDP_BUF(buf)->srcport; session.size = sizeof(session.addr); session.ifindex = 1; PRINTF("coap-context: got dtls message from "); PRINT6ADDR(&session.addr.ipaddr); PRINTF(":%d %u bytes\n", uip_ntohs(session.addr.port), uip_appdatalen(buf)); PRINTF("Received appdata %p appdatalen %d\n", ip_buf_appdata(buf), ip_buf_appdatalen(buf)); coap_ctx->buf = buf; ret = dtls_handle_message(coap_ctx->dtls_context, &session, ip_buf_appdata(buf), ip_buf_appdatalen(buf)); /* We always release the buffer here as this buffer is never sent * to network anyway. */ if (coap_ctx->buf) { ip_buf_unref(coap_ctx->buf); coap_ctx->buf = NULL; } return ret; } return 0; }
static inline struct net_buf *prepare_reply(const char *type, struct net_buf *buf) { printk("%s: received %d bytes\n", type, ip_buf_appdatalen(buf)); /* In this test we reverse the received bytes. * We could just pass the data back as is but * this way it is possible to see how the app * can manipulate the received data. */ reverse(ip_buf_appdata(buf), ip_buf_appdatalen(buf)); return buf; }
int tcp_rx(struct net_context *ctx, uint8_t *buf, size_t *read_bytes, size_t size) { struct net_buf *nbuf; int rc; nbuf = net_receive(ctx, TCP_RX_TIMEOUT); rc = -EIO; if (nbuf != NULL) { *read_bytes = ip_buf_appdatalen(nbuf); if (*read_bytes > size) { rc = -ENOMEM; } else { memcpy(buf, ip_buf_appdata(nbuf), *read_bytes); rc = 0; } ip_buf_unref(nbuf); } return rc; }
/*---------------------------------------------------------------------------*/ int coap_context_wait_data(coap_context_t *coap_ctx, int32_t ticks) { struct net_buf *buf; buf = net_receive(coap_ctx->net_ctx, ticks); if (buf) { PRINTF("coap-context: got message from "); PRINT6ADDR(&UIP_IP_BUF(buf)->srcipaddr); PRINTF(":%d %u bytes\n", uip_ntohs(UIP_UDP_BUF(buf)->srcport), uip_appdatalen(buf)); PRINTF("Received data appdata %p appdatalen %d\n", ip_buf_appdata(buf), ip_buf_appdatalen(buf)); coap_ctx->buf = buf; coap_engine_receive(coap_ctx); return 1; } return 0; }
/*---------------------------------------------------------------------------*/ int coap_context_reply(coap_context_t *ctx, struct net_buf *buf) { int max_data_len, ret; max_data_len = IP_BUF_MAX_DATA - UIP_IPUDPH_LEN; PRINTF("%s: reply to peer data %p len %d\n", __FUNCTION__, ip_buf_appdata(buf), ip_buf_appdatalen(buf)); if (ip_buf_appdatalen(buf) > max_data_len) { PRINTF("%s: too much (%d bytes) data to send (max %d bytes)\n", __FUNCTION__, ip_buf_appdatalen(buf), max_data_len); ip_buf_unref(buf); ret = -EINVAL; goto out; } if (net_reply(ctx->net_ctx, buf)) { ip_buf_unref(buf); } out: return ret; }
/*---------------------------------------------------------------------------*/ int coap_context_send_message(coap_context_t *coap_ctx, uip_ipaddr_t *addr, uint16_t port, const uint8_t *data, uint16_t length) { int ret; if(coap_ctx == NULL || coap_ctx->is_used == 0) { PRINTF("coap-context: can not send on non-used context\n"); return 0; } ip_buf_appdatalen(coap_ctx->buf) = length; if (!uip_udp_conn(coap_ctx->buf)) { /* Normal send, not a reply */ ret = coap_context_send(coap_ctx, coap_ctx->buf); } else { /* We need to set the uIP buffer lengths in net_buf properly as * otherwise the final buffer length in * net_init.c:udp_prepare_and_send() will be usually incorrect * (uip_len() will be length of the received packet). So by setting * uip_len() to 0 here, we let the sending in net_init.c to * set the send buffer length correctly. */ uip_len(coap_ctx->buf) = 0; memcpy(ip_buf_appdata(coap_ctx->buf), data, length); ret = coap_context_reply(coap_ctx, coap_ctx->buf); } coap_ctx->buf = NULL; return ret; }
static void receive_data(const char *taskname, struct net_context *ctx) { struct net_buf *buf; #ifdef CONFIG_NET_SANITY_TEST int rp; #endif buf = net_receive(ctx, TICKS_NONE); if (buf) { PRINT("%s: %s(): received %d bytes\n", taskname, __func__, ip_buf_appdatalen(buf)); if (memcmp(ip_buf_appdata(buf), lorem_ipsum, sizeof(lorem_ipsum))) { PRINT("ERROR: data does not match\n"); #ifdef CONFIG_NET_SANITY_TEST rp = TC_FAIL; } else { rp = TC_PASS; #endif } ip_buf_unref(buf); #ifdef CONFIG_NET_SANITY_TEST loopback++; test_rp = test_rp && rp; TC_END_RESULT(rp); if (loopback == CONFIG_NET_15_4_LOOPBACK_NUM) { loopback = 0; TC_END_REPORT(test_rp); } #endif } }
/* This is called by contiki/ip/tcpip.c:tcpip_uipcall() when packet * is processed. */ PROCESS_THREAD(tcp, ev, data, buf, user_data) { PROCESS_BEGIN(); while(1) { PROCESS_YIELD_UNTIL(ev == tcpip_event); if (POINTER_TO_INT(data) == TCP_WRITE_EVENT) { /* We want to send data to peer. */ struct net_context *context = user_data; if (!context) { continue; } do { context = user_data; if (!context || !buf) { break; } if (!context->ps.net_buf || context->ps.net_buf != buf) { NET_DBG("psock init %p buf %p\n", &context->ps, buf); PSOCK_INIT(&context->ps, buf); } handle_tcp_connection(&context->ps, POINTER_TO_INT(data), buf); PROCESS_WAIT_EVENT_UNTIL(ev == tcpip_event); if (POINTER_TO_INT(data) != TCP_WRITE_EVENT) { goto read_data; } } while(!(uip_closed(buf) || uip_aborted(buf) || uip_timedout(buf))); context = user_data; if (context && context->tcp_type == NET_TCP_TYPE_CLIENT) { NET_DBG("\nConnection closed.\n"); ip_buf_sent_status(buf) = -ECONNRESET; } continue; } read_data: /* We are receiving data from peer. */ if (buf && uip_newdata(buf)) { struct net_buf *clone; if (!uip_len(buf)) { continue; } /* Note that uIP stack will reuse the buffer when * sending ACK to peer host. The sending will happen * right after this function returns. Because of this * we cannot use the same buffer to pass data to * application. */ clone = net_buf_clone(buf); if (!clone) { NET_ERR("No enough RX buffers, " "packet %p discarded\n", buf); continue; } ip_buf_appdata(clone) = uip_buf(clone) + (ip_buf_appdata(buf) - (void *)uip_buf(buf)); ip_buf_appdatalen(clone) = uip_len(buf); ip_buf_len(clone) = ip_buf_len(buf); ip_buf_context(clone) = user_data; uip_set_conn(clone) = uip_conn(buf); uip_flags(clone) = uip_flags(buf); uip_flags(clone) |= UIP_CONNECTED; NET_DBG("packet received context %p buf %p len %d " "appdata %p appdatalen %d\n", ip_buf_context(clone), clone, ip_buf_len(clone), ip_buf_appdata(clone), ip_buf_appdatalen(clone)); nano_fifo_put(net_context_get_queue(user_data), clone); /* We let the application to read the data now */ fiber_yield(); } } PROCESS_END(); }