Skip to content

Commit 9ab63b8

Browse files
committed
net: sockets: Add SOCK_RAW support for AF_INET/AF_INET6 sockets
Introduce changes in the networking stack which allow to create raw IP sockets, so that applications can send and receive raw IP datagrams. Signed-off-by: Robert Lubos <[email protected]>
1 parent 0789962 commit 9ab63b8

File tree

8 files changed

+312
-40
lines changed

8 files changed

+312
-40
lines changed

subsys/net/ip/connection.c

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,37 @@ static enum net_verdict conn_raw_socket(struct net_pkt *pkt,
635635
return NET_OK;
636636
}
637637

638+
#if defined(CONFIG_NET_SOCKETS_INET_RAW)
639+
static void conn_raw_ip_socket(struct net_pkt *pkt, struct net_conn *conn)
640+
{
641+
struct net_pkt *raw_pkt;
642+
struct net_pkt_cursor cur;
643+
644+
net_pkt_cursor_backup(pkt, &cur);
645+
net_pkt_cursor_init(pkt);
646+
647+
NET_DBG("[%p] raw IP match found cb %p ud %p", conn, conn->cb,
648+
conn->user_data);
649+
650+
raw_pkt = net_pkt_clone(pkt, CLONE_TIMEOUT);
651+
if (!raw_pkt) {
652+
return;
653+
}
654+
655+
if (conn->cb(conn, raw_pkt, NULL, NULL, conn->user_data) == NET_DROP) {
656+
net_pkt_unref(raw_pkt);
657+
}
658+
659+
net_pkt_cursor_restore(pkt, &cur);
660+
}
661+
#else
662+
static void conn_raw_ip_socket(struct net_pkt *pkt, struct net_conn *conn)
663+
{
664+
ARG_UNUSED(pkt);
665+
ARG_UNUSED(conn);
666+
}
667+
#endif /* defined(CONFIG_NET_SOCKETS_INET_RAW) */
668+
638669
enum net_verdict net_conn_input(struct net_pkt *pkt,
639670
union net_ip_header *ip_hdr,
640671
uint8_t proto,
@@ -643,14 +674,17 @@ enum net_verdict net_conn_input(struct net_pkt *pkt,
643674
struct net_if *pkt_iface = net_pkt_iface(pkt);
644675
uint8_t pkt_family = net_pkt_family(pkt);
645676
uint16_t src_port = 0U, dst_port = 0U;
677+
bool raw_ip_pkt = false;
646678

647679
if (!net_pkt_filter_local_in_recv_ok(pkt)) {
648680
/* drop the packet */
649681
return NET_DROP;
650682
}
651683

652684
if (IS_ENABLED(CONFIG_NET_IP) && (pkt_family == AF_INET || pkt_family == AF_INET6)) {
653-
if (IS_ENABLED(CONFIG_NET_UDP) && proto == IPPROTO_UDP) {
685+
if (IS_ENABLED(CONFIG_NET_SOCKETS_INET_RAW) && proto_hdr == NULL) {
686+
raw_ip_pkt = true;
687+
} else if (IS_ENABLED(CONFIG_NET_UDP) && proto == IPPROTO_UDP) {
654688
src_port = proto_hdr->udp->src_port;
655689
dst_port = proto_hdr->udp->dst_port;
656690
} else if (IS_ENABLED(CONFIG_NET_TCP) && proto == IPPROTO_TCP) {
@@ -660,7 +694,8 @@ enum net_verdict net_conn_input(struct net_pkt *pkt,
660694
src_port = proto_hdr->tcp->src_port;
661695
dst_port = proto_hdr->tcp->dst_port;
662696
}
663-
if (!conn_are_endpoints_valid(pkt, pkt_family, ip_hdr, src_port, dst_port)) {
697+
if (!raw_ip_pkt && !conn_are_endpoints_valid(pkt, pkt_family, ip_hdr,
698+
src_port, dst_port)) {
664699
NET_DBG("Dropping invalid src/dst end-points packet");
665700
return NET_DROP;
666701
}
@@ -693,7 +728,7 @@ enum net_verdict net_conn_input(struct net_pkt *pkt,
693728
net_conn_cb_t cb = NULL;
694729
void *user_data = NULL;
695730

696-
if (IS_ENABLED(CONFIG_NET_IP)) {
731+
if (IS_ENABLED(CONFIG_NET_IP) && !raw_ip_pkt) {
697732
/* If we receive a packet with multicast destination address, we might
698733
* need to deliver the packet to multiple recipients.
699734
*/
@@ -736,7 +771,7 @@ enum net_verdict net_conn_input(struct net_pkt *pkt,
736771

737772
if (IS_ENABLED(CONFIG_NET_IPV4_MAPPING_TO_IPV6)) {
738773
if (!(conn->family == AF_INET6 && pkt_family == AF_INET &&
739-
!conn->v6only)) {
774+
!conn->v6only && conn->type != SOCK_RAW)) {
740775
continue;
741776
}
742777
} else {
@@ -746,6 +781,11 @@ enum net_verdict net_conn_input(struct net_pkt *pkt,
746781
/* We might have a match for v4-to-v6 mapping, check more */
747782
}
748783

784+
if (IS_ENABLED(CONFIG_NET_SOCKETS_INET_RAW) && raw_ip_pkt &&
785+
conn->type != SOCK_RAW) {
786+
continue;
787+
}
788+
749789
/* Is the candidate connection matching the packet's protocol within the family? */
750790
if (conn->proto != proto) {
751791
/* For packet socket data, the proto is set to ETH_P_ALL
@@ -757,6 +797,10 @@ enum net_verdict net_conn_input(struct net_pkt *pkt,
757797
if (proto != ETH_P_ALL && proto != IPPROTO_RAW) {
758798
continue; /* wrong protocol */
759799
}
800+
} else if (IS_ENABLED(CONFIG_NET_SOCKETS_INET_RAW) && raw_ip_pkt) {
801+
if (conn->proto != 0) {
802+
continue;
803+
}
760804
} else {
761805
continue; /* wrong protocol */
762806
}
@@ -793,6 +837,15 @@ enum net_verdict net_conn_input(struct net_pkt *pkt,
793837

794838
continue; /* packet was consumed */
795839
}
840+
} else if (IS_ENABLED(CONFIG_NET_SOCKETS_INET_RAW) && raw_ip_pkt) {
841+
if ((conn->flags & NET_CONN_LOCAL_ADDR_SET) &&
842+
!conn_addr_cmp(pkt, ip_hdr, &conn->local_addr, false)) {
843+
continue; /* wrong local address */
844+
}
845+
846+
conn_raw_ip_socket(pkt, conn);
847+
848+
continue;
796849
} else if ((IS_ENABLED(CONFIG_NET_UDP) || IS_ENABLED(CONFIG_NET_TCP)) &&
797850
(conn_family == AF_INET || conn_family == AF_INET6 ||
798851
conn_family == AF_UNSPEC)) {
@@ -904,6 +957,11 @@ enum net_verdict net_conn_input(struct net_pkt *pkt,
904957
}
905958
}
906959

960+
if (IS_ENABLED(CONFIG_NET_SOCKETS_INET_RAW) && raw_ip_pkt) {
961+
/* Raw IP packets are passed further in the stack regardless. */
962+
return NET_CONTINUE;
963+
}
964+
907965
if (IS_ENABLED(CONFIG_NET_IP) && is_mcast_pkt && mcast_pkt_delivered) {
908966
/* As one or more multicast packets
909967
* have already been delivered in the loop above,

subsys/net/ip/ipv4.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,12 @@ enum net_verdict net_ipv4_input(struct net_pkt *pkt, bool is_loopback)
383383
net_sprint_ipv4_addr(&hdr->src),
384384
net_sprint_ipv4_addr(&hdr->dst));
385385

386+
ip.ipv4 = hdr;
387+
388+
if (IS_ENABLED(CONFIG_NET_SOCKETS_INET_RAW)) {
389+
(void)net_conn_input(pkt, &ip, hdr->proto, NULL);
390+
}
391+
386392
switch (hdr->proto) {
387393
case IPPROTO_ICMP:
388394
verdict = net_icmpv4_input(pkt, hdr);
@@ -440,8 +446,6 @@ enum net_verdict net_ipv4_input(struct net_pkt *pkt, bool is_loopback)
440446
goto drop;
441447
}
442448

443-
ip.ipv4 = hdr;
444-
445449
verdict = net_conn_input(pkt, &ip, hdr->proto, &proto_hdr);
446450
if (verdict != NET_DROP) {
447451
return verdict;

subsys/net/ip/ipv6.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -762,6 +762,12 @@ enum net_verdict net_ipv6_input(struct net_pkt *pkt, bool is_loopback)
762762

763763
net_pkt_set_ipv6_ext_len(pkt, ext_len);
764764

765+
ip.ipv6 = hdr;
766+
767+
if (IS_ENABLED(CONFIG_NET_SOCKETS_INET_RAW)) {
768+
(void)net_conn_input(pkt, &ip, current_hdr, NULL);
769+
}
770+
765771
switch (current_hdr) {
766772
case IPPROTO_ICMPV6:
767773
verdict = net_icmpv6_input(pkt, hdr);
@@ -816,8 +822,6 @@ enum net_verdict net_ipv6_input(struct net_pkt *pkt, bool is_loopback)
816822
return verdict;
817823
}
818824

819-
ip.ipv6 = hdr;
820-
821825
verdict = net_conn_input(pkt, &ip, current_hdr, &proto_hdr);
822826

823827
NET_DBG("%s verdict %s", "Connection", net_verdict2str(verdict));

0 commit comments

Comments
 (0)