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.
This commit is contained in:
David van Moolenbroek 2017-01-05 15:32:54 +00:00 committed by Dirk Ziegelmeier
parent 162cc4d343
commit b59472cf63
3 changed files with 31 additions and 6 deletions

View File

@ -287,11 +287,9 @@ raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg)
/** /**
* @ingroup raw_raw * @ingroup raw_raw
* Send the raw IP packet to the given address. Note that actually you cannot * Send the raw IP packet to the given address. An IP header will be prepended
* modify the IP headers (this is inconsistent with the receive callback where * to the packet, unless the RAW_FLAGS_HDRINCL flag is set on the PCB. In that
* you actually get the IP headers), you can only specify the IP payload here. * case, the packet must include an IP header, which will then be sent as is.
* It requires some more changes in lwIP. (there will be a raw_send() function
* then.)
* *
* @param pcb the raw pcb which to send * @param pcb the raw pcb which to send
* @param p the IP payload 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 * @ingroup raw_raw
* Send the raw IP packet to the given address, using a particular outgoing * 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 pcb RAW PCB used to send the data
* @param p chain of pbufs to be sent * @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); IP6_HLEN);
#endif #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? */ /* not enough space to add an IP header to first pbuf in given p chain? */
if (pbuf_header(p, header_size)) { if (pbuf_header(p, header_size)) {
/* allocate header in new pbuf */ /* allocate header in new pbuf */

View File

@ -243,6 +243,11 @@ extern struct ip_globals ip_data;
(IP_IS_V6(dest) ? \ (IP_IS_V6(dest) ? \
ip6_output_if_src(p, ip_2_ip6(src), ip_2_ip6(dest), ttl, tos, proto, netif) : \ 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)) 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 */ /** Output IP packet with addr_hint */
#define ip_output_hinted(p, src, dest, ttl, tos, proto, addr_hint) \ #define ip_output_hinted(p, src, dest, ttl, tos, proto, addr_hint) \
(IP_IS_V6(dest) ? \ (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) ip4_output_if_src(p, src, dest, ttl, tos, proto, netif)
#define ip_output_hinted(p, src, dest, ttl, tos, proto, addr_hint) \ #define ip_output_hinted(p, src, dest, ttl, tos, proto, addr_hint) \
ip4_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) \ #define ip_route(src, dest) \
ip4_route_src(dest, src) ip4_route_src(dest, src)
#define ip_netif_get_local_ip(netif, dest) \ #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) ip6_output_if_src(p, src, dest, ttl, tos, proto, netif)
#define ip_output_hinted(p, src, dest, ttl, tos, proto, addr_hint) \ #define ip_output_hinted(p, src, dest, ttl, tos, proto, addr_hint) \
ip6_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) \ #define ip_route(src, dest) \
ip6_route(src, dest) ip6_route(src, dest)
#define ip_netif_get_local_ip(netif, dest) \ #define ip_netif_get_local_ip(netif, dest) \

View File

@ -53,6 +53,7 @@ extern "C" {
#endif #endif
#define RAW_FLAGS_CONNECTED 0x01U #define RAW_FLAGS_CONNECTED 0x01U
#define RAW_FLAGS_HDRINCL 0x02U
struct raw_pcb; 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); void raw_recv (struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg);
#define raw_flags(pcb) ((pcb)->flags) #define raw_flags(pcb) ((pcb)->flags)
#define raw_setflags(pcb,f) ((pcb)->flags = (f))
/* The following functions are the lower layer interface to RAW. */ /* The following functions are the lower layer interface to RAW. */
u8_t raw_input (struct pbuf *p, struct netif *inp); u8_t raw_input (struct pbuf *p, struct netif *inp);