diff --git a/examples/gcoap/Makefile b/examples/gcoap/Makefile index 8fb9e795f4..5a20324681 100644 --- a/examples/gcoap/Makefile +++ b/examples/gcoap/Makefile @@ -14,17 +14,33 @@ 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 + + ifeq (1,$(LWIP_IPV4)) + USEMODULE += ipv4_addr + + USEMODULE += lwip_arp + USEMODULE += lwip_ipv4 + USEMODULE += lwip_dhcp_auto + CFLAGS += -DETHARP_SUPPORT_STATIC_ENTRIES=1 + endif + + ifeq (1,$(LWIP_IPV6)) + USEMODULE += ipv6_addr + + USEMODULE += lwip_ipv6 + USEMODULE += lwip_ipv6_autoconfig + endif endif USEMODULE += gcoap @@ -33,6 +49,7 @@ USEMODULE += gcoap USEMODULE += od USEMODULE += fmt USEMODULE += netutils +USEMODULE += random # Add also the shell, some shell commands USEMODULE += shell USEMODULE += shell_cmds_default diff --git a/examples/gcoap/client.c b/examples/gcoap/client.c index d22c62eac0..370c1c74c3 100644 --- a/examples/gcoap/client.c +++ b/examples/gcoap/client.c @@ -141,18 +141,47 @@ 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) { - netif_t *netif; + bool is_ipv4 = false; + bool is_ipv6 = false; - /* parse hostname */ - if (netutils_get_ipv6((ipv6_addr_t *)&remote->addr, &netif, addr_str) < 0) { + if (IS_ACTIVE(SOCK_HAS_IPV6)) { + netif_t *netif; + /* IPv6 might contain '.', but IPv4 cannot contain ':' */ + if (strstr(addr_str, ":") != NULL) { + + /* 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; + } + } + + if (IS_ACTIVE(SOCK_HAS_IPV4)) { + if (!is_ipv6 && strstr(addr_str, ".") != NULL) { /* IPv4 */ + + /* 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; + } + } + + 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 +252,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 +300,15 @@ int gcoap_cli_cmd(int argc, char **argv) _proxied = false; return 0; } - printf("usage: %s proxy set [%%iface] \n", argv[0]); + + if (IS_ACTIVE(SOCK_HAS_IPV4)) { + printf("usage: %s proxy set \n", argv[0]); + } + + if (IS_ACTIVE(SOCK_HAS_IPV6)) { + printf("usage: %s proxy set [%%iface] \n", argv[0]); + } + printf(" %s proxy unset\n", argv[0]); return 1; } @@ -287,7 +346,14 @@ 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); + /* IPv6 might contain '.', but IPv4 cannot contain ':' */ + if (strstr(argv[apos], ":") != NULL) { + 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 +404,18 @@ int gcoap_cli_cmd(int argc, char **argv) return 0; } else { - printf("usage: %s [-c] [%%iface] [data]\n", - argv[0]); - printf(" %s ping [%%iface] \n", argv[0]); + if (IS_ACTIVE(SOCK_HAS_IPV4)) { + printf("usage: %s [-c] [data]\n", + argv[0]); + printf(" %s ping \n", argv[0]); + } + + if (IS_ACTIVE(SOCK_HAS_IPV6)) { + printf("usage: %s [-c] [%%iface] [data]\n", + argv[0]); + printf(" %s ping [%%iface] \n", argv[0]); + } + printf("Options\n"); printf(" -c Send confirmably (defaults to non-confirmable)\n"); return 1; diff --git a/sys/Makefile.include b/sys/Makefile.include index 2f7c9101ae..8a266165a6 100644 --- a/sys/Makefile.include +++ b/sys/Makefile.include @@ -189,3 +189,7 @@ endif ifneq (,$(filter preprocessor_%,$(USEMODULE))) include $(RIOTBASE)/sys/preprocessor/Makefile.include endif + +ifneq (,$(filter gcoap,$(USEMODULE))) + include $(RIOTBASE)/sys/net/application_layer/gcoap/Makefile.include +endif diff --git a/sys/net/application_layer/gcoap/Makefile.include b/sys/net/application_layer/gcoap/Makefile.include new file mode 100644 index 0000000000..5be3bbb663 --- /dev/null +++ b/sys/net/application_layer/gcoap/Makefile.include @@ -0,0 +1,4 @@ +ifeq (2, $(words $(filter ipv4 ipv6, $(USEMODULE)))) + $(shell $(COLOR_ECHO) "$(COLOR_YELLOW)Due to limitations in the gcoap API it is currently not \ + possible to use a dual stack setup$(COLOR_RESET)" 1>&2) +endif diff --git a/sys/net/application_layer/gcoap/gcoap.c b/sys/net/application_layer/gcoap/gcoap.c index e0622c74bb..aaa0e1afba 100644 --- a/sys/net/application_layer/gcoap/gcoap.c +++ b/sys/net/application_layer/gcoap/gcoap.c @@ -159,7 +159,17 @@ static void *_event_loop(void *arg) sock_udp_ep_t local; memset(&local, 0, sizeof(sock_udp_ep_t)); + + /* FIXME: Once the problems with IPv4/IPv6 dual stack use in RIOT are fixed, adapt these lines + * (and e.g. use AF_UNSPEC) */ +#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); @@ -828,8 +838,20 @@ static int _find_resource(gcoap_socket_type_t tl_type, static bool _memo_ep_is_multicast(const gcoap_request_memo_t *memo) { - return memo->remote_ep.family == AF_INET6 && - ipv6_addr_is_multicast((const ipv6_addr_t *)&memo->remote_ep.addr.ipv6); + switch (memo->remote_ep.family) { +#ifdef SOCK_HAS_IPV6 + case AF_INET6: + return ipv6_addr_is_multicast((const ipv6_addr_t *)&memo->remote_ep.addr.ipv6); +#endif +#ifdef SOCK_HAS_IPV4 + case AF_INET: + return ipv4_addr_is_multicast((const ipv4_addr_t *)&memo->remote_ep.addr.ipv4); +#endif + default: + assert(0); + } + + return false; } /*