diff --git a/examples/gcoap/Makefile b/examples/gcoap/Makefile index bcb3c4731e673..8c93d4e46f7fe 100644 --- a/examples/gcoap/Makefile +++ b/examples/gcoap/Makefile @@ -14,17 +14,36 @@ RIOTBASE ?= $(CURDIR)/../.. USEMODULE += netdev_default # use GNRC by default -LWIP ?= 0 +LWIP_IPV4 ?= 0 +LWIP_IPV6 ?= 0 -ifeq (0,$(LWIP)) +ifeq (,$(filter 1, $(LWIP_IPV4) $(LWIP_IPV6))) USEMODULE += auto_init_gnrc_netif # Specify the mandatory networking modules USEMODULE += gnrc_ipv6_default # Additional networking modules that can be dropped if not needed USEMODULE += gnrc_icmpv6_echo else - USEMODULE += lwip_ipv6 USEMODULE += lwip_netdev + + ifneq (0,$(LWIP_IPV4)) + USEMODULE += ipv4_addr + + USEMODULE += lwip_arp + USEMODULE += lwip_ipv4 + USEMODULE += lwip_dhcp_auto + CFLAGS += -DETHARP_SUPPORT_STATIC_ENTRIES=1 + + # not included when using IPv4-only, but required by CoAP + USEMODULE += random + endif + + ifneq (0,$(LWIP_IPV6)) + USEMODULE += ipv6_addr + + USEMODULE += lwip_ipv6 + USEMODULE += lwip_ipv6_autoconfig + endif endif USEMODULE += gcoap diff --git a/examples/gcoap/client.c b/examples/gcoap/client.c index d22c62eac0d32..8538135645051 100644 --- a/examples/gcoap/client.c +++ b/examples/gcoap/client.c @@ -141,18 +141,48 @@ static void _resp_handler(const gcoap_request_memo_t *memo, coap_pkt_t* pdu, } } -static bool _parse_endpoint(sock_udp_ep_t *remote, - const char *addr_str, const char *port_str) +static bool _parse_endpoint(sock_udp_ep_t *remote, const char *addr_str, const char *port_str) { + bool is_ipv4 = false; + bool is_ipv6 = false; + +#ifdef SOCK_HAS_IPV6 netif_t *netif; + if (strstr(addr_str, ":") != NULL) { /* IPv6 might contain '.', but IPv4 cannot contain ':' */ + + /* parse hostname */ + if (netutils_get_ipv6((ipv6_addr_t *)&remote->addr, &netif, addr_str) < 0) { + puts("gcoap_cli: unable to parse destination ipv6 address"); + return false; + } + + is_ipv6 = true; + remote->netif = netif ? netif_get_id(netif) : SOCK_ADDR_ANY_NETIF; + remote->family = AF_INET6; + } +#endif + +#ifdef SOCK_HAS_IPV4 + if (!is_ipv6 && strstr(addr_str, ".") != NULL) { /* IPv4 */ - /* parse hostname */ - if (netutils_get_ipv6((ipv6_addr_t *)&remote->addr, &netif, addr_str) < 0) { + /* parse hostname */ + if (netutils_get_ipv4((ipv4_addr_t *)&remote->addr, addr_str) < 0) { + puts("gcoap_cli: unable to parse destination ipv4 address"); + return false; + } + + is_ipv4 = true; + remote->netif = SOCK_ADDR_ANY_NETIF; + remote->family = AF_INET; + } +#else + (void)is_ipv6; +#endif + + if (!is_ipv4 && !is_ipv6) { puts("gcoap_cli: unable to parse destination address"); return false; } - remote->netif = netif ? netif_get_id(netif) : SOCK_ADDR_ANY_NETIF; - remote->family = AF_INET6; /* parse port */ remote->port = atoi(port_str); @@ -223,12 +253,34 @@ int gcoap_cli_cmd(int argc, char **argv) printf("CoAP open requests: %u\n", open_reqs); printf("Configured Proxy: "); if (_proxied) { +#ifdef SOCK_HAS_IPV6 char addrstr[IPV6_ADDR_MAX_STR_LEN]; - printf("[%s]:%u\n", - ipv6_addr_to_str(addrstr, - (ipv6_addr_t *) &_proxy_remote.addr.ipv6, - sizeof(addrstr)), - _proxy_remote.port); +#else + char addrstr[IPV4_ADDR_MAX_STR_LEN]; +#endif + + switch (_proxy_remote.family) { +#ifdef SOCK_HAS_IPV4 + case AF_INET: + printf("%s:%u\n", + ipv4_addr_to_str(addrstr, + (ipv4_addr_t *) &_proxy_remote.addr.ipv4, + sizeof(addrstr)), + _proxy_remote.port); + break; +#endif +#ifdef SOCK_HAS_IPV6 + case AF_INET6: + printf("[%s]:%u\n", + ipv6_addr_to_str(addrstr, + (ipv6_addr_t *) &_proxy_remote.addr.ipv6, + sizeof(addrstr)), + _proxy_remote.port); + break; +#endif + default: + assert(0); + } } else { puts("None"); @@ -249,7 +301,12 @@ int gcoap_cli_cmd(int argc, char **argv) _proxied = false; return 0; } - printf("usage: %s proxy set [%%iface] \n", argv[0]); +#ifdef SOCK_HAS_IPV4 + printf("usage: %s proxy set \n", argv[0]); +#endif +#ifdef SOCK_HAS_IPV6 + printf("usage: %s proxy set [%%iface] \n", argv[0]); +#endif printf(" %s proxy unset\n", argv[0]); return 1; } @@ -287,7 +344,12 @@ int gcoap_cli_cmd(int argc, char **argv) } if (_proxied) { - uri_len = snprintf(proxy_uri, 64, "coap://[%s]:%s%s", argv[apos], argv[apos+1], uri); + if (strstr(argv[apos], ":") != NULL) { /* IPv6 might contain '.', but IPv4 cannot contain ':' */ + uri_len = snprintf(proxy_uri, 64, "coap://[%s]:%s%s", argv[apos], argv[apos+1], uri); + } + else { + uri_len = snprintf(proxy_uri, 64, "coap://%s:%s%s", argv[apos], argv[apos+1], uri); + } uri = proxy_uri; gcoap_req_init(&pdu, &buf[0], CONFIG_GCOAP_PDU_BUF_SIZE, code_pos, NULL); @@ -338,9 +400,20 @@ int gcoap_cli_cmd(int argc, char **argv) return 0; } else { - printf("usage: %s [-c] [%%iface] [data]\n", +#ifdef SOCK_HAS_IPV4 + printf("usage: %s [-c] [data]\n", + argv[0]); +#endif +#ifdef SOCK_HAS_IPV6 + printf("usage: %s [-c] [%%iface] [data]\n", argv[0]); - printf(" %s ping [%%iface] \n", argv[0]); +#endif +#ifdef SOCK_HAS_IPV4 + printf(" %s ping \n", argv[0]); +#endif +#ifdef SOCK_HAS_IPV6 + printf(" %s ping [%%iface] \n", argv[0]); +#endif printf("Options\n"); printf(" -c Send confirmably (defaults to non-confirmable)\n"); return 1; diff --git a/sys/net/application_layer/gcoap/gcoap.c b/sys/net/application_layer/gcoap/gcoap.c index 23dbcba156503..efc4e01291a06 100644 --- a/sys/net/application_layer/gcoap/gcoap.c +++ b/sys/net/application_layer/gcoap/gcoap.c @@ -149,7 +149,19 @@ static void *_event_loop(void *arg) sock_udp_ep_t local; memset(&local, 0, sizeof(sock_udp_ep_t)); + +#if defined(SOCK_HAS_IPV4) && defined(SOCK_HAS_IPV6) +#error "Due to limitations in the gcoap API it is currently not possible to use a dual stack setup" +#endif + +#ifdef SOCK_HAS_IPV4 + local.family = AF_INET; +#endif + +#ifdef SOCK_HAS_IPV6 local.family = AF_INET6; +#endif + local.netif = SOCK_ADDR_ANY_NETIF; local.port = CONFIG_GCOAP_PORT; int res = sock_udp_create(&_sock_udp, &local, NULL, 0);