raw: add core support for multicast TX options

The patch simply copies the relevant bits from the UDP implementation.
Perhaps most notably, the patch does *not* copy the IPv4-only UDP
support for IP_MULTICAST_IF, because that option can also be
implemented using the interface index based approach. Largely thanks
to this omission, at least on 32-bit platforms, this patch does not
increase the RAW PCB size at all.
This commit is contained in:
David van Moolenbroek 2017-02-06 17:10:45 +00:00 committed by Dirk Ziegelmeier
parent ab8119360e
commit 6ce9a01c3e
4 changed files with 64 additions and 13 deletions

View File

@ -95,8 +95,8 @@ PACK_STRUCT_END
#if (!LWIP_UDP && LWIP_DHCP) #if (!LWIP_UDP && LWIP_DHCP)
#error "If you want to use DHCP, you have to define LWIP_UDP=1 in your lwipopts.h" #error "If you want to use DHCP, you have to define LWIP_UDP=1 in your lwipopts.h"
#endif #endif
#if (!LWIP_UDP && LWIP_MULTICAST_TX_OPTIONS) #if (!LWIP_UDP && !LWIP_RAW && LWIP_MULTICAST_TX_OPTIONS)
#error "If you want to use LWIP_MULTICAST_TX_OPTIONS, you have to define LWIP_UDP=1 in your lwipopts.h" #error "If you want to use LWIP_MULTICAST_TX_OPTIONS, you have to define LWIP_UDP=1 and/or LWIP_RAW=1 in your lwipopts.h"
#endif #endif
#if (!LWIP_UDP && LWIP_DNS) #if (!LWIP_UDP && LWIP_DNS)
#error "If you want to use DNS, you have to define LWIP_UDP=1 in your lwipopts.h" #error "If you want to use DNS, you have to define LWIP_UDP=1 in your lwipopts.h"

View File

@ -220,7 +220,7 @@ raw_bind(struct raw_pcb *pcb, const ip_addr_t *ipaddr)
* This is legacy support: scope-aware callers should always provide properly * This is legacy support: scope-aware callers should always provide properly
* zoned source addresses. */ * zoned source addresses. */
if (IP_IS_V6(&pcb->local_ip) && if (IP_IS_V6(&pcb->local_ip) &&
ip6_addr_lacks_zone(ip_2_ip6(&pcb->local_ip), IP6_UNICAST)) { ip6_addr_lacks_zone(ip_2_ip6(&pcb->local_ip), IP6_UNKNOWN)) {
ip6_addr_select_zone(ip_2_ip6(&pcb->local_ip), ip_2_ip6(&pcb->local_ip)); ip6_addr_select_zone(ip_2_ip6(&pcb->local_ip), ip_2_ip6(&pcb->local_ip));
} }
#endif /* LWIP_IPV6 && LWIP_IPV6_SCOPES */ #endif /* LWIP_IPV6 && LWIP_IPV6_SCOPES */
@ -325,12 +325,29 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr)
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n")); LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n"));
#if LWIP_MULTICAST_TX_OPTIONS
netif = NULL;
if (ip_addr_ismulticast(ipaddr) && (pcb->mcast_ifindex != NETIF_NO_INDEX)) {
/* For multicast-destined packets, use the user-provided interface index to
* determine the outgoing interface, if an interface index is set and a
* matching netif can be found. Otherwise, fall back to regular routing. */
for (netif = netif_list; netif != NULL; netif = netif->next) {
if (pcb->mcast_ifindex == netif_num_to_index(netif)) {
break; /* found! */
}
}
}
if (netif == NULL)
#endif /* LWIP_MULTICAST_TX_OPTIONS */
{
if (IP_IS_ANY_TYPE_VAL(pcb->local_ip)) { if (IP_IS_ANY_TYPE_VAL(pcb->local_ip)) {
/* Don't call ip_route() with IP_ANY_TYPE */ /* Don't call ip_route() with IP_ANY_TYPE */
netif = ip_route(IP46_ADDR_ANY(IP_GET_TYPE(ipaddr)), ipaddr); netif = ip_route(IP46_ADDR_ANY(IP_GET_TYPE(ipaddr)), ipaddr);
} else { } else {
netif = ip_route(&pcb->local_ip, ipaddr); netif = ip_route(&pcb->local_ip, ipaddr);
} }
}
if (netif == NULL) { if (netif == NULL) {
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to ")); LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to "));
@ -338,7 +355,7 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr)
return ERR_RTE; return ERR_RTE;
} }
if (ip_addr_isany(&pcb->local_ip)) { if (ip_addr_isany(&pcb->local_ip) || ip_addr_ismulticast(&pcb->local_ip)) {
/* use outgoing network interface IP address as source address */ /* use outgoing network interface IP address as source address */
src_ip = ip_netif_get_local_ip(netif, ipaddr); src_ip = ip_netif_get_local_ip(netif, ipaddr);
#if LWIP_IPV6 #if LWIP_IPV6
@ -374,6 +391,7 @@ raw_sendto_if_src(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip,
err_t err; err_t err;
struct pbuf *q; /* q will be sent down the stack */ struct pbuf *q; /* q will be sent down the stack */
s16_t header_size; s16_t header_size;
u8_t ttl;
if ((pcb == NULL) || (dst_ip == NULL) || (netif == NULL) || (src_ip == NULL) || if ((pcb == NULL) || (dst_ip == NULL) || (netif == NULL) || (src_ip == NULL) ||
!IP_ADDR_PCB_VERSION_MATCH(pcb, src_ip) || !IP_ADDR_PCB_VERSION_MATCH(pcb, dst_ip)) { !IP_ADDR_PCB_VERSION_MATCH(pcb, src_ip) || !IP_ADDR_PCB_VERSION_MATCH(pcb, dst_ip)) {
@ -397,6 +415,7 @@ raw_sendto_if_src(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip,
if (p->len < header_size) { if (p->len < header_size) {
return ERR_VAL; return ERR_VAL;
} }
/* @todo multicast loop support, if at all desired for this scenario.. */
NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint); NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint);
err = ip_output_if_hdrincl(p, src_ip, dst_ip, netif); err = ip_output_if_hdrincl(p, src_ip, dst_ip, netif);
NETIF_SET_HWADDRHINT(netif, NULL); NETIF_SET_HWADDRHINT(netif, NULL);
@ -446,6 +465,13 @@ raw_sendto_if_src(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip,
} }
#endif /* IP_SOF_BROADCAST */ #endif /* IP_SOF_BROADCAST */
/* Multicast Loop? */
#if LWIP_MULTICAST_TX_OPTIONS
if (((pcb->flags & RAW_FLAGS_MULTICAST_LOOP) != 0) && ip_addr_ismulticast(dst_ip)) {
q->flags |= PBUF_FLAG_MCASTLOOP;
}
#endif /* LWIP_MULTICAST_TX_OPTIONS */
#if LWIP_IPV6 #if LWIP_IPV6
/* If requested, based on the IPV6_CHECKSUM socket option per RFC3542, /* If requested, based on the IPV6_CHECKSUM socket option per RFC3542,
compute the checksum and update the checksum in the payload. */ compute the checksum and update the checksum in the payload. */
@ -456,8 +482,15 @@ raw_sendto_if_src(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip,
} }
#endif #endif
/* Determine TTL to use */
#if LWIP_MULTICAST_TX_OPTIONS
ttl = (ip_addr_ismulticast(dst_ip) ? raw_get_multicast_ttl(pcb) : pcb->ttl);
#else /* LWIP_MULTICAST_TX_OPTIONS */
ttl = pcb->ttl;
#endif /* LWIP_MULTICAST_TX_OPTIONS */
NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint); NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint);
err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, pcb->protocol, netif); err = ip_output_if(q, src_ip, dst_ip, ttl, pcb->tos, pcb->protocol, netif);
NETIF_SET_HWADDRHINT(netif, NULL); NETIF_SET_HWADDRHINT(netif, NULL);
/* did we chain a header earlier? */ /* did we chain a header earlier? */
@ -538,6 +571,9 @@ raw_new(u8_t proto)
memset(pcb, 0, sizeof(struct raw_pcb)); memset(pcb, 0, sizeof(struct raw_pcb));
pcb->protocol = proto; pcb->protocol = proto;
pcb->ttl = RAW_TTL; pcb->ttl = RAW_TTL;
#if LWIP_MULTICAST_TX_OPTIONS
raw_set_multicast_ttl(pcb, RAW_TTL);
#endif /* LWIP_MULTICAST_TX_OPTIONS */
pcb->next = raw_pcbs; pcb->next = raw_pcbs;
raw_pcbs = pcb; raw_pcbs = pcb;
} }

View File

@ -986,7 +986,7 @@
* core support for the corresponding IPv6 options. * core support for the corresponding IPv6 options.
*/ */
#if !defined LWIP_MULTICAST_TX_OPTIONS || defined __DOXYGEN__ #if !defined LWIP_MULTICAST_TX_OPTIONS || defined __DOXYGEN__
#define LWIP_MULTICAST_TX_OPTIONS ((LWIP_IGMP || LWIP_IPV6_MLD) && LWIP_UDP) #define LWIP_MULTICAST_TX_OPTIONS ((LWIP_IGMP || LWIP_IPV6_MLD) && (LWIP_UDP || LWIP_RAW))
#endif #endif
/** /**
* @} * @}

View File

@ -54,6 +54,7 @@ extern "C" {
#define RAW_FLAGS_CONNECTED 0x01U #define RAW_FLAGS_CONNECTED 0x01U
#define RAW_FLAGS_HDRINCL 0x02U #define RAW_FLAGS_HDRINCL 0x02U
#define RAW_FLAGS_MULTICAST_LOOP 0x04U
struct raw_pcb; struct raw_pcb;
@ -80,6 +81,13 @@ struct raw_pcb {
u8_t protocol; u8_t protocol;
u8_t flags; u8_t flags;
#if LWIP_MULTICAST_TX_OPTIONS
/** outgoing network interface for multicast packets, by interface index (if nonzero) */
u8_t mcast_ifindex;
/** TTL for outgoing multicast packets */
u8_t mcast_ttl;
#endif /* LWIP_MULTICAST_TX_OPTIONS */
/** receive callback function */ /** receive callback function */
raw_recv_fn recv; raw_recv_fn recv;
/* user-supplied argument for the recv callback */ /* user-supplied argument for the recv callback */
@ -118,6 +126,13 @@ void raw_netif_ip_addr_changed(const ip_addr_t* old_addr, const ip_addr_t* new_a
/* for compatibility with older implementation */ /* for compatibility with older implementation */
#define raw_new_ip6(proto) raw_new_ip_type(IPADDR_TYPE_V6, proto) #define raw_new_ip6(proto) raw_new_ip_type(IPADDR_TYPE_V6, proto)
#if LWIP_MULTICAST_TX_OPTIONS
#define raw_set_multicast_netif_index(pcb, idx) ((pcb)->mcast_ifindex = (idx))
#define raw_get_multicast_netif_index(pcb) ((pcb)->mcast_ifindex)
#define raw_set_multicast_ttl(pcb, value) ((pcb)->mcast_ttl = (value))
#define raw_get_multicast_ttl(pcb) ((pcb)->mcast_ttl)
#endif /* LWIP_MULTICAST_TX_OPTIONS */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif