Implement UDP dual-stack PCB support

Create special IP address type "IPADDR_TYPE_ANY" for it.
SNMP uses new feature in non-netconn mode.

TODO: Same for TCP & RAW, adapt NETCONN to use this feature
This commit is contained in:
Dirk Ziegelmeier 2016-02-24 22:33:05 +01:00
parent 1dde3d6e56
commit 953b7bdd59
8 changed files with 62 additions and 35 deletions

View File

@ -84,13 +84,16 @@ snmp_get_local_ip_for_dst(void* handle, const ip_addr_t *dst, ip_addr_t *result)
void
snmp_init(void)
{
struct udp_pcb *snmp_pcb = udp_new();
err_t err;
struct udp_pcb *snmp_pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
LWIP_ERROR("snmp_raw: no PCB", (snmp_pcb != NULL), return;);
snmp_traps_handle = snmp_pcb;
udp_recv(snmp_pcb, snmp_recv, (void *)SNMP_IN_PORT);
udp_bind(snmp_pcb, IP_ADDR_ANY, SNMP_IN_PORT);
err = udp_bind(snmp_pcb, IP_ANY_TYPE, SNMP_IN_PORT);
LWIP_ERROR("snmp_raw: Unable to bind PCB", (err == ERR_OK), return;);
}
#endif /* LWIP_SNMP && SNMP_USE_RAW */

View File

@ -61,6 +61,10 @@
#include "lwip/api.h"
#include "netif/ppp/ppp_impl.h"
#if LWIP_IPV4 && LWIP_IPV6
const ip_addr_t ip_addr_any_type = IPADDR_ANY_TYPE_INIT;
#endif
/* Compile-time sanity checks for configuration errors.
* These can be done independently of LWIP_DEBUG, without penalty.
*/

View File

@ -167,7 +167,7 @@ raw_input(struct pbuf *p, struct netif *inp)
err_t
raw_bind(struct raw_pcb *pcb, const ip_addr_t *ipaddr)
{
if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr)) {
if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr)) {
return ERR_VAL;
}
ip_addr_set_ipaddr(&pcb->local_ip, ipaddr);
@ -190,7 +190,7 @@ raw_bind(struct raw_pcb *pcb, const ip_addr_t *ipaddr)
err_t
raw_connect(struct raw_pcb *pcb, const ip_addr_t *ipaddr)
{
if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr)) {
if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr)) {
return ERR_VAL;
}
ip_addr_set_ipaddr(&pcb->remote_ip, ipaddr);

View File

@ -450,7 +450,7 @@ tcp_bind(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port)
#endif /* LWIP_IPV4 */
/* still need to check for ipaddr == NULL in IPv6 only case */
if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr)) {
if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr)) {
return ERR_VAL;
}
@ -756,7 +756,7 @@ tcp_connect(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port,
u32_t iss;
u16_t old_local_port;
if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr)) {
if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr)) {
return ERR_VAL;
}

View File

@ -147,11 +147,20 @@ again:
* @return 1 on match, 0 otherwise
*/
static u8_t
udp_input_local_match(struct udp_pcb *pcb, struct netif *inp, u8_t broadcast)
udp_input_local_match(struct udp_pcb *pcb, struct netif *netif, u8_t broadcast)
{
LWIP_UNUSED_ARG(netif); /* in IPv6 only case */
LWIP_UNUSED_ARG(broadcast); /* in IPv6 only case */
/* @todo: Add special dualstack case here */
/* Dual-stack: PCBs listening to any IP type also listen to any IP address */
if(IP_IS_ANY_TYPE_VAL(pcb->local_ip)) {
#if IP_SOF_BROADCAST_RECV
if(broadcast && !ip_get_option(pcb, SOF_BROADCAST)) {
return 0;
}
#endif /* IP_SOF_BROADCAST_RECV */
return 1;
}
/* Only need to check PCB if incoming IP version matches PCB IP version */
if(ip_current_is_v6() == IP_IS_V6_VAL(pcb->local_ip)) {
@ -167,7 +176,7 @@ udp_input_local_match(struct udp_pcb *pcb, struct netif *inp, u8_t broadcast)
{
if(ip4_addr_isany(ip_2_ip4(&pcb->local_ip)) ||
((ip4_current_dest_addr()->addr == IPADDR_BROADCAST)) ||
ip4_addr_netcmp(ip_2_ip4(&pcb->local_ip), ip4_current_dest_addr(), netif_ip4_netmask(inp))) {
ip4_addr_netcmp(ip_2_ip4(&pcb->local_ip), ip4_current_dest_addr(), netif_ip4_netmask(netif))) {
return 1;
}
}
@ -907,7 +916,7 @@ udp_bind(struct udp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port)
#endif /* LWIP_IPV4 */
/* still need to check for ipaddr == NULL in IPv6 only case */
if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr)) {
if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr)) {
return ERR_VAL;
}
@ -998,7 +1007,7 @@ udp_connect(struct udp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port)
{
struct udp_pcb *ipcb;
if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr)) {
if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr)) {
return ERR_VAL;
}
@ -1123,9 +1132,8 @@ udp_new(void)
return pcb;
}
#if LWIP_IPV6
/**
* Create a UDP PCB for IPv6.
* Create a UDP PCB for specific IP type. See IPADDR_TYPE_XX definitions.
*
* @return The UDP PCB which was created. NULL if the PCB data structure
* could not be allocated.
@ -1133,17 +1141,18 @@ udp_new(void)
* @see udp_remove()
*/
struct udp_pcb *
udp_new_ip6(void)
udp_new_ip_type(u8_t type)
{
struct udp_pcb *pcb;
pcb = udp_new();
#if LWIP_IPV4
IP_SET_TYPE_VAL(pcb->local_ip, IPADDR_TYPE_V6);
IP_SET_TYPE_VAL(pcb->remote_ip, IPADDR_TYPE_V6);
#endif /* LWIP_IPV4 */
#if LWIP_IPV4 && LWIP_IPV6
IP_SET_TYPE_VAL(pcb->local_ip, type);
IP_SET_TYPE_VAL(pcb->remote_ip, type);
#else
LWIP_UNUSED_ARG(type);
#endif /* LWIP_IPV4 && LWIP_IPV6 */
return pcb;
}
#endif /* LWIP_IPV6 */
#if LWIP_IPV4
/** This function is called from netif.c when address is changed

View File

@ -42,6 +42,11 @@
extern "C" {
#endif
/** These are the values for ip_addr_t.type */
#define IPADDR_TYPE_V4 0U
#define IPADDR_TYPE_V6 6U
#define IPADDR_TYPE_ANY 46U
#if LWIP_IPV4 && LWIP_IPV6
/** A union struct for both IP version's addresses.
* ATTENTION: watch out for its size when adding IPv6 address scope!
@ -54,19 +59,21 @@ typedef struct _ip_addr {
u8_t type;
} ip_addr_t;
/** These are the values for ip_addr_t.type */
#define IPADDR_TYPE_V4 0U
#define IPADDR_TYPE_V6 6U
extern const ip_addr_t ip_addr_any_type;
#define IPADDR4_INIT(u32val) { { { { u32val, 0ul, 0ul, 0ul } } }, IPADDR_TYPE_V4 }
#define IPADDR6_INIT(a, b, c, d) { { { { a, b, c, d } } }, IPADDR_TYPE_V6 }
#define IP_IS_ANY_TYPE_VAL(ipaddr) ((ipaddr).type == IPADDR_TYPE_ANY)
#define IPADDR_ANY_TYPE_INIT { { { { 0ul, 0ul, 0ul, 0ul } } }, IPADDR_TYPE_ANY }
#define IP_IS_V6_VAL(ipaddr) ((ipaddr).type == IPADDR_TYPE_V6)
#define IP_IS_V6(ipaddr) (((ipaddr) != NULL) && IP_IS_V6_VAL(*(ipaddr)))
#define IP_SET_TYPE_VAL(ipaddr, iptype) do { (ipaddr).type = (iptype); }while(0)
#define IP_SET_TYPE(ipaddr, iptype) do { if((ipaddr) != NULL) { IP_SET_TYPE_VAL(*(ipaddr), iptype); }}while(0)
#define IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr) (IP_IS_V6_VAL(pcb->local_ip) == IP_IS_V6(ipaddr))
#define IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr) (pcb->local_ip.type == ipaddr->type)
#define IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr) (IP_IS_ANY_TYPE_VAL(pcb->local_ip) || IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr))
/* Convert generic ip address to specific protocol version */
#define ip_2_ip6(ipaddr) (&((ipaddr)->u_addr.ip6))
@ -88,12 +95,10 @@ typedef struct _ip_addr {
IP_SET_TYPE(ipaddr, IPADDR_TYPE_V4); }}while(0)
#define ip_addr_get_ip4_u32(ipaddr) (((ipaddr) && !IP_IS_V6(ipaddr)) ? \
ip4_addr_get_u32(ip_2_ip4(ipaddr)) : 0)
#define ip_addr_set(dest, src) do{if(IP_IS_V6(src)){ \
ip6_addr_set(ip_2_ip6(dest), ip_2_ip6(src)); IP_SET_TYPE(dest, IPADDR_TYPE_V6); }else{ \
ip4_addr_set(ip_2_ip4(dest), ip_2_ip4(src)); IP_SET_TYPE(dest, IPADDR_TYPE_V4); }}while(0)
#define ip_addr_set_ipaddr(dest, src) do{if(IP_IS_V6(src)){ \
ip6_addr_set(ip_2_ip6(dest), ip_2_ip6(src)); IP_SET_TYPE(dest, IPADDR_TYPE_V6); }else{ \
ip4_addr_set(ip_2_ip4(dest), ip_2_ip4(src)); IP_SET_TYPE(dest, IPADDR_TYPE_V4); }}while(0)
#define ip_addr_set(dest, src) do{ IP_SET_TYPE(dest, src->type); if(IP_IS_V6(src)){ \
ip6_addr_set(ip_2_ip6(dest), ip_2_ip6(src)); }else{ \
ip4_addr_set(ip_2_ip4(dest), ip_2_ip4(src)); }}while(0)
#define ip_addr_set_ipaddr(dest, src) ip_addr_set(dest, src)
#define ip_addr_set_zero(ipaddr) do{ \
ip6_addr_set_zero(ip_2_ip6(ipaddr)); IP_SET_TYPE(ipaddr, 0); }while(0)
#define ip_addr_set_zero_ip4(ipaddr) do{ \
@ -150,7 +155,8 @@ int ipaddr_aton(const char *cp, ip_addr_t *addr);
#else /* LWIP_IPV4 && LWIP_IPV6 */
#define IP_ADDR_PCB_VERSION_MATCH(addr, pcb) 1
#define IP_ADDR_PCB_VERSION_MATCH(addr, pcb) 1
#define IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr) 1
#if LWIP_IPV4
@ -158,6 +164,7 @@ typedef ip4_addr_t ip_addr_t;
#define IPADDR4_INIT(u32val) { u32val }
#define IP_IS_V6_VAL(ipaddr) 0
#define IP_IS_V6(ipaddr) 0
#define IP_IS_ANY_TYPE_VAL(ipaddr) 0
#define IP_SET_TYPE_VAL(ipaddr, iptype)
#define IP_SET_TYPE(ipaddr, iptype)
#define ip_2_ip4(ipaddr) (ipaddr)
@ -195,6 +202,7 @@ typedef ip6_addr_t ip_addr_t;
#define IPADDR6_INIT(a, b, c, d) { { a, b, c, d } }
#define IP_IS_V6_VAL(ipaddr) 1
#define IP_IS_V6(ipaddr) 1
#define IP_IS_ANY_TYPE_VAL(ipaddr) 0
#define IP_SET_TYPE_VAL(ipaddr, iptype)
#define IP_SET_TYPE(ipaddr, iptype)
#define ip_2_ip6(ipaddr) (ipaddr)
@ -265,6 +273,12 @@ extern const ip_addr_t ip6_addr_any;
#endif
#if LWIP_IPV4 && LWIP_IPV6
#define IP_ANY_TYPE (&ip_addr_any_type)
#else
#define IP_ANY_TYPE IP_ADDR_ANY
#endif
#ifdef __cplusplus
}
#endif

View File

@ -123,6 +123,7 @@ extern struct udp_pcb *udp_pcbs;
/* The following functions is the application layer interface to the
UDP code. */
struct udp_pcb * udp_new (void);
struct udp_pcb * udp_new_ip_type(u8_t type);
void udp_remove (struct udp_pcb *pcb);
err_t udp_bind (struct udp_pcb *pcb, const ip_addr_t *ipaddr,
u16_t port);
@ -164,10 +165,6 @@ void udp_input (struct pbuf *p, struct netif *inp);
void udp_init (void);
#if LWIP_IPV6
struct udp_pcb * udp_new_ip6(void);
#endif /* LWIP_IPV6 */
#if LWIP_MULTICAST_TX_OPTIONS
#define udp_set_multicast_netif_addr(pcb, ip4addr) ip_addr_copy_from_ip4((pcb)->multicast_ip, *(ip4addr))
#define udp_get_multicast_netif_addr(pcb) ip_2_ip4(&(pcb)->multicast_ip)

View File

@ -131,7 +131,7 @@ ppp_pcb *pppol2tp_create(struct netif *pppif,
#if LWIP_IPV6
if (IP_IS_V6_VAL(*ipaddr)) {
udp = udp_new_ip6();
udp = udp_new_ip_type(IPADDR_TYPE_V6);
} else
#endif /* LWIP_IPV6 */
udp = udp_new();