static void tcp_received(struct net_context *context, struct net_pkt *pkt, int status, void *user_data) { static char dbg[MAX_DBG_PRINT + 1]; sa_family_t family = net_pkt_family(pkt); struct net_pkt *reply_pkt; int ret; snprintf(dbg, MAX_DBG_PRINT, "TCP IPv%c", family == AF_INET6 ? '6' : '4'); reply_pkt = build_reply_pkt(dbg, context, pkt); net_pkt_unref(pkt); ret = net_context_send(reply_pkt, pkt_sent, K_NO_WAIT, UINT_TO_POINTER(net_pkt_get_len(reply_pkt)), NULL); if (ret < 0) { printk("Cannot send data to peer (%d)", ret); net_pkt_unref(reply_pkt); quit(); } }
static void send_tcp_data(struct net_app_ctx *ctx, struct data *data) { struct net_pkt *pkt; size_t len; int ret; do { data->expecting_tcp = sys_rand32_get() % ipsum_len; } while (data->expecting_tcp == 0); data->received_tcp = 0; pkt = prepare_send_pkt(ctx, data->proto, data->expecting_tcp); if (!pkt) { return; } len = net_pkt_get_len(pkt); NET_ASSERT_INFO(data->expecting_tcp == len, "%s data to send %d bytes, real len %zu", data->proto, data->expecting_tcp, len); ret = net_app_send_pkt(ctx, pkt, NULL, 0, K_FOREVER, UINT_TO_POINTER(len)); if (ret < 0) { NET_ERR("Cannot send %s data to peer (%d)", data->proto, ret); net_pkt_unref(pkt); } }
static void udp_received(struct net_context *context, struct net_pkt *pkt, int status, void *user_data) { struct net_pkt *reply_pkt; struct sockaddr dst_addr; sa_family_t family = net_pkt_family(pkt); static char dbg[MAX_DBG_PRINT + 1]; int ret; snprintf(dbg, MAX_DBG_PRINT, "UDP IPv%c", family == AF_INET6 ? '6' : '4'); set_dst_addr(family, pkt, &dst_addr); reply_pkt = build_reply_pkt(dbg, context, pkt); net_pkt_unref(pkt); ret = net_context_sendto(reply_pkt, &dst_addr, family == AF_INET6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in), pkt_sent, 0, UINT_TO_POINTER(net_pkt_get_len(reply_pkt)), user_data); if (ret < 0) { printk("Cannot send data to peer (%d)", ret); net_pkt_unref(reply_pkt); } }
int net_ipv4_finalize_raw(struct net_pkt *pkt, u8_t next_header) { /* Set the length of the IPv4 header */ size_t total_len; net_pkt_compact(pkt); total_len = net_pkt_get_len(pkt); NET_IPV4_HDR(pkt)->len[0] = total_len / 256; NET_IPV4_HDR(pkt)->len[1] = total_len - NET_IPV4_HDR(pkt)->len[0] * 256; NET_IPV4_HDR(pkt)->chksum = 0; NET_IPV4_HDR(pkt)->chksum = ~net_calc_chksum_ipv4(pkt); #if defined(CONFIG_NET_UDP) if (next_header == IPPROTO_UDP) { NET_UDP_HDR(pkt)->chksum = 0; NET_UDP_HDR(pkt)->chksum = ~net_calc_chksum_udp(pkt); } #endif #if defined(CONFIG_NET_TCP) if (next_header == IPPROTO_TCP) { NET_TCP_HDR(pkt)->chksum = 0; NET_TCP_HDR(pkt)->chksum = ~net_calc_chksum_tcp(pkt); } #endif return 0; }
int udp_tx(void *context, const unsigned char *buf, size_t size) { struct udp_context *ctx = context; struct net_context *net_ctx; struct net_pkt *send_pkt; int rc, len; net_ctx = ctx->net_ctx; send_pkt = net_pkt_get_tx(net_ctx, K_FOREVER); if (!send_pkt) { printk("cannot create pkt\n"); return -EIO; } rc = net_pkt_append_all(send_pkt, size, (u8_t *) buf, K_FOREVER); if (!rc) { printk("cannot write buf\n"); return -EIO; } len = net_pkt_get_len(send_pkt); rc = net_context_sendto(send_pkt, &net_ctx->remote, addrlen, NULL, K_FOREVER, NULL, NULL); if (rc < 0) { printk("Cannot send data to peer (%d)\n", rc); net_pkt_unref(send_pkt); return -EIO; } else { return len; } }
int net_recv_data(struct net_if *iface, struct net_pkt *pkt) { SYS_LOG_DBG("Got data, pkt %p, frags->len %d", pkt, net_pkt_get_len(pkt)); k_fifo_put(&tx_queue, pkt); return 0; }
static enum net_verdict net_bt_recv(struct net_if *iface, struct net_pkt *pkt) { NET_DBG("iface %p pkt %p len %zu", iface, pkt, net_pkt_get_len(pkt)); if (!net_6lo_uncompress(pkt)) { NET_DBG("Packet decompression failed"); return NET_DROP; } return NET_CONTINUE; }
static struct net_pkt *build_reply_pkt(const char *name, struct net_context *context, struct net_pkt *pkt) { struct net_pkt *reply_pkt; struct net_buf *tmp; int header_len, recv_len, reply_len; printk("%s received %d bytes", name, net_pkt_appdatalen(pkt)); reply_pkt = net_pkt_get_tx(context, K_FOREVER); recv_len = net_pkt_get_len(pkt); tmp = pkt->frags; /* Remove frag link so original pkt can be unrefed */ pkt->frags = NULL; /* First fragment will contain IP header so move the data * down in order to get rid of it. */ header_len = net_pkt_appdata(pkt) - tmp->data; /* After this pull, the tmp->data points directly to application * data. */ net_buf_pull(tmp, header_len); /* Add the entire chain into reply */ net_pkt_frag_add(reply_pkt, tmp); reply_len = net_pkt_get_len(reply_pkt); printk("Received %d bytes, sending %d bytes", recv_len - header_len, reply_len); return reply_pkt; }
static enum net_verdict ieee802154_recv(struct net_if *iface, struct net_pkt *pkt) { struct ieee802154_mpdu mpdu; if (!ieee802154_validate_frame(net_pkt_ll(pkt), net_pkt_get_len(pkt), &mpdu)) { return NET_DROP; } if (mpdu.mhr.fs->fc.frame_type == IEEE802154_FRAME_TYPE_BEACON) { return ieee802154_handle_beacon(iface, &mpdu); } if (ieee802154_is_scanning(iface)) { return NET_DROP; } if (mpdu.mhr.fs->fc.frame_type == IEEE802154_FRAME_TYPE_MAC_COMMAND) { return ieee802154_handle_mac_command(iface, &mpdu); } /* At this point the frame has to be a DATA one */ ieee802154_acknowledge(iface, &mpdu); net_pkt_set_ll_reserve(pkt, mpdu.payload - (void *)net_pkt_ll(pkt)); net_buf_pull(pkt->frags, net_pkt_ll_reserve(pkt)); set_pkt_ll_addr(net_pkt_ll_src(pkt), mpdu.mhr.fs->fc.pan_id_comp, mpdu.mhr.fs->fc.src_addr_mode, mpdu.mhr.src_addr); set_pkt_ll_addr(net_pkt_ll_dst(pkt), false, mpdu.mhr.fs->fc.dst_addr_mode, mpdu.mhr.dst_addr); if (!ieee802154_decipher_data_frame(iface, pkt, &mpdu)) { return NET_DROP; } pkt_hexdump(pkt, true); return ieee802154_manage_recv_packet(iface, pkt); }
static void net_rx_thread(void) { struct net_pkt *pkt; NET_DBG("Starting RX thread (stack %zu bytes)", sizeof(rx_stack)); /* Starting TX side. The ordering is important here and the TX * can only be started when RX side is ready to receive packets. * We synchronize the startup of the device so that both RX and TX * are only started fully when both are ready to receive or send * data. */ net_if_init(&startup_sync); k_sem_take(&startup_sync, K_FOREVER); /* This will take the interface up and start everything. */ net_if_post_init(); while (1) { #if defined(CONFIG_NET_STATISTICS) || defined(CONFIG_NET_DEBUG_CORE) size_t pkt_len; #endif pkt = k_fifo_get(&rx_queue, K_FOREVER); net_analyze_stack("RX thread", rx_stack, sizeof(rx_stack)); #if defined(CONFIG_NET_STATISTICS) || defined(CONFIG_NET_DEBUG_CORE) pkt_len = net_pkt_get_len(pkt); #endif NET_DBG("Received pkt %p len %zu", pkt, pkt_len); net_stats_update_bytes_recv(pkt_len); processing_data(pkt, false); net_print_statistics(); net_pkt_print(); k_yield(); } }
bool ieee802154_decipher_data_frame(struct net_if *iface, struct net_pkt *pkt, struct ieee802154_mpdu *mpdu) { struct ieee802154_context *ctx = net_if_l2_data(iface); u8_t level; if (!mpdu->mhr.fs->fc.security_enabled) { return true; } /* Section 7.2.3 (i) talks about "security level policy" conformance * but such policy does not seem to be detailed. So let's assume both * ends should have same security level. */ if (mpdu->mhr.aux_sec->control.security_level != ctx->sec_ctx.level) { return false; } /* ToDo: handle src short address * This will require to look up in nbr cache with short addr * in order to get the extended address related to it */ if (!ieee802154_decrypt_auth(&ctx->sec_ctx, net_pkt_ll(pkt), net_pkt_ll_reserve(pkt), net_pkt_get_len(pkt), net_pkt_ll_src(pkt)->addr, sys_le32_to_cpu( mpdu->mhr.aux_sec->frame_counter))) { NET_ERR("Could not decipher the frame"); return false; } level = ctx->sec_ctx.level; if (level >= IEEE802154_SECURITY_LEVEL_ENC) { level -= 4; } /* We remove tag size from frag's length, it is now useless */ pkt->frags->len -= level_2_tag_size[level]; return true; }
static enum net_verdict net_bt_send(struct net_if *iface, struct net_pkt *pkt) { struct bt_context *ctxt = net_if_get_device(iface)->driver_data; NET_DBG("iface %p pkt %p len %zu", iface, pkt, net_pkt_get_len(pkt)); /* Only accept IPv6 packets */ if (net_pkt_family(pkt) != AF_INET6) { return NET_DROP; } if (!net_6lo_compress(pkt, true, NULL)) { NET_DBG("Packet compression failed"); return NET_DROP; } net_if_queue_tx(ctxt->iface, pkt); return NET_OK; }
static int bt_iface_send(struct net_if *iface, struct net_pkt *pkt) { struct bt_context *ctxt = net_if_get_device(iface)->driver_data; struct net_buf *frags; int ret; NET_DBG("iface %p pkt %p len %zu", iface, pkt, net_pkt_get_len(pkt)); /* Dettach data fragments for packet */ frags = pkt->frags; pkt->frags = NULL; net_pkt_unref(pkt); ret = bt_l2cap_chan_send(&ctxt->ipsp_chan.chan, frags); if (ret < 0) { return ret; } return ret; }
/** * TX - transmit to SLIP interface */ static void tx_thread(void) { SYS_LOG_DBG("TX thread started"); /* Allow to send one TX */ k_sem_give(&tx_sem); while (1) { struct net_pkt *pkt; struct net_buf *buf; size_t len; k_sem_take(&tx_sem, K_FOREVER); pkt = k_fifo_get(&tx_queue, K_FOREVER); buf = net_buf_frag_last(pkt->frags); len = net_pkt_get_len(pkt); SYS_LOG_DBG("Send pkt %p buf %p len %d", pkt, buf, len); hexdump("SLIP <", buf->data, buf->len); /* Remove LQI */ /* TODO: Reuse get_lqi() */ buf->len -= 1; /* remove FCS 2 bytes */ buf->len -= 2; /* SLIP encode and send */ len = slip_buffer(slip_buf, buf); uart_fifo_fill(uart_dev, slip_buf, len); net_pkt_unref(pkt); #if 0 k_yield(); #endif } }
/* Called by driver when an IP packet has been received */ int net_recv_data(struct net_if *iface, struct net_pkt *pkt) { NET_ASSERT(pkt && pkt->frags); NET_ASSERT(iface); if (!pkt->frags) { return -ENODATA; } if (!atomic_test_bit(iface->flags, NET_IF_UP)) { return -ENETDOWN; } NET_DBG("fifo %p iface %p pkt %p len %zu", &rx_queue, iface, pkt, net_pkt_get_len(pkt)); net_pkt_set_iface(pkt, iface); k_fifo_put(&rx_queue, pkt); return 0; }
static inline void telnet_handle_input(struct net_pkt *pkt) { struct console_input *input; u16_t len, offset, pos; len = net_pkt_appdatalen(pkt); if (len > CONSOLE_MAX_LINE_LEN || len < TELNET_MIN_MSG) { return; } if (telnet_handle_command(pkt)) { return; } if (!avail_queue || !input_queue) { return; } input = k_fifo_get(avail_queue, K_NO_WAIT); if (!input) { return; } offset = net_pkt_get_len(pkt) - len; net_frag_read(pkt->frags, offset, &pos, len, input->line); /* LF/CR will be removed if only the line is not NUL terminated */ if (input->line[len-1] != NVT_NUL) { if (input->line[len-1] == NVT_LF) { input->line[len-1] = NVT_NUL; } if (input->line[len-2] == NVT_CR) { input->line[len-2] = NVT_NUL; } } k_fifo_put(input_queue, input); }
static int eth_send(struct device *dev, struct net_pkt *pkt) { struct eth_context *ctx = dev->driver_data; int count = net_pkt_get_len(pkt); int ret; ret = net_pkt_read(pkt, ctx->send, count); if (ret) { return ret; } update_gptp(net_pkt_iface(pkt), pkt, true); LOG_DBG("Send pkt %p len %d", pkt, count); ret = eth_write_data(ctx->dev_fd, ctx->send, count); if (ret < 0) { LOG_DBG("Cannot send pkt %p (%d)", pkt, ret); } return ret < 0 ? ret : 0; }
static void test_fragment_compact(void) { struct net_pkt *pkt; struct net_buf *frags[FRAG_COUNT], *frag; int i, bytes, total, count; pkt = net_pkt_get_reserve_rx(0, K_FOREVER); frag = NULL; for (i = 0, total = 0; i < FRAG_COUNT; i++) { frags[i] = net_pkt_get_reserve_rx_data(12, K_FOREVER); if (frag) { net_buf_frag_add(frag, frags[i]); } frag = frags[i]; /* Copy character test data in front of the fragment */ memcpy(net_buf_add(frags[i], sizeof(test_data)), test_data, sizeof(test_data)); /* Followed by bytes of zeroes */ memset(net_buf_add(frags[i], sizeof(test_data)), 0, sizeof(test_data)); total++; } if (total != FRAG_COUNT) { printk("There should be %d fragments but was %d\n", FRAG_COUNT, total); zassert_true(false, "Invalid fragment count"); } DBG("step 1\n"); pkt->frags = net_buf_frag_add(pkt->frags, frags[0]); bytes = net_pkt_get_len(pkt); if (bytes != FRAG_COUNT * sizeof(test_data) * 2) { printk("Compact test failed, fragments had %d bytes but " "should have had %zd\n", bytes, FRAG_COUNT * sizeof(test_data) * 2); zassert_true(false, "Invalid fragment bytes"); } zassert_false(net_pkt_is_compact(pkt), "The pkt is definitely not compact"); DBG("step 2\n"); net_pkt_compact(pkt); zassert_true(net_pkt_is_compact(pkt), "The pkt should be in compact form"); DBG("step 3\n"); /* Try compacting again, nothing should happen */ net_pkt_compact(pkt); zassert_true(net_pkt_is_compact(pkt), "The pkt should be compacted now"); total = calc_fragments(pkt); /* Add empty fragment at the end and compact, the last fragment * should be removed. */ frag = net_pkt_get_reserve_rx_data(0, K_FOREVER); net_pkt_frag_add(pkt, frag); count = calc_fragments(pkt); DBG("step 4\n"); net_pkt_compact(pkt); i = calc_fragments(pkt); if (count != (i + 1)) { printk("Last fragment removal failed, chain should have %d " "fragments but had %d\n", i-1, i); zassert_true(false, "Last frag rm fails"); } if (i != total) { printk("Fragments missing, expecting %d but got %d\n", total, i); zassert_true(false, "Frags missing"); } /* Add two empty fragments at the end and compact, the last two * fragment should be removed. */ frag = net_pkt_get_reserve_rx_data(0, K_FOREVER); net_pkt_frag_add(pkt, frag); frag = net_pkt_get_reserve_rx_data(0, K_FOREVER); net_pkt_frag_add(pkt, frag); count = calc_fragments(pkt); DBG("step 5\n"); net_pkt_compact(pkt); i = calc_fragments(pkt); if (count != (i + 2)) { printk("Last two fragment removal failed, chain should have " "%d fragments but had %d\n", i-2, i); zassert_true(false, "Last two frag rm fails"); } if (i != total) { printk("Fragments missing, expecting %d but got %d\n", total, i); zassert_true(false, "Frags missing"); } /* Add empty fragment at the beginning and at the end, and then * compact, the two fragment should be removed. */ frag = net_pkt_get_reserve_rx_data(0, K_FOREVER); net_pkt_frag_insert(pkt, frag); frag = net_pkt_get_reserve_rx_data(0, K_FOREVER); net_pkt_frag_add(pkt, frag); count = calc_fragments(pkt); DBG("step 6\n"); net_pkt_compact(pkt); i = calc_fragments(pkt); if (count != (i + 2)) { printk("Two fragment removal failed, chain should have " "%d fragments but had %d\n", i-2, i); zassert_true(false, "Two frag rm fails"); } if (i != total) { printk("Fragments missing, expecting %d but got %d\n", total, i); zassert_true(false, "Frags missing"); } DBG("test_fragment_compact passed\n"); }
static struct net_pkt *build_reply_pkt(const char *name, struct net_context *context, struct net_pkt *pkt) { struct net_pkt *reply_pkt; struct net_buf *frag, *tmp; int header_len, recv_len, reply_len; NET_INFO("%s received %d bytes", name, net_pkt_appdatalen(pkt)); if (net_pkt_appdatalen(pkt) == 0) { return NULL; } reply_pkt = net_pkt_get_tx(context, K_FOREVER); NET_ASSERT(reply_pkt); recv_len = net_pkt_get_len(pkt); tmp = pkt->frags; /* First fragment will contain IP header so move the data * down in order to get rid of it. */ header_len = net_pkt_appdata(pkt) - tmp->data; NET_ASSERT(header_len < CONFIG_NET_BUF_DATA_SIZE); /* After this pull, the tmp->data points directly to application * data. */ net_buf_pull(tmp, header_len); while (tmp) { frag = net_pkt_get_data(context, K_FOREVER); if (!net_buf_headroom(tmp)) { /* If there is no link layer headers in the * received fragment, then get rid of that also * in the sending fragment. We end up here * if MTU is larger than fragment size, this * is typical for ethernet. */ net_buf_push(frag, net_buf_headroom(frag)); frag->len = 0; /* to make fragment empty */ /* Make sure to set the reserve so that * in sending side we add the link layer * header if needed. */ net_pkt_set_ll_reserve(reply_pkt, 0); } NET_ASSERT(net_buf_tailroom(frag) >= tmp->len); memcpy(net_buf_add(frag, tmp->len), tmp->data, tmp->len); net_pkt_frag_add(reply_pkt, frag); tmp = net_pkt_frag_del(pkt, NULL, tmp); } reply_len = net_pkt_get_len(reply_pkt); NET_ASSERT_INFO((recv_len - header_len) == reply_len, "Received %d bytes, sending %d bytes", recv_len - header_len, reply_len); return reply_pkt; }
static void test_pkt_read_append(void) { int remaining = strlen(sample_data); u8_t verify_rw_short[sizeof(test_rw_short)]; u8_t verify_rw_long[sizeof(test_rw_long)]; struct net_pkt *pkt; struct net_buf *frag; struct net_buf *tfrag; struct ipv6_hdr *ipv6; struct udp_hdr *udp; u8_t data[10]; int pos = 0; int bytes; u16_t off; u16_t tpos; u16_t fail_pos; /* Example of multi fragment read, append and skip APS's */ pkt = net_pkt_get_reserve_rx(0, K_FOREVER); frag = net_pkt_get_reserve_rx_data(LL_RESERVE, K_FOREVER); /* Place the IP + UDP header in the first fragment */ if (!net_buf_tailroom(frag)) { ipv6 = (struct ipv6_hdr *)(frag->data); udp = (struct udp_hdr *)((void *)ipv6 + sizeof(*ipv6)); if (net_buf_tailroom(frag) < sizeof(ipv6)) { printk("Not enough space for IPv6 header, " "needed %zd bytes, has %zd bytes\n", sizeof(ipv6), net_buf_tailroom(frag)); zassert_true(false, "No space for IPv6 header"); } net_buf_add(frag, sizeof(ipv6)); if (net_buf_tailroom(frag) < sizeof(udp)) { printk("Not enough space for UDP header, " "needed %zd bytes, has %zd bytes\n", sizeof(udp), net_buf_tailroom(frag)); zassert_true(false, "No space for UDP header"); } net_pkt_set_appdata(pkt, (void *)udp + sizeof(*udp)); net_pkt_set_appdatalen(pkt, 0); } net_pkt_frag_add(pkt, frag); /* Put some data to rest of the fragments */ frag = net_pkt_get_reserve_rx_data(LL_RESERVE, K_FOREVER); if (net_buf_tailroom(frag) - (CONFIG_NET_BUF_DATA_SIZE - LL_RESERVE)) { printk("Invalid number of bytes available in the buf, " "should be 0 but was %zd - %d\n", net_buf_tailroom(frag), CONFIG_NET_BUF_DATA_SIZE - LL_RESERVE); zassert_true(false, "Invalid number of bytes avail"); } if (((int)net_buf_tailroom(frag) - remaining) > 0) { printk("We should have been out of space now, " "tailroom %zd user data len %zd\n", net_buf_tailroom(frag), strlen(sample_data)); zassert_true(false, "Not out of space"); } while (remaining > 0) { int copy; bytes = net_buf_tailroom(frag); copy = remaining > bytes ? bytes : remaining; memcpy(net_buf_add(frag, copy), &sample_data[pos], copy); DBG("Remaining %d left %d copy %d\n", remaining, bytes, copy); pos += bytes; remaining -= bytes; if (net_buf_tailroom(frag) - (bytes - copy)) { printk("There should have not been any tailroom left, " "tailroom %zd\n", net_buf_tailroom(frag) - (bytes - copy)); zassert_true(false, "Still tailroom left"); } net_pkt_frag_add(pkt, frag); if (remaining > 0) { frag = net_pkt_get_reserve_rx_data(LL_RESERVE, K_FOREVER); } } bytes = net_pkt_get_len(pkt); if (bytes != strlen(sample_data)) { printk("Invalid number of bytes in message, %zd vs %d\n", strlen(sample_data), bytes); zassert_true(false, "Message size wrong"); } /* Failure cases */ /* Invalid buffer */ tfrag = net_frag_skip(NULL, 10, &fail_pos, 10); zassert_true(!tfrag && fail_pos == 0xffff, "Invalid case NULL buffer"); /* Invalid: Skip more than a buffer length.*/ tfrag = net_buf_frag_last(pkt->frags); tfrag = net_frag_skip(tfrag, tfrag->len - 1, &fail_pos, tfrag->len + 2); if (!(!tfrag && fail_pos == 0xffff)) { printk("Invalid case offset %d length to skip %d," "frag length %d\n", tfrag->len - 1, tfrag->len + 2, tfrag->len); zassert_true(false, "Invalid offset"); } /* Invalid offset */ tfrag = net_buf_frag_last(pkt->frags); tfrag = net_frag_skip(tfrag, tfrag->len + 10, &fail_pos, 10); if (!(!tfrag && fail_pos == 0xffff)) { printk("Invalid case offset %d length to skip %d," "frag length %d\n", tfrag->len + 10, 10, tfrag->len); zassert_true(false, "Invalid offset"); } /* Valid cases */ /* Offset is more than single fragment length */ /* Get the first data fragment */ tfrag = pkt->frags; tfrag = tfrag->frags; off = tfrag->len; tfrag = net_frag_read(tfrag, off + 10, &tpos, 10, data); if (!tfrag || memcmp(sample_data + off + 10, data, 10)) { printk("Failed to read from offset %d, frag length %d " "read length %d\n", tfrag->len + 10, tfrag->len, 10); zassert_true(false, "Fail offset read"); } /* Skip till end of all fragments */ /* Get the first data fragment */ tfrag = pkt->frags; tfrag = tfrag->frags; tfrag = net_frag_skip(tfrag, 0, &tpos, strlen(sample_data)); zassert_true(!tfrag && tpos == 0, "Invalid skip till end of all fragments"); /* Short data test case */ /* Test case scenario: * 1) Cache the current fragment and offset * 2) Append short data * 3) Append short data again * 4) Skip first short data from cached frag or offset * 5) Read short data and compare */ tfrag = net_buf_frag_last(pkt->frags); off = tfrag->len; zassert_true(net_pkt_append_all(pkt, (u16_t)sizeof(test_rw_short), test_rw_short, K_FOREVER), "net_pkt_append failed"); zassert_true(net_pkt_append_all(pkt, (u16_t)sizeof(test_rw_short), test_rw_short, K_FOREVER), "net_pkt_append failed"); tfrag = net_frag_skip(tfrag, off, &tpos, (u16_t)sizeof(test_rw_short)); zassert_not_null(tfrag, "net_frag_skip failed"); tfrag = net_frag_read(tfrag, tpos, &tpos, (u16_t)sizeof(test_rw_short), verify_rw_short); zassert_true(!tfrag && tpos == 0, "net_frag_read failed"); zassert_false(memcmp(test_rw_short, verify_rw_short, sizeof(test_rw_short)), "net_frag_read failed with mismatch data"); /* Long data test case */ /* Test case scenario: * 1) Cache the current fragment and offset * 2) Append long data * 3) Append long data again * 4) Skip first long data from cached frag or offset * 5) Read long data and compare */ tfrag = net_buf_frag_last(pkt->frags); off = tfrag->len; zassert_true(net_pkt_append_all(pkt, (u16_t)sizeof(test_rw_long), test_rw_long, K_FOREVER), "net_pkt_append failed"); zassert_true(net_pkt_append_all(pkt, (u16_t)sizeof(test_rw_long), test_rw_long, K_FOREVER), "net_pkt_append failed"); tfrag = net_frag_skip(tfrag, off, &tpos, (u16_t)sizeof(test_rw_long)); zassert_not_null(tfrag, "net_frag_skip failed"); tfrag = net_frag_read(tfrag, tpos, &tpos, (u16_t)sizeof(test_rw_long), verify_rw_long); zassert_true(!tfrag && tpos == 0, "net_frag_read failed"); zassert_false(memcmp(test_rw_long, verify_rw_long, sizeof(test_rw_long)), "net_frag_read failed with mismatch data"); net_pkt_unref(pkt); DBG("test_pkt_read_append passed\n"); }
static void http_receive_cb(struct http_client_ctx *ctx, struct net_pkt *pkt) { size_t start = ctx->rsp.data_len; size_t len = 0; struct net_buf *frag; int header_len; if (!pkt) { return; } /* Get rid of possible IP headers in the first fragment. */ frag = pkt->frags; header_len = net_pkt_appdata(pkt) - frag->data; NET_DBG("Received %d bytes data", net_pkt_appdatalen(pkt)); /* After this pull, the frag->data points directly to application data. */ net_buf_pull(frag, header_len); while (frag) { /* If this fragment cannot be copied to result buf, * then parse what we have which will cause the callback to be * called in function on_body(), and continue copying. */ if (ctx->rsp.data_len + frag->len > ctx->rsp.response_buf_len) { /* If the caller has not supplied a callback, then * we cannot really continue if the response buffer * overflows. Set the data_len to mark how many bytes * should be needed in the response_buf. */ if (!ctx->rsp.cb) { ctx->rsp.data_len = net_pkt_get_len(pkt); goto out; } http_parser_execute(&ctx->parser, &ctx->settings, ctx->rsp.response_buf + start, len); ctx->rsp.data_len = 0; len = 0; start = 0; } memcpy(ctx->rsp.response_buf + ctx->rsp.data_len, frag->data, frag->len); ctx->rsp.data_len += frag->len; len += frag->len; frag = frag->frags; } out: /* The parser's error can be catched outside, reading the * http_errno struct member */ http_parser_execute(&ctx->parser, &ctx->settings, ctx->rsp.response_buf + start, len); net_pkt_unref(pkt); }
void http_rx_tx(struct net_context *net_ctx, struct net_pkt *rx, int status, void *user_data) { struct http_server_ctx *http_ctx = NULL; struct net_buf *data = NULL; u16_t rcv_len; u16_t offset; int parsed_len; int rc; if (status) { printf("[%s:%d] Status code: %d, <%s>\n", __func__, __LINE__, status, RC_STR(status)); goto lb_exit; } if (!user_data) { printf("[%s:%d] User data is null\n", __func__, __LINE__); goto lb_exit; } http_ctx = (struct http_server_ctx *)user_data; if (http_ctx->net_ctx != net_ctx) { printf("[%s:%d] Wrong network context received\n", __func__, __LINE__); goto lb_exit; } if (!rx) { printf("[%s:%d] Connection closed by peer\n", __func__, __LINE__); goto lb_exit; } rcv_len = net_pkt_appdatalen(rx); if (rcv_len == 0) { /* don't print info about zero-length app data buffers */ goto lb_exit; } data = net_buf_alloc(&http_msg_pool, APP_SLEEP_MSECS); if (data == NULL) { printf("[%s:%d] Data buffer alloc error\n", __func__, __LINE__); goto lb_exit; } offset = net_pkt_get_len(rx) - rcv_len; rc = net_frag_linear_copy(data, rx->frags, offset, rcv_len); if (rc != 0) { printf("[%s:%d] Linear copy error\n", __func__, __LINE__); goto lb_exit; } data->data[min(data->size - 1, rcv_len)] = 0; parser_init(http_ctx); parsed_len = parser_parse_request(http_ctx, data); if (parsed_len <= 0) { printf("[%s:%d] Received: %u bytes, only parsed: %d bytes\n", __func__, __LINE__, rcv_len, parsed_len); } if (http_ctx->parser.http_errno != HPE_OK) { http_response_400(http_ctx, NULL); } else { http_tx(http_ctx); } lb_exit: net_pkt_frag_unref(data); net_pkt_unref(rx); http_ctx_release(http_ctx); }
static void test_fragment_copy(void) { struct net_pkt *pkt, *new_pkt; struct net_buf *frag, *new_frag; struct ipv6_hdr *ipv6; struct udp_hdr *udp; size_t orig_len, reserve; int pos; pkt = net_pkt_get_reserve_rx(0, K_FOREVER); frag = net_pkt_get_reserve_rx_data(LL_RESERVE, K_FOREVER); /* Place the IP + UDP header in the first fragment */ if (net_buf_tailroom(frag)) { ipv6 = (struct ipv6_hdr *)(frag->data); udp = (struct udp_hdr *)((void *)ipv6 + sizeof(*ipv6)); if (net_buf_tailroom(frag) < sizeof(*ipv6)) { printk("Not enough space for IPv6 header, " "needed %zd bytes, has %zd bytes\n", sizeof(ipv6), net_buf_tailroom(frag)); zassert_true(false, "No space for IPv6 header"); } net_buf_add(frag, sizeof(*ipv6)); if (net_buf_tailroom(frag) < sizeof(*udp)) { printk("Not enough space for UDP header, " "needed %zd bytes, has %zd bytes\n", sizeof(udp), net_buf_tailroom(frag)); zassert_true(false, "No space for UDP header"); } net_buf_add(frag, sizeof(*udp)); memcpy(net_buf_add(frag, 15), example_data, 15); net_pkt_set_appdata(pkt, (void *)udp + sizeof(*udp) + 15); net_pkt_set_appdatalen(pkt, 0); } net_pkt_frag_add(pkt, frag); orig_len = net_pkt_get_len(pkt); DBG("Total copy data len %zd\n", orig_len); linearize(pkt, buf_orig, orig_len); /* Then copy a fragment list to a new fragment list. * Reserve some space in front of the buffers. */ reserve = sizeof(struct ipv6_hdr) + sizeof(struct icmp_hdr); new_frag = net_pkt_copy_all(pkt, reserve, K_FOREVER); zassert_not_null(new_frag, "Cannot copy fragment list"); new_pkt = net_pkt_get_reserve_tx(0, K_FOREVER); new_pkt->frags = net_buf_frag_add(new_pkt->frags, new_frag); DBG("Total new data len %zd\n", net_pkt_get_len(new_pkt)); if ((net_pkt_get_len(pkt) + reserve) != net_pkt_get_len(new_pkt)) { int diff; diff = net_pkt_get_len(new_pkt) - reserve - net_pkt_get_len(pkt); printk("Fragment list missing data, %d bytes not copied " "(%zd vs %zd)\n", diff, net_pkt_get_len(pkt) + reserve, net_pkt_get_len(new_pkt)); zassert_true(false, "Frag list missing"); } if (net_pkt_get_len(new_pkt) != (orig_len + sizeof(struct ipv6_hdr) + sizeof(struct icmp_hdr))) { printk("Fragment list missing data, new pkt len %zd " "should be %zd\n", net_pkt_get_len(new_pkt), orig_len + sizeof(struct ipv6_hdr) + sizeof(struct icmp_hdr)); zassert_true(false, "Frag list missing data"); } linearize(new_pkt, buf_copy, sizeof(buf_copy)); zassert_true(memcmp(buf_orig, buf_copy, sizeof(buf_orig)), "Buffer copy failed, buffers are same"); pos = memcmp(buf_orig, buf_copy + sizeof(struct ipv6_hdr) + sizeof(struct icmp_hdr), orig_len); if (pos) { printk("Buffer copy failed at pos %d\n", pos); zassert_true(false, "Buf copy failed"); } }
static void test_ipv6_multi_frags(void) { struct net_pkt *pkt; struct net_buf *frag; struct ipv6_hdr *ipv6; struct udp_hdr *udp; int bytes, remaining = strlen(example_data), pos = 0; /* Example of multi fragment scenario with IPv6 */ pkt = net_pkt_get_reserve_rx(0, K_FOREVER); frag = net_pkt_get_reserve_rx_data(LL_RESERVE, K_FOREVER); /* Place the IP + UDP header in the first fragment */ if (!net_buf_tailroom(frag)) { ipv6 = (struct ipv6_hdr *)(frag->data); udp = (struct udp_hdr *)((void *)ipv6 + sizeof(*ipv6)); if (net_buf_tailroom(frag) < sizeof(ipv6)) { printk("Not enough space for IPv6 header, " "needed %zd bytes, has %zd bytes\n", sizeof(ipv6), net_buf_tailroom(frag)); zassert_true(false, "No space for IPv6 header"); } net_buf_add(frag, sizeof(ipv6)); if (net_buf_tailroom(frag) < sizeof(udp)) { printk("Not enough space for UDP header, " "needed %zd bytes, has %zd bytes\n", sizeof(udp), net_buf_tailroom(frag)); zassert_true(false, "No space for UDP header"); } net_pkt_set_appdata(pkt, (void *)udp + sizeof(*udp)); net_pkt_set_appdatalen(pkt, 0); } net_pkt_frag_add(pkt, frag); /* Put some data to rest of the fragments */ frag = net_pkt_get_reserve_rx_data(LL_RESERVE, K_FOREVER); if (net_buf_tailroom(frag) - (CONFIG_NET_BUF_DATA_SIZE - LL_RESERVE)) { printk("Invalid number of bytes available in the buf, " "should be 0 but was %zd - %d\n", net_buf_tailroom(frag), CONFIG_NET_BUF_DATA_SIZE - LL_RESERVE); zassert_true(false, "Invalid byte count"); } if (((int)net_buf_tailroom(frag) - remaining) > 0) { printk("We should have been out of space now, " "tailroom %zd user data len %zd\n", net_buf_tailroom(frag), strlen(example_data)); zassert_true(false, "Still space"); } while (remaining > 0) { int copy; bytes = net_buf_tailroom(frag); copy = remaining > bytes ? bytes : remaining; memcpy(net_buf_add(frag, copy), &example_data[pos], copy); DBG("Remaining %d left %d copy %d\n", remaining, bytes, copy); pos += bytes; remaining -= bytes; if (net_buf_tailroom(frag) - (bytes - copy)) { printk("There should have not been any tailroom left, " "tailroom %zd\n", net_buf_tailroom(frag) - (bytes - copy)); zassert_true(false, "There is still tailroom left"); } net_pkt_frag_add(pkt, frag); if (remaining > 0) { frag = net_pkt_get_reserve_rx_data(LL_RESERVE, K_FOREVER); } } bytes = net_pkt_get_len(pkt); if (bytes != strlen(example_data)) { printk("Invalid number of bytes in message, %zd vs %d\n", strlen(example_data), bytes); zassert_true(false, "Invalid number of bytes"); } /* Normally one should not unref the fragment list like this * because it will leave the pkt->frags pointing to already * freed fragment. */ net_pkt_frag_unref(pkt->frags); zassert_not_null(pkt->frags, "Frag list empty"); pkt->frags = NULL; /* to prevent double free */ net_pkt_unref(pkt); }
int http_request(struct http_client_ctx *ctx, struct http_client_request *req, s32_t timeout) { const char *method = http_method_str(req->method); struct net_pkt *pkt; int ret = -ENOMEM; pkt = net_pkt_get_tx(ctx->tcp.ctx, timeout); if (!pkt) { return -ENOMEM; } if (!net_pkt_append_all(pkt, strlen(method), (u8_t *)method, timeout)) { goto out; } /* Space after method string. */ if (!net_pkt_append_all(pkt, 1, (u8_t *)" ", timeout)) { goto out; } if (!net_pkt_append_all(pkt, strlen(req->url), (u8_t *)req->url, timeout)) { goto out; } if (!net_pkt_append_all(pkt, strlen(req->protocol), (u8_t *)req->protocol, timeout)) { goto out; } if (req->host) { if (!net_pkt_append_all(pkt, strlen(HTTP_HOST), (u8_t *)HTTP_HOST, timeout)) { goto out; } if (!net_pkt_append_all(pkt, strlen(req->host), (u8_t *)req->host, timeout)) { goto out; } if (!net_pkt_append_all(pkt, strlen(HTTP_CRLF), (u8_t *)HTTP_CRLF, timeout)) { goto out; } } if (req->header_fields) { if (!net_pkt_append_all(pkt, strlen(req->header_fields), (u8_t *)req->header_fields, timeout)) { goto out; } } if (req->content_type_value) { if (!net_pkt_append_all(pkt, strlen(HTTP_CONTENT_TYPE), (u8_t *)HTTP_CONTENT_TYPE, timeout)) { goto out; } if (!net_pkt_append_all(pkt, strlen(req->content_type_value), (u8_t *)req->content_type_value, timeout)) { goto out; } } if (req->payload && req->payload_size) { char content_len_str[HTTP_CONT_LEN_SIZE]; ret = snprintk(content_len_str, HTTP_CONT_LEN_SIZE, HTTP_CRLF "Content-Length: %u" HTTP_CRLF HTTP_CRLF, req->payload_size); if (ret <= 0 || ret >= HTTP_CONT_LEN_SIZE) { ret = -ENOMEM; goto out; } if (!net_pkt_append_all(pkt, ret, (u8_t *)content_len_str, timeout)) { ret = -ENOMEM; goto out; } if (!net_pkt_append_all(pkt, req->payload_size, (u8_t *)req->payload, timeout)) { ret = -ENOMEM; goto out; } } else { if (!net_pkt_append_all(pkt, strlen(HTTP_EOF), (u8_t *)HTTP_EOF, timeout)) { goto out; } } #if defined(CONFIG_NET_IPV6) if (net_pkt_family(pkt) == AF_INET6) { net_pkt_set_appdatalen(pkt, net_pkt_get_len(pkt) - net_pkt_ip_hdr_len(pkt) - net_pkt_ipv6_ext_opt_len(pkt)); } else #endif { net_pkt_set_appdatalen(pkt, net_pkt_get_len(pkt) - net_pkt_ip_hdr_len(pkt)); } ret = ctx->tcp.send_data(pkt, NULL, timeout, NULL, ctx); if (ret == 0) { return 0; } out: net_pkt_unref(pkt); return ret; }
enum net_verdict net_ipv4_process_pkt(struct net_pkt *pkt) { struct net_ipv4_hdr *hdr = NET_IPV4_HDR(pkt); int real_len = net_pkt_get_len(pkt); int pkt_len = (hdr->len[0] << 8) + hdr->len[1]; enum net_verdict verdict = NET_DROP; if (real_len != pkt_len) { NET_DBG("IPv4 packet size %d pkt len %d", pkt_len, real_len); goto drop; } #if defined(CONFIG_NET_DEBUG_IPV4) do { char out[sizeof("xxx.xxx.xxx.xxx")]; snprintk(out, sizeof(out), "%s", net_sprint_ipv4_addr(&hdr->dst)); NET_DBG("IPv4 packet received from %s to %s", net_sprint_ipv4_addr(&hdr->src), out); } while (0); #endif /* CONFIG_NET_DEBUG_IPV4 */ net_pkt_set_ip_hdr_len(pkt, sizeof(struct net_ipv4_hdr)); if (!net_is_my_ipv4_addr(&hdr->dst)) { #if defined(CONFIG_NET_DHCPV4) if (hdr->proto == IPPROTO_UDP && net_ipv4_addr_cmp(&hdr->dst, net_ipv4_broadcast_address())) { verdict = net_conn_input(IPPROTO_UDP, pkt); if (verdict != NET_DROP) { return verdict; } } #endif NET_DBG("IPv4 packet in pkt %p not for me", pkt); goto drop; } switch (hdr->proto) { case IPPROTO_ICMP: verdict = process_icmpv4_pkt(pkt, hdr); break; case IPPROTO_UDP: verdict = net_conn_input(IPPROTO_UDP, pkt); break; case IPPROTO_TCP: verdict = net_conn_input(IPPROTO_TCP, pkt); break; } if (verdict != NET_DROP) { return verdict; } drop: net_stats_update_ipv4_drop(); return NET_DROP; }