Esempio n. 1
0
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;
}
Esempio n. 2
0
static int loopback_send(struct net_if *iface, struct net_pkt *pkt)
{
	struct net_pkt *cloned;
	int res;

	if (!pkt->frags) {
		SYS_LOG_ERR("No data to send");
		return -ENODATA;
	}

	/* We need to swap the IP addresses because otherwise
	 * the packet will be dropped.
	 */

	if (net_pkt_family(pkt) == AF_INET6) {
		struct in6_addr addr;

		net_ipaddr_copy(&addr, &NET_IPV6_HDR(pkt)->src);
		net_ipaddr_copy(&NET_IPV6_HDR(pkt)->src,
				&NET_IPV6_HDR(pkt)->dst);
		net_ipaddr_copy(&NET_IPV6_HDR(pkt)->dst, &addr);
	} else {
		struct in_addr addr;

		net_ipaddr_copy(&addr, &NET_IPV4_HDR(pkt)->src);
		net_ipaddr_copy(&NET_IPV4_HDR(pkt)->src,
				&NET_IPV4_HDR(pkt)->dst);
		net_ipaddr_copy(&NET_IPV4_HDR(pkt)->dst, &addr);
	}

	/* We should simulate normal driver meaning that if the packet is
	 * properly sent (which is always in this driver), then the packet
	 * must be dropped. This is very much needed for TCP packets where
	 * the packet is reference counted in various stages of sending.
	 */
	cloned = net_pkt_clone(pkt, K_MSEC(100));
	if (!cloned) {
		res = -ENOMEM;
		goto out;
	}

	res = net_recv_data(iface, cloned);
	if (res < 0) {
		SYS_LOG_ERR("Data receive failed.");
		goto out;
	}

	net_pkt_unref(pkt);

out:
	/* Let the receiving thread run now */
	k_yield();

	return res;
}
Esempio n. 3
0
static void setup_ipv4_udp(struct net_pkt *pkt,
			   struct in_addr *remote_addr,
			   struct in_addr *local_addr,
			   u16_t remote_port,
			   u16_t local_port)
{
	NET_IPV4_HDR(pkt)->vhl = 0x45;
	NET_IPV4_HDR(pkt)->tos = 0;
	NET_IPV4_HDR(pkt)->len[0] = 0;
	NET_IPV4_HDR(pkt)->len[1] = NET_UDPH_LEN +
		sizeof(struct net_ipv4_hdr) + strlen(payload);

	NET_IPV4_HDR(pkt)->proto = IPPROTO_UDP;

	net_ipaddr_copy(&NET_IPV4_HDR(pkt)->src, remote_addr);
	net_ipaddr_copy(&NET_IPV4_HDR(pkt)->dst, local_addr);

	net_pkt_set_ip_hdr_len(pkt, sizeof(struct net_ipv4_hdr));
	net_pkt_set_ipv6_ext_len(pkt, 0);

	net_buf_add(pkt->frags, net_pkt_ip_hdr_len(pkt) +
				sizeof(struct net_udp_hdr));

	NET_UDP_HDR(pkt)->src_port = htons(remote_port);
	NET_UDP_HDR(pkt)->dst_port = htons(local_port);

	net_buf_add_mem(pkt->frags, payload, strlen(payload));
}
Esempio n. 4
0
u16_t net_calc_chksum(struct net_pkt *pkt, u8_t proto)
{
	u16_t upper_layer_len;
	u16_t sum;

	switch (net_pkt_family(pkt)) {
#if defined(CONFIG_NET_IPV4)
	case AF_INET:
		upper_layer_len = (NET_IPV4_HDR(pkt)->len[0] << 8) +
			NET_IPV4_HDR(pkt)->len[1] -
			net_pkt_ipv6_ext_len(pkt) -
			net_pkt_ip_hdr_len(pkt);

		if (proto == IPPROTO_ICMP) {
			return htons(calc_chksum(0, net_pkt_ip_data(pkt) +
						 net_pkt_ip_hdr_len(pkt),
						 upper_layer_len));
		} else {
			sum = calc_chksum(upper_layer_len + proto,
					  (u8_t *)&NET_IPV4_HDR(pkt)->src,
					  2 * sizeof(struct in_addr));
		}
		break;
#endif
#if defined(CONFIG_NET_IPV6)
	case AF_INET6:
		upper_layer_len = (NET_IPV6_HDR(pkt)->len[0] << 8) +
			NET_IPV6_HDR(pkt)->len[1] - net_pkt_ipv6_ext_len(pkt);
		sum = calc_chksum(upper_layer_len + proto,
				  (u8_t *)&NET_IPV6_HDR(pkt)->src,
				  2 * sizeof(struct in6_addr));
		break;
#endif
	default:
		NET_DBG("Unknown protocol family %d", net_pkt_family(pkt));
		return 0;
	}

	sum = calc_chksum_pkt(sum, pkt, upper_layer_len);

	sum = (sum == 0) ? 0xffff : htons(sum);

	return sum;
}
Esempio n. 5
0
u16_t net_calc_chksum_ipv4(struct net_pkt *pkt)
{
	u16_t sum;

	sum = calc_chksum(0, (u8_t *)NET_IPV4_HDR(pkt), NET_IPV4H_LEN);

	sum = (sum == 0) ? 0xffff : htons(sum);

	return sum;
}
Esempio n. 6
0
static inline void set_dst_addr(sa_family_t family,
				struct net_pkt *pkt,
				struct sockaddr *dst_addr)
{
#if defined(CONFIG_NET_IPV6)
	if (family == AF_INET6) {
		net_ipaddr_copy(&net_sin6(dst_addr)->sin6_addr,
				&NET_IPV6_HDR(pkt)->src);
		net_sin6(dst_addr)->sin6_family = AF_INET6;
		net_sin6(dst_addr)->sin6_port = NET_UDP_HDR(pkt)->src_port;
	}
#endif /* CONFIG_NET_IPV6) */

#if defined(CONFIG_NET_IPV4)
	if (family == AF_INET) {
		net_ipaddr_copy(&net_sin(dst_addr)->sin_addr,
				&NET_IPV4_HDR(pkt)->src);
		net_sin(dst_addr)->sin_family = AF_INET;
		net_sin(dst_addr)->sin_port = NET_UDP_HDR(pkt)->src_port;
	}
#endif /* CONFIG_NET_IPV6) */
}
Esempio n. 7
0
static bool run_tests(void)
{
	struct net_pkt *pkt, *pkt2;
	struct net_buf *frag;
	struct net_if *iface;
	struct net_if_addr *ifaddr;
	struct net_arp_hdr *arp_hdr;
	struct net_ipv4_hdr *ipv4;
	struct net_eth_hdr *eth_hdr;
	int len;

	struct in_addr dst = { { { 192, 168, 0, 2 } } };
	struct in_addr dst_far = { { { 10, 11, 12, 13 } } };
	struct in_addr dst_far2 = { { { 172, 16, 14, 186 } } };
	struct in_addr src = { { { 192, 168, 0, 1 } } };
	struct in_addr netmask = { { { 255, 255, 255, 0 } } };
	struct in_addr gw = { { { 192, 168, 0, 42 } } };

	net_arp_init();

	iface = net_if_get_default();

	net_if_ipv4_set_gw(iface, &gw);
	net_if_ipv4_set_netmask(iface, &netmask);

	/* Unicast test */
	ifaddr = net_if_ipv4_addr_add(iface,
				      &src,
				      NET_ADDR_MANUAL,
				      0);
	ifaddr->addr_state = NET_ADDR_PREFERRED;

	/* Application data for testing */
	pkt = net_pkt_get_reserve_tx(sizeof(struct net_eth_hdr), K_FOREVER);
	if (!pkt) {
		printk("Out of mem TX\n");
		return false;
	}

	frag = net_pkt_get_frag(pkt, K_FOREVER);
	if (!frag) {
		printk("Out of mem DATA\n");
		return false;
	}

	net_pkt_frag_add(pkt, frag);

	net_pkt_set_iface(pkt, iface);

	setup_eth_header(iface, pkt, &hwaddr, NET_ETH_PTYPE_IP);

	len = strlen(app_data);

	if (net_pkt_ll_reserve(pkt) != sizeof(struct net_eth_hdr)) {
		printk("LL reserve invalid, should be %zd was %d\n",
		       sizeof(struct net_eth_hdr),
		       net_pkt_ll_reserve(pkt));
		return false;
	}

	ipv4 = (struct net_ipv4_hdr *)net_buf_add(frag,
						  sizeof(struct net_ipv4_hdr));
	net_ipaddr_copy(&ipv4->src, &src);
	net_ipaddr_copy(&ipv4->dst, &dst);

	memcpy(net_buf_add(frag, len), app_data, len);

	pkt2 = net_arp_prepare(pkt);

	/* pkt2 is the ARP packet and pkt is the IPv4 packet and it was
	 * stored in ARP table.
	 */
	if (pkt2 == pkt) {
		/* The packets cannot be the same as the ARP cache has
		 * still room for the pkt.
		 */
		printk("ARP cache should still have free space\n");
		return false;
	}

	if (!pkt2) {
		printk("ARP pkt is empty\n");
		return false;
	}

	/* The ARP cache should now have a link to pending net_pkt
	 * that is to be sent after we have got an ARP reply.
	 */
	if (!pkt->frags) {
		printk("Pending pkt fragment is NULL\n");
		return false;
	}
	pending_pkt = pkt;

	/* pkt2 should contain the arp header, verify it */
	if (memcmp(net_pkt_ll(pkt2), net_eth_broadcast_addr(),
		   sizeof(struct net_eth_addr))) {
		printk("ARP ETH dest address invalid\n");
		net_hexdump("ETH dest wrong  ", net_pkt_ll(pkt2),
			    sizeof(struct net_eth_addr));
		net_hexdump("ETH dest correct",
			    (u8_t *)net_eth_broadcast_addr(),
			    sizeof(struct net_eth_addr));
		return false;
	}

	if (memcmp(net_pkt_ll(pkt2) + sizeof(struct net_eth_addr),
		   iface->link_addr.addr,
		   sizeof(struct net_eth_addr))) {
		printk("ARP ETH source address invalid\n");
		net_hexdump("ETH src correct",
			    iface->link_addr.addr,
			    sizeof(struct net_eth_addr));
		net_hexdump("ETH src wrong  ",
			    net_pkt_ll(pkt2) +	sizeof(struct net_eth_addr),
			    sizeof(struct net_eth_addr));
		return false;
	}

	arp_hdr = NET_ARP_HDR(pkt2);
	eth_hdr = NET_ETH_HDR(pkt2);

	if (eth_hdr->type != htons(NET_ETH_PTYPE_ARP)) {
		printk("ETH type 0x%x, should be 0x%x\n",
		       eth_hdr->type, htons(NET_ETH_PTYPE_ARP));
		return false;
	}

	if (arp_hdr->hwtype != htons(NET_ARP_HTYPE_ETH)) {
		printk("ARP hwtype 0x%x, should be 0x%x\n",
		       arp_hdr->hwtype, htons(NET_ARP_HTYPE_ETH));
		return false;
	}

	if (arp_hdr->protocol != htons(NET_ETH_PTYPE_IP)) {
		printk("ARP protocol 0x%x, should be 0x%x\n",
		       arp_hdr->protocol, htons(NET_ETH_PTYPE_IP));
		return false;
	}

	if (arp_hdr->hwlen != sizeof(struct net_eth_addr)) {
		printk("ARP hwlen 0x%x, should be 0x%zx\n",
		       arp_hdr->hwlen, sizeof(struct net_eth_addr));
		return false;
	}

	if (arp_hdr->protolen != sizeof(struct in_addr)) {
		printk("ARP IP addr len 0x%x, should be 0x%zx\n",
		       arp_hdr->protolen, sizeof(struct in_addr));
		return false;
	}

	if (arp_hdr->opcode != htons(NET_ARP_REQUEST)) {
		printk("ARP opcode 0x%x, should be 0x%x\n",
		       arp_hdr->opcode, htons(NET_ARP_REQUEST));
		return false;
	}

	if (!net_ipv4_addr_cmp(&arp_hdr->dst_ipaddr,
			       &NET_IPV4_HDR(pkt)->dst)) {
		char out[sizeof("xxx.xxx.xxx.xxx")];
		snprintk(out, sizeof(out), "%s",
			 net_sprint_ipv4_addr(&arp_hdr->dst_ipaddr));
		printk("ARP IP dest invalid %s, should be %s", out,
		       net_sprint_ipv4_addr(&NET_IPV4_HDR(pkt)->dst));
		return false;
	}

	if (!net_ipv4_addr_cmp(&arp_hdr->src_ipaddr,
			       &NET_IPV4_HDR(pkt)->src)) {
		char out[sizeof("xxx.xxx.xxx.xxx")];
		snprintk(out, sizeof(out), "%s",
			 net_sprint_ipv4_addr(&arp_hdr->src_ipaddr));
		printk("ARP IP src invalid %s, should be %s", out,
		       net_sprint_ipv4_addr(&NET_IPV4_HDR(pkt)->src));
		return false;
	}

	/* We could have send the new ARP request but for this test we
	 * just free it.
	 */
	net_pkt_unref(pkt2);

	if (pkt->ref != 2) {
		printk("ARP cache should own the original packet\n");
		return false;
	}

	/* Then a case where target is not in the same subnet */
	net_ipaddr_copy(&ipv4->dst, &dst_far);

	pkt2 = net_arp_prepare(pkt);

	if (pkt2 == pkt) {
		printk("ARP cache should not find anything\n");
		return false;
	}

	if (!pkt2) {
		printk("ARP pkt2 is empty\n");
		return false;
	}

	arp_hdr = NET_ARP_HDR(pkt2);

	if (!net_ipv4_addr_cmp(&arp_hdr->dst_ipaddr, &iface->ipv4.gw)) {
		char out[sizeof("xxx.xxx.xxx.xxx")];
		snprintk(out, sizeof(out), "%s",
			 net_sprint_ipv4_addr(&arp_hdr->dst_ipaddr));
		printk("ARP IP dst invalid %s, should be %s\n", out,
			 net_sprint_ipv4_addr(&iface->ipv4.gw));
		return false;
	}

	net_pkt_unref(pkt2);

	/* Try to find the same destination again, this should fail as there
	 * is a pending request in ARP cache.
	 */
	net_ipaddr_copy(&ipv4->dst, &dst_far);

	/* Make sure prepare will not free the pkt because it will be
	 * needed in the later test case.
	 */
	net_pkt_ref(pkt);

	pkt2 = net_arp_prepare(pkt);
	if (!pkt2) {
		printk("ARP cache is not sending the request again\n");
		return false;
	}

	net_pkt_unref(pkt2);

	/* Try to find the different destination, this should fail too
	 * as the cache table should be full.
	 */
	net_ipaddr_copy(&ipv4->dst, &dst_far2);

	/* Make sure prepare will not free the pkt because it will be
	 * needed in the next test case.
	 */
	net_pkt_ref(pkt);

	pkt2 = net_arp_prepare(pkt);
	if (!pkt2) {
		printk("ARP cache did not send a req\n");
		return false;
	}

	/* Restore the original address so that following test case can
	 * work properly.
	 */
	net_ipaddr_copy(&ipv4->dst, &dst);

	/* The arp request packet is now verified, create an arp reply.
	 * The previous value of pkt is stored in arp table and is not lost.
	 */
	pkt = net_pkt_get_reserve_rx(sizeof(struct net_eth_hdr), K_FOREVER);
	if (!pkt) {
		printk("Out of mem RX reply\n");
		return false;
	}
	printk("%d pkt %p\n", __LINE__, pkt);

	frag = net_pkt_get_frag(pkt, K_FOREVER);
	if (!frag) {
		printk("Out of mem DATA reply\n");
		return false;
	}
	printk("%d frag %p\n", __LINE__, frag);

	net_pkt_frag_add(pkt, frag);

	net_pkt_set_iface(pkt, iface);

	arp_hdr = NET_ARP_HDR(pkt);
	net_buf_add(frag, sizeof(struct net_arp_hdr));

	net_ipaddr_copy(&arp_hdr->dst_ipaddr, &dst);
	net_ipaddr_copy(&arp_hdr->src_ipaddr, &src);

	pkt2 = prepare_arp_reply(iface, pkt, &hwaddr);
	if (!pkt2) {
		printk("ARP reply generation failed.");
		return false;
	}

	/* The pending packet should now be sent */
	switch (net_arp_input(pkt2)) {
	case NET_OK:
	case NET_CONTINUE:
		break;
	case NET_DROP:
		break;
	}

	/* Yielding so that network interface TX thread can proceed. */
	k_yield();

	if (send_status < 0) {
		printk("ARP reply was not sent\n");
		return false;
	}

	if (pkt->ref != 1) {
		printk("ARP cache should no longer own the original packet\n");
		return false;
	}

	net_pkt_unref(pkt);

	/* Then feed in ARP request */
	pkt = net_pkt_get_reserve_rx(sizeof(struct net_eth_hdr), K_FOREVER);
	if (!pkt) {
		printk("Out of mem RX request\n");
		return false;
	}

	frag = net_pkt_get_frag(pkt, K_FOREVER);
	if (!frag) {
		printk("Out of mem DATA request\n");
		return false;
	}

	net_pkt_frag_add(pkt, frag);

	net_pkt_set_iface(pkt, iface);
	send_status = -EINVAL;

	arp_hdr = NET_ARP_HDR(pkt);
	net_buf_add(frag, sizeof(struct net_arp_hdr));

	net_ipaddr_copy(&arp_hdr->dst_ipaddr, &src);
	net_ipaddr_copy(&arp_hdr->src_ipaddr, &dst);
	setup_eth_header(iface, pkt, &hwaddr, NET_ETH_PTYPE_ARP);

	pkt2 = prepare_arp_request(iface, pkt, &hwaddr);
	if (!pkt2) {
		printk("ARP request generation failed.");
		return false;
	}

	req_test = true;

	switch (net_arp_input(pkt2)) {
	case NET_OK:
	case NET_CONTINUE:
		break;
	case NET_DROP:
		break;
	}

	/* Yielding so that network interface TX thread can proceed. */
	k_yield();

	if (send_status < 0) {
		printk("ARP req was not sent\n");
		return false;
	}

	net_pkt_unref(pkt);

	printk("Network ARP checks passed\n");

	return true;
}
Esempio n. 8
0
/* Check if the IPv{4|6} addresses are proper. As this can be expensive,
 * make this optional.
 */
static inline int check_ip_addr(struct net_pkt *pkt)
{
#if defined(CONFIG_NET_IPV6)
	if (net_pkt_family(pkt) == AF_INET6) {
		if (net_ipv6_addr_cmp(&NET_IPV6_HDR(pkt)->dst,
				      net_ipv6_unspecified_address())) {
			NET_DBG("IPv6 dst address missing");
			return -EADDRNOTAVAIL;
		}

		/* If the destination address is our own, then route it
		 * back to us.
		 */
		if (net_is_ipv6_addr_loopback(&NET_IPV6_HDR(pkt)->dst) ||
		    net_is_my_ipv6_addr(&NET_IPV6_HDR(pkt)->dst)) {
			struct in6_addr addr;

			/* Swap the addresses so that in receiving side
			 * the packet is accepted.
			 */
			net_ipaddr_copy(&addr, &NET_IPV6_HDR(pkt)->src);
			net_ipaddr_copy(&NET_IPV6_HDR(pkt)->src,
					&NET_IPV6_HDR(pkt)->dst);
			net_ipaddr_copy(&NET_IPV6_HDR(pkt)->dst, &addr);

			return 1;
		}

		/* The source check must be done after the destination check
		 * as having src ::1 is perfectly ok if dst is ::1 too.
		 */
		if (net_is_ipv6_addr_loopback(&NET_IPV6_HDR(pkt)->src)) {
			NET_DBG("IPv6 loopback src address");
			return -EADDRNOTAVAIL;
		}
	} else
#endif /* CONFIG_NET_IPV6 */

#if defined(CONFIG_NET_IPV4)
	if (net_pkt_family(pkt) == AF_INET) {
		if (net_ipv4_addr_cmp(&NET_IPV4_HDR(pkt)->dst,
				      net_ipv4_unspecified_address())) {
			return -EADDRNOTAVAIL;
		}

		/* If the destination address is our own, then route it
		 * back to us.
		 */
		if (net_is_ipv4_addr_loopback(&NET_IPV4_HDR(pkt)->dst) ||
		    net_is_my_ipv4_addr(&NET_IPV4_HDR(pkt)->dst)) {
			struct in_addr addr;

			/* Swap the addresses so that in receiving side
			 * the packet is accepted.
			 */
			net_ipaddr_copy(&addr, &NET_IPV4_HDR(pkt)->src);
			net_ipaddr_copy(&NET_IPV4_HDR(pkt)->src,
					&NET_IPV4_HDR(pkt)->dst);
			net_ipaddr_copy(&NET_IPV4_HDR(pkt)->dst, &addr);

			return 1;
		}

		/* The source check must be done after the destination check
		 * as having src 127.0.0.0/8 is perfectly ok if dst is in
		 * localhost subnet too.
		 */
		if (net_is_ipv4_addr_loopback(&NET_IPV4_HDR(pkt)->src)) {
			NET_DBG("IPv4 loopback src address");
			return -EADDRNOTAVAIL;
		}
	} else
#endif /* CONFIG_NET_IPV4 */

	{
		;
	}

	return 0;
}
Esempio n. 9
0
struct net_pkt *net_ipv4_create_raw(struct net_pkt *pkt,
				    const struct in_addr *src,
				    const struct in_addr *dst,
				    struct net_if *iface,
				    u8_t next_header)
{
	struct net_buf *header;

	header = net_pkt_get_frag(pkt, K_FOREVER);

	net_pkt_frag_insert(pkt, header);

	NET_IPV4_HDR(pkt)->vhl = 0x45;
	NET_IPV4_HDR(pkt)->tos = 0x00;
	NET_IPV4_HDR(pkt)->proto = 0;

	NET_IPV4_HDR(pkt)->ttl = net_if_ipv4_get_ttl(iface);
	NET_IPV4_HDR(pkt)->offset[0] = NET_IPV4_HDR(pkt)->offset[1] = 0;
	NET_IPV4_HDR(pkt)->id[0] = NET_IPV4_HDR(pkt)->id[1] = 0;

	net_ipaddr_copy(&NET_IPV4_HDR(pkt)->dst, dst);
	net_ipaddr_copy(&NET_IPV4_HDR(pkt)->src, src);

	NET_IPV4_HDR(pkt)->proto = next_header;

	net_pkt_set_ip_hdr_len(pkt, sizeof(struct net_ipv4_hdr));
	net_pkt_set_family(pkt, AF_INET);

	net_buf_add(header, sizeof(struct net_ipv4_hdr));

	return pkt;
}
Esempio n. 10
0
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;
}