From b59472cf63b49b3da2ad49fd05716af5cb1eebc8 Mon Sep 17 00:00:00 2001 From: David van Moolenbroek Date: Thu, 5 Jan 2017 15:32:54 +0000 Subject: [PATCH] raw: core support for IP_HDRINCL socket option This patch adds a new RAW_FLAGS_HDRINCL flag to the raw core implementation. When this flag is set on a RAW PCB, the raw send routines expect the caller to supply an IP header for the given packet, and will use that IP header instead of prepending one to the packet themselves. This feature allows the IP_HDRINCL socket option to be implemented in higher layers with no further effort. Even thoguh that option is traditionally supported for IPv4 sockets only (e.g., see RFC 3542 Sec. 3), the RAW_FLAGS_HDRINCL flag supports both IPv4 and IPv6, as much of the lower-level infrastructure was already in place anyway. --- src/core/raw.c | 26 ++++++++++++++++++++------ src/include/lwip/ip.h | 9 +++++++++ src/include/lwip/raw.h | 2 ++ 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/core/raw.c b/src/core/raw.c index 1729fc7d..4828df6f 100644 --- a/src/core/raw.c +++ b/src/core/raw.c @@ -287,11 +287,9 @@ raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg) /** * @ingroup raw_raw - * Send the raw IP packet to the given address. Note that actually you cannot - * modify the IP headers (this is inconsistent with the receive callback where - * you actually get the IP headers), you can only specify the IP payload here. - * It requires some more changes in lwIP. (there will be a raw_send() function - * then.) + * Send the raw IP packet to the given address. An IP header will be prepended + * to the packet, unless the RAW_FLAGS_HDRINCL flag is set on the PCB. In that + * case, the packet must include an IP header, which will then be sent as is. * * @param pcb the raw pcb which to send * @param p the IP payload to send @@ -342,7 +340,9 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr) /** * @ingroup raw_raw * Send the raw IP packet to the given address, using a particular outgoing - * netif and source IP address. An IP header will be prepended to the packet. + * netif and source IP address. An IP header will be prepended to the packet, + * unless the RAW_FLAGS_HDRINCL flag is set on the PCB. In that case, the + * packet must include an IP header, which will then be sent as is. * * @param pcb RAW PCB used to send the data * @param p chain of pbufs to be sent @@ -372,6 +372,20 @@ raw_sendto_if_src(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, IP6_HLEN); #endif + /* Handle the HDRINCL option as an exception: none of the code below applies + * to this case, and sending the packet needs to be done differently too. */ + if (pcb->flags & RAW_FLAGS_HDRINCL) { + /* A full header *must* be present in the first pbuf of the chain, as the + * output routines may access its fields directly. */ + if (p->len < header_size) { + return ERR_VAL; + } + NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint); + err = ip_output_if_hdrincl(p, src_ip, dst_ip, netif); + NETIF_SET_HWADDRHINT(netif, NULL); + return err; + } + /* not enough space to add an IP header to first pbuf in given p chain? */ if (pbuf_header(p, header_size)) { /* allocate header in new pbuf */ diff --git a/src/include/lwip/ip.h b/src/include/lwip/ip.h index 0673be9b..f104917c 100644 --- a/src/include/lwip/ip.h +++ b/src/include/lwip/ip.h @@ -243,6 +243,11 @@ extern struct ip_globals ip_data; (IP_IS_V6(dest) ? \ ip6_output_if_src(p, ip_2_ip6(src), ip_2_ip6(dest), ttl, tos, proto, netif) : \ ip4_output_if_src(p, ip_2_ip4(src), ip_2_ip4(dest), ttl, tos, proto, netif)) +/** Output IP packet that already includes an IP header. */ +#define ip_output_if_hdrincl(p, src, dest, netif) \ + (IP_IS_V6(dest) ? \ + ip6_output_if(p, ip_2_ip6(src), LWIP_IP_HDRINCL, 0, 0, 0, netif) : \ + ip4_output_if(p, ip_2_ip4(src), LWIP_IP_HDRINCL, 0, 0, 0, netif)) /** Output IP packet with addr_hint */ #define ip_output_hinted(p, src, dest, ttl, tos, proto, addr_hint) \ (IP_IS_V6(dest) ? \ @@ -277,6 +282,8 @@ err_t ip_input(struct pbuf *p, struct netif *inp); ip4_output_if_src(p, src, dest, ttl, tos, proto, netif) #define ip_output_hinted(p, src, dest, ttl, tos, proto, addr_hint) \ ip4_output_hinted(p, src, dest, ttl, tos, proto, addr_hint) +#define ip_output_if_hdrincl(p, src, dest, netif) \ + ip4_output_if(p, src, LWIP_IP_HDRINCL, 0, 0, 0, netif) #define ip_route(src, dest) \ ip4_route_src(dest, src) #define ip_netif_get_local_ip(netif, dest) \ @@ -295,6 +302,8 @@ err_t ip_input(struct pbuf *p, struct netif *inp); ip6_output_if_src(p, src, dest, ttl, tos, proto, netif) #define ip_output_hinted(p, src, dest, ttl, tos, proto, addr_hint) \ ip6_output_hinted(p, src, dest, ttl, tos, proto, addr_hint) +#define ip_output_if_hdrincl(p, src, dest, netif) \ + ip6_output_if(p, src, LWIP_IP_HDRINCL, 0, 0, 0, netif) #define ip_route(src, dest) \ ip6_route(src, dest) #define ip_netif_get_local_ip(netif, dest) \ diff --git a/src/include/lwip/raw.h b/src/include/lwip/raw.h index c5a3b21b..644ba1a8 100644 --- a/src/include/lwip/raw.h +++ b/src/include/lwip/raw.h @@ -53,6 +53,7 @@ extern "C" { #endif #define RAW_FLAGS_CONNECTED 0x01U +#define RAW_FLAGS_HDRINCL 0x02U struct raw_pcb; @@ -106,6 +107,7 @@ err_t raw_send (struct raw_pcb *pcb, struct pbuf *p); void raw_recv (struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg); #define raw_flags(pcb) ((pcb)->flags) +#define raw_setflags(pcb,f) ((pcb)->flags = (f)) /* The following functions are the lower layer interface to RAW. */ u8_t raw_input (struct pbuf *p, struct netif *inp);