diff options
Diffstat (limited to 'components/net/netdev/src')
| -rw-r--r-- | components/net/netdev/src/netdev.c | 284 | ||||
| -rw-r--r-- | components/net/netdev/src/netdev_ipaddr.c | 357 |
2 files changed, 534 insertions, 107 deletions
diff --git a/components/net/netdev/src/netdev.c b/components/net/netdev/src/netdev.c index 5f49a46f17..68e5364a9e 100644 --- a/components/net/netdev/src/netdev.c +++ b/components/net/netdev/src/netdev.c @@ -34,11 +34,11 @@ struct netdev *netdev_default; /** * This function will register network interface device and * add it to network interface device list. - * + * * @param netdev the network interface device object * @param name the network interface device name * @param user_data user-specific data - * + * * @return 0: registered successfully * -1: registered failed */ @@ -58,9 +58,21 @@ int netdev_register(struct netdev *netdev, const char *name, void *user_data) ip_addr_set_zero(&(netdev->ip_addr)); ip_addr_set_zero(&(netdev->netmask)); ip_addr_set_zero(&(netdev->gw)); + + IP_SET_TYPE_VAL(netdev->ip_addr, IPADDR_TYPE_V4); + IP_SET_TYPE_VAL(netdev->netmask, IPADDR_TYPE_V4); + IP_SET_TYPE_VAL(netdev->gw, IPADDR_TYPE_V4); +#if NETDEV_IPV6 + for (index = 0; index < NETDEV_IPV6_NUM_ADDRESSES; index++) + { + ip_addr_set_zero(&(netdev->ip6_addr[index])); + IP_SET_TYPE_VAL(netdev->ip_addr, IPADDR_TYPE_V6); + } +#endif /* NETDEV_IPV6 */ for (index = 0; index < NETDEV_DNS_SERVERS_NUM; index++) { ip_addr_set_zero(&(netdev->dns_servers[index])); + IP_SET_TYPE_VAL(netdev->ip_addr, IPADDR_TYPE_V4); } netdev->status_callback = RT_NULL; netdev->addr_callback = RT_NULL; @@ -87,15 +99,15 @@ int netdev_register(struct netdev *netdev, const char *name, void *user_data) rt_hw_interrupt_enable(level); - return RT_EOK; + return RT_EOK; } /** * This function will unregister network interface device and * delete it from network interface device list. - * + * * @param netdev the network interface device object - * + * * @return 0: unregistered successfully * -1: unregistered failed */ @@ -106,7 +118,7 @@ int netdev_unregister(struct netdev *netdev) struct netdev *cur_netdev = RT_NULL; RT_ASSERT(netdev); - + if (netdev_list == RT_NULL) { return -RT_ERROR; @@ -117,29 +129,46 @@ int netdev_unregister(struct netdev *netdev) for (node = &(netdev_list->list); node; node = rt_slist_next(node)) { cur_netdev = rt_slist_entry(node, struct netdev, list); - if (cur_netdev && (rt_memcpy(cur_netdev, netdev, sizeof(struct netdev)) == 0)) + if (cur_netdev == netdev) { - rt_slist_remove(&(netdev_list->list), &(cur_netdev->list)); - rt_hw_interrupt_enable(level); - - return RT_EOK; + /* find this network interface device in network interface device list */ + if (netdev_list == netdev && rt_slist_next(&netdev_list->list) == RT_NULL) + { + netdev_list = RT_NULL; + } + else + { + rt_slist_remove(&(netdev_list->list), &(cur_netdev->list)); + } + if (netdev_default == netdev) + { + netdev_default = netdev_list; + } + break; } } - rt_hw_interrupt_enable(level); - /* not find this network interface device in network interface device list */ + if (cur_netdev == netdev) + { +#ifdef RT_USING_SAL + extern int sal_netdev_cleanup(struct netdev *netdev); + sal_netdev_cleanup(netdev); +#endif + rt_memset(netdev, 0, sizeof(*netdev)); + } + return -RT_ERROR; } /** * This function will get the first network interface device * with the flags in network interface device list. - * + * * @param flags the network interface device flags - * + * * @return != NULL: network interface device object - * NULL: get failed + * NULL: get failed */ struct netdev *netdev_get_first_by_flags(uint16_t flags) { @@ -172,11 +201,11 @@ struct netdev *netdev_get_first_by_flags(uint16_t flags) /** * This function will get the first network interface device * in network interface device list by IP address. - * + * * @param addr the network interface device IP address - * + * * @return != NULL: network interface device object - * NULL: get failed + * NULL: get failed */ struct netdev *netdev_get_by_ipaddr(ip_addr_t *ip_addr) { @@ -209,11 +238,11 @@ struct netdev *netdev_get_by_ipaddr(ip_addr_t *ip_addr) /** * This function will get network interface device * in network interface device list by netdev name. - * + * * @param name the network interface device name - * + * * @return != NULL: network interface device object - * NULL: get failed + * NULL: get failed */ struct netdev *netdev_get_by_name(const char *name) { @@ -247,11 +276,11 @@ struct netdev *netdev_get_by_name(const char *name) /** * This function will get the first network interface device * in network interface device list by protocol family type. - * + * * @param family the network interface device protocol family type - * + * * @return != NULL: network interface device object - * NULL: get failed + * NULL: get failed */ struct netdev *netdev_get_by_family(int family) { @@ -296,15 +325,15 @@ struct netdev *netdev_get_by_family(int family) /** * This function will get the family type from network interface device - * + * * @param netdev network interface device object - * + * * @return the network interface device family type */ int netdev_family_get(struct netdev *netdev) { - RT_ASSERT(netdev); - + RT_ASSERT(netdev); + return ((struct sal_proto_family *)netdev->sal_user_data)->family; } @@ -312,7 +341,7 @@ int netdev_family_get(struct netdev *netdev) /** * This function will set default network interface device. - * + * * @param netdev the network interface device to change */ void netdev_set_default(struct netdev *netdev) @@ -320,15 +349,21 @@ void netdev_set_default(struct netdev *netdev) if (netdev) { netdev_default = netdev; - LOG_D("Setting default network interface device name(%s) successfully.", netdev->name); + + if (netdev->ops->set_default) + { + /* set default network interface device in the current network stack */ + netdev->ops->set_default(netdev); + } + LOG_D("Setting default network interface device name(%s) successfully.", netdev->name); } } /** * This function will enable network interface device . - * + * * @param netdev the network interface device to change - * + * * @return 0: set status successfully * -1: set status failed */ @@ -341,7 +376,7 @@ int netdev_set_up(struct netdev *netdev) LOG_E("The network interface device(%s) not support to set status.", netdev->name); return -RT_ERROR; } - + /* network interface device status flags check */ if (netdev_is_up(netdev)) { @@ -353,9 +388,9 @@ int netdev_set_up(struct netdev *netdev) } /** * This function will disable network interface device. - * + * * @param netdev the network interface device to change - * + * * @return 0: set status successfully * -1: set sttaus failed */ @@ -368,7 +403,7 @@ int netdev_set_down(struct netdev *netdev) LOG_E("The network interface device(%s) not support to set status.", netdev->name); return -RT_ERROR; } - + /* network interface device status flags check */ if (!netdev_is_up(netdev)) { @@ -381,10 +416,10 @@ int netdev_set_down(struct netdev *netdev) /** * This function will control network interface device DHCP capability enable or disable. - * + * * @param netdev the network interface device device to change * @param is_enable the new DHCP status - * + * * @return 0: set DHCP status successfully * -1: set DHCP status failed */ @@ -403,17 +438,17 @@ int netdev_dhcp_enabled(struct netdev *netdev, rt_bool_t is_enabled) { return RT_EOK; } - + /* execute network interface device DHCP capability control operations */ return netdev->ops->set_dhcp(netdev, is_enabled); } /** * This function will set network interface device IP address. - * + * * @param netdev the network interface device to change * @param ipaddr the new IP address - * + * * @return 0: set IP address successfully * -1: set IP address failed */ @@ -427,7 +462,7 @@ int netdev_set_ipaddr(struct netdev *netdev, const ip_addr_t *ip_addr) LOG_E("The network interface device(%s) not support to set IP address.", netdev->name); return -RT_ERROR; } - + if (netdev_is_dhcp_enabled(netdev)) { LOG_E("The network interface device(%s) DHCP capability is enable, not support set IP address.", netdev->name); @@ -440,10 +475,10 @@ int netdev_set_ipaddr(struct netdev *netdev, const ip_addr_t *ip_addr) /** * This function will set network interface device netmask address. - * + * * @param netdev the network interface device to change * @param netmask the new netmask address - * + * * @return 0: set netmask address successfully * -1: set netmask address failed */ @@ -457,7 +492,7 @@ int netdev_set_netmask(struct netdev *netdev, const ip_addr_t *netmask) LOG_E("The network interface device(%s) not support to set netmask address.", netdev->name); return -RT_ERROR; } - + if (netdev_is_dhcp_enabled(netdev)) { LOG_E("The network interface device(%s) DHCP capability is enable, not support set netmask address.", netdev->name); @@ -470,10 +505,10 @@ int netdev_set_netmask(struct netdev *netdev, const ip_addr_t *netmask) /** * This function will set network interface device gateway address. - * + * * @param netdev the network interface device to change - * @param gateway the new gateway address - * + * @param gateway the new gateway address + * * @return 0: set gateway address successfully * -1: set gateway address failed */ @@ -487,7 +522,7 @@ int netdev_set_gw(struct netdev *netdev, const ip_addr_t *gw) LOG_E("The network interface device(%s) not support to set gateway address.", netdev->name); return -RT_ERROR; } - + if (netdev_is_dhcp_enabled(netdev)) { LOG_E("The network interface device(%s) DHCP capability is enable, not support set gateway address.", netdev->name); @@ -500,10 +535,10 @@ int netdev_set_gw(struct netdev *netdev, const ip_addr_t *gw) /** * This function will set network interface device DNS server address. - * + * * @param netdev the network interface device to change * @param dns_server the new DNS server address - * + * * @return 0: set netmask address successfully * -1: set netmask address failed */ @@ -530,7 +565,7 @@ int netdev_set_dns_server(struct netdev *netdev, uint8_t dns_num, const ip_addr_ /** * This function will set callback to be called when the network interface device status has been changed. - * + * * @param netdev the network interface device to change * @param status_callback the callback be called when the status has been changed. */ @@ -544,7 +579,7 @@ void netdev_set_status_callback(struct netdev *netdev, netdev_callback_fn status /** * This function will set callback to be called when the network interface device address has been changed. - * + * * @param netdev the network interface device to change * @param addr_callback the callback be called when the address has been changed. */ @@ -560,7 +595,7 @@ void netdev_set_addr_callback(struct netdev *netdev, netdev_callback_fn addr_cal /** * This function will set network interface device IP address. * @NOTE it can only be called in the network interface device driver. - * + * * @param netdev the network interface device to change * @param ipaddr the new IP address */ @@ -591,7 +626,7 @@ void netdev_low_level_set_ipaddr(struct netdev *netdev, const ip_addr_t *ip_addr /** * This function will set network interface device netmask address. * @NOTE it can only be called in the network interface device driver. - * + * * @param netdev the network interface device to change * @param netmask the new netmask address */ @@ -605,7 +640,7 @@ void netdev_low_level_set_netmask(struct netdev *netdev, const ip_addr_t *netmas #ifdef RT_USING_SAL /* set network interface device flags to internet up */ - if (netdev_is_up(netdev) && netdev_is_link_up(netdev) && + if (netdev_is_up(netdev) && netdev_is_link_up(netdev) && !ip_addr_isany(&(netdev->ip_addr))) { sal_check_netdev_internet_up(netdev); @@ -623,7 +658,7 @@ void netdev_low_level_set_netmask(struct netdev *netdev, const ip_addr_t *netmas /** * This function will set network interface device gateway address. * @NOTE it can only be called in the network interface device driver. - * + * * @param netdev the network interface device to change * @param gateway the new gateway address */ @@ -637,7 +672,7 @@ void netdev_low_level_set_gw(struct netdev *netdev, const ip_addr_t *gw) #ifdef RT_USING_SAL /* set network interface device flags to internet up */ - if (netdev_is_up(netdev) && netdev_is_link_up(netdev) && + if (netdev_is_up(netdev) && netdev_is_link_up(netdev) && !ip_addr_isany(&(netdev->ip_addr))) { sal_check_netdev_internet_up(netdev); @@ -655,10 +690,10 @@ void netdev_low_level_set_gw(struct netdev *netdev, const ip_addr_t *gw) /** * This function will set network interface device DNS server address. * @NOTE it can only be called in the network interface device driver. - * + * * @param netdev the network interface device to change * @param dns_server the new DNS server address - * + * */ void netdev_low_level_set_dns_server(struct netdev *netdev, uint8_t dns_num, const ip_addr_t *dns_server) { @@ -666,6 +701,10 @@ void netdev_low_level_set_dns_server(struct netdev *netdev, uint8_t dns_num, con RT_ASSERT(dns_server); + if (netdev == RT_NULL) + { + return; + } /* check DNS servers is exist */ for (index = 0; index < NETDEV_DNS_SERVERS_NUM; index++) { @@ -675,7 +714,7 @@ void netdev_low_level_set_dns_server(struct netdev *netdev, uint8_t dns_num, con } } - if (netdev && dns_num < NETDEV_DNS_SERVERS_NUM) + if (dns_num < NETDEV_DNS_SERVERS_NUM) { ip_addr_copy(netdev->dns_servers[dns_num], *dns_server); @@ -707,7 +746,7 @@ static void netdev_auto_change_default(struct netdev *netdev) /** * This function will set network interface device status. * @NOTE it can only be called in the network interface device driver. - * + * * @param netdev the network interface device to change * @param is_up the new status */ @@ -740,14 +779,14 @@ void netdev_low_level_set_status(struct netdev *netdev, rt_bool_t is_up) /** * This function will set network interface device active link status. * @NOTE it can only be called in the network interface device driver. - * + * * @param netdev the network interface device to change * @param is_up the new link status */ void netdev_low_level_set_link_status(struct netdev *netdev, rt_bool_t is_up) { if (netdev && netdev_is_link_up(netdev) != is_up) - { + { if (is_up) { netdev->flags |= NETDEV_FLAG_LINK_UP; @@ -763,7 +802,7 @@ void netdev_low_level_set_link_status(struct netdev *netdev, rt_bool_t is_up) else { netdev->flags &= ~NETDEV_FLAG_LINK_UP; - + /* set network interface device flags to internet down */ netdev->flags &= ~NETDEV_FLAG_INTERNET_UP; @@ -784,7 +823,7 @@ void netdev_low_level_set_link_status(struct netdev *netdev, rt_bool_t is_up) /** * This function will set network interface device DHCP status. * @NOTE it can only be called in the network interface device driver. - * + * * @param netdev the network interface device to change * @param is_up the new DHCP status */ @@ -809,7 +848,7 @@ void netdev_low_level_set_dhcp_status(struct netdev *netdev, rt_bool_t is_enable } } -#ifdef FINSH_USING_MSH +#ifdef RT_USING_FINSH #include <finsh.h> @@ -820,7 +859,6 @@ static void netdev_list_if(void) #define NETDEV_IFCONFIG_IEMI_MAX_LEN 8 rt_ubase_t index; - rt_base_t level; rt_slist_t *node = RT_NULL; struct netdev *netdev = RT_NULL; struct netdev *cur_netdev_list = netdev_list; @@ -831,15 +869,13 @@ static void netdev_list_if(void) return; } - level = rt_hw_interrupt_disable(); - for (node = &(cur_netdev_list->list); node; node = rt_slist_next(node)) { netdev = rt_list_entry(node, struct netdev, list); - rt_kprintf("network interface device: %s%s\n", - netdev->name, - (netdev == netdev_default)?" (Default)":""); + rt_kprintf("network interface device: %.*s%s\n", + RT_NAME_MAX, netdev->name, + (netdev == netdev_default) ? " (Default)" : ""); rt_kprintf("MTU: %d\n", netdev->mtu); /* 6 - MAC address, 8 - IEMI */ @@ -853,13 +889,13 @@ static void netdev_list_if(void) } else if (netdev->hwaddr_len == NETDEV_IFCONFIG_IEMI_MAX_LEN) { - rt_kprintf("IEMI: "); + rt_kprintf("IMEI: "); for (index = 0; index < netdev->hwaddr_len; index++) { /* two numbers are displayed at one time*/ if (netdev->hwaddr[index] < 10 && index != netdev->hwaddr_len - 1) rt_kprintf("0"); - + rt_kprintf("%d", netdev->hwaddr[index]); } } @@ -881,18 +917,38 @@ static void netdev_list_if(void) rt_kprintf("gw address: %s\n", inet_ntoa(netdev->gw)); rt_kprintf("net mask : %s\n", inet_ntoa(netdev->netmask)); +#if NETDEV_IPV6 + { + ip_addr_t *addr; + int i; + + addr = &netdev->ip6_addr[0]; + + if (!ip_addr_isany(addr)) + { + rt_kprintf("ipv6 link-local: %s %s\n", inet_ntoa(*addr), + !ip_addr_isany(addr) ? "VALID" : "INVALID"); + + for (i = 1; i < NETDEV_IPV6_NUM_ADDRESSES; i++) + { + addr = &netdev->ip6_addr[i]; + rt_kprintf("ipv6[%d] address: %s %s\n", i, inet_ntoa(*addr), + !ip_addr_isany(addr) ? "VALID" : "INVALID"); + } + } + } +#endif /* NETDEV_IPV6 */ + for (index = 0; index < NETDEV_DNS_SERVERS_NUM; index++) { rt_kprintf("dns server #%d: %s\n", index, inet_ntoa(netdev->dns_servers[index])); } - + if (rt_slist_next(node)) { rt_kprintf("\n"); } } - - rt_hw_interrupt_enable(level); } static void netdev_set_if(char* netdev_name, char* ip_addr, char* gw_addr, char* nm_addr) @@ -951,7 +1007,7 @@ FINSH_FUNCTION_EXPORT_ALIAS(netdev_ifconfig, __cmd_ifconfig, list the informatio #endif /* NETDEV_USING_IFCONFIG */ #ifdef NETDEV_USING_PING -static int netdev_cmd_ping(char* target_name, rt_uint32_t times, rt_size_t size) +int netdev_cmd_ping(char* target_name, rt_uint32_t times, rt_size_t size) { #define NETDEV_PING_DATA_SIZE 32 /** ping receive timeout - in milliseconds */ @@ -966,7 +1022,7 @@ static int netdev_cmd_ping(char* target_name, rt_uint32_t times, rt_size_t size) struct netdev *netdev = RT_NULL; struct netdev_ping_resp ping_resp; int index, ret = 0; - + if (size == 0) { size = NETDEV_PING_DATA_SIZE; @@ -981,20 +1037,34 @@ static int netdev_cmd_ping(char* target_name, rt_uint32_t times, rt_size_t size) { /* using first internet up status network interface device */ netdev = netdev_get_first_by_flags(NETDEV_FLAG_LINK_UP); - if (netdev == RT_NULL || NETDEV_PING_IS_COMMONICABLE(netdev) == 0) + if (netdev == RT_NULL) + { + rt_kprintf("ping: not found available network interface device.\n"); + return -RT_ERROR; + } + else if (netdev->ops == RT_NULL || netdev->ops->ping == RT_NULL) + { + rt_kprintf("ping: network interface device(%s) not support ping feature.\n", netdev->name); + return -RT_ERROR; + } + else if (!netdev_is_up(netdev) || !netdev_is_link_up(netdev)) { - rt_kprintf("ping: network interface device get error.\n"); + rt_kprintf("ping: network interface device(%s) status error.\n", netdev->name); return -RT_ERROR; } } for (index = 0; index < times; index++) { + int delay_tick = 0; + rt_tick_t start_tick = 0; + rt_memset(&ping_resp, 0x00, sizeof(struct netdev_ping_resp)); + start_tick = rt_tick_get(); ret = netdev->ops->ping(netdev, (const char *)target_name, size, NETDEV_PING_RECV_TIMEO, &ping_resp); if (ret == -RT_ETIMEOUT) { - rt_kprintf("ping: from %s icmp_seq=%d timeout\n", + rt_kprintf("ping: from %s icmp_seq=%d timeout\n", (ip_addr_isany(&(ping_resp.ip_addr))) ? target_name : inet_ntoa(ping_resp.ip_addr), index); } else if (ret == -RT_ERROR) @@ -1007,17 +1077,19 @@ static int netdev_cmd_ping(char* target_name, rt_uint32_t times, rt_size_t size) { if (ping_resp.ttl == 0) { - rt_kprintf("%d bytes from %s icmp_seq=%d time=%d ms\n", + rt_kprintf("%d bytes from %s icmp_seq=%d time=%d ms\n", ping_resp.data_len, inet_ntoa(ping_resp.ip_addr), index, ping_resp.ticks); } else { - rt_kprintf("%d bytes from %s icmp_seq=%d ttl=%d time=%d ms\n", + rt_kprintf("%d bytes from %s icmp_seq=%d ttl=%d time=%d ms\n", ping_resp.data_len, inet_ntoa(ping_resp.ip_addr), index, ping_resp.ttl, ping_resp.ticks); } } - - rt_thread_mdelay(NETDEV_PING_DELAY); + + /* if the response time is more than NETDEV_PING_DELAY, no nead to delay */ + delay_tick = ((rt_tick_get() - start_tick) > NETDEV_PING_DELAY) || (index == times) ? 0 : NETDEV_PING_DELAY; + rt_thread_delay(delay_tick); } return RT_EOK; @@ -1041,33 +1113,28 @@ FINSH_FUNCTION_EXPORT_ALIAS(netdev_ping, __cmd_ping, ping network host); static void netdev_list_dns(void) { - rt_base_t level; int index = 0; struct netdev *netdev = RT_NULL; rt_slist_t *node = RT_NULL; - level = rt_hw_interrupt_disable(); - for (node = &(netdev_list->list); node; node = rt_slist_next(node)) { netdev = rt_list_entry(node, struct netdev, list); - rt_kprintf("network interface device: %s%s\n", - netdev->name, + rt_kprintf("network interface device: %.*s%s\n", + RT_NAME_MAX, netdev->name, (netdev == netdev_default)?" (Default)":""); for(index = 0; index < NETDEV_DNS_SERVERS_NUM; index++) { rt_kprintf("dns server #%d: %s\n", index, inet_ntoa(netdev->dns_servers[index])); } - + if (rt_slist_next(node)) { rt_kprintf("\n"); } } - - rt_hw_interrupt_enable(level); } static void netdev_set_dns(char *netdev_name, uint8_t dns_num, char *dns_server) @@ -1083,9 +1150,10 @@ static void netdev_set_dns(char *netdev_name, uint8_t dns_num, char *dns_server) } inet_aton(dns_server, &dns_addr); - netdev_set_dns_server(netdev, dns_num, &dns_addr); - - rt_kprintf("set network interface device(%s) dns server #0: %s\n", netdev_name, dns_server); + if (netdev_set_dns_server(netdev, dns_num, &dns_addr) == RT_EOK) + { + rt_kprintf("set network interface device(%s) dns server #%d: %s\n", netdev_name, dns_num, dns_server); + } } int netdev_dns(int argc, char **argv) @@ -1115,7 +1183,6 @@ FINSH_FUNCTION_EXPORT_ALIAS(netdev_dns, __cmd_dns, list and set the information #ifdef NETDEV_USING_NETSTAT static void netdev_cmd_netstat(void) { - rt_base_t level; rt_slist_t *node = RT_NULL; struct netdev *netdev = RT_NULL; struct netdev *cur_netdev_list = netdev_list; @@ -1126,8 +1193,6 @@ static void netdev_cmd_netstat(void) return; } - level = rt_hw_interrupt_disable(); - for (node = &(cur_netdev_list->list); node; node = rt_slist_next(node)) { netdev = rt_list_entry(node, struct netdev, list); @@ -1138,9 +1203,14 @@ static void netdev_cmd_netstat(void) } } - rt_hw_interrupt_enable(level); - - netdev->ops->netstat(netdev); + if (netdev->ops->netstat != RT_NULL) + { + netdev->ops->netstat(netdev); + } + else + { + rt_kprintf("netstat: this command is not supported!\n"); + } } int netdev_netstat(int argc, char **argv) @@ -1149,7 +1219,7 @@ int netdev_netstat(int argc, char **argv) { rt_kprintf("Please input: netstat \n"); } - else + else { netdev_cmd_netstat(); } @@ -1159,4 +1229,4 @@ int netdev_netstat(int argc, char **argv) FINSH_FUNCTION_EXPORT_ALIAS(netdev_netstat, __cmd_netstat, list the information of TCP / IP); #endif /* NETDEV_USING_NETSTAT */ -#endif /* FINSH_USING_MSH */ +#endif /* RT_USING_FINSH */ diff --git a/components/net/netdev/src/netdev_ipaddr.c b/components/net/netdev/src/netdev_ipaddr.c index 988bd50eb7..8d83937da9 100644 --- a/components/net/netdev/src/netdev_ipaddr.c +++ b/components/net/netdev/src/netdev_ipaddr.c @@ -19,8 +19,10 @@ #define isxdigit(c) (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F')) #define islower(c) in_range(c, 'a', 'z') #define isspace(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v') +#define xchar(i) ((i) < 10 ? '0' + (i) : 'A' + (i) - 10) #endif +#if NETDEV_IPV4 /** * Check whether "cp" is a valid ascii representation @@ -255,3 +257,358 @@ in_addr_t netdev_ipaddr_addr(const char *cp) } return (IPADDR_NONE); } + +#endif /* NETDEV_IPV4 */ + + +#if NETDEV_IPV6 + +RT_WEAK const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; + +/** + * Check whether "cp" is a valid ascii representation + * of an IPv6 address and convert to a binary address. + * Returns 1 if the address is valid, 0 if not. + * + * @param cp IPv6 address in ascii representation (e.g. "FF01::1") + * @param addr pointer to which to save the ip address in network order + * @return 1 if cp could be converted to addr, 0 on failure + */ +int +netdev_ip6addr_aton(const char *cp, ip6_addr_t *addr) +{ + uint32_t addr_index, zero_blocks, current_block_index, current_block_value; + const char *s; + + /* Count the number of colons, to count the number of blocks in a "::" sequence + zero_blocks may be 1 even if there are no :: sequences */ + zero_blocks = 8; + for (s = cp; *s != 0; s++) + { + if (*s == ':') + { + zero_blocks--; + } + else if (!isxdigit(*s)) + { + break; + } + } + + /* parse each block */ + addr_index = 0; + current_block_index = 0; + current_block_value = 0; + for (s = cp; *s != 0; s++) + { + if (*s == ':') + { + if (addr) + { + if (current_block_index & 0x1) + { + addr->addr[addr_index++] |= current_block_value; + } + else + { + addr->addr[addr_index] = current_block_value << 16; + } + } + current_block_index++; + current_block_value = 0; + if (current_block_index > 7) + { + /* address too long! */ + return 0; + } + if (s[1] == ':') + { + if (s[2] == ':') + { + /* invalid format: three successive colons */ + return 0; + } + s++; + /* "::" found, set zeros */ + while (zero_blocks > 0) + { + zero_blocks--; + if (current_block_index & 0x1) + { + addr_index++; + } + else + { + if (addr) + { + addr->addr[addr_index] = 0; + } + } + current_block_index++; + if (current_block_index > 7) + { + /* address too long! */ + return 0; + } + } + } + } + else if (isxdigit(*s)) + { + /* add current digit */ + current_block_value = (current_block_value << 4) + + (isdigit(*s) ? (uint32_t)(*s - '0') : (uint32_t)(10 + (islower(*s) ? *s - 'a' : *s - 'A'))); + } + else + { + /* unexpected digit, space? CRLF? */ + break; + } + } + + if (addr) + { + if (current_block_index & 0x1) + { + addr->addr[addr_index++] |= current_block_value; + } + else + { + addr->addr[addr_index] = current_block_value << 16; + } + } + + /* convert to network byte order. */ + if (addr) + { + for (addr_index = 0; addr_index < 4; addr_index++) + { + addr->addr[addr_index] = htonl(addr->addr[addr_index]); + } + } + + if (current_block_index != 7) + { + return 0; + } + + return 1; +} + +/** + * Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used. + * + * @param addr ip6 address in network order to convert + * @param buf target buffer where the string is stored + * @param buflen length of buf + * @return either pointer to buf which now holds the ASCII + * representation of addr or NULL if buf was too small + */ +char * +netdev_ip6addr_ntoa_r(const ip6_addr_t *addr, char *buf, int buflen) +{ + uint32_t current_block_index, current_block_value, next_block_value; + int32_t i; + uint8_t zero_flag, empty_block_flag; + + i = 0; + empty_block_flag = 0; /* used to indicate a zero chain for "::' */ + + for (current_block_index = 0; current_block_index < 8; current_block_index++) + { + /* get the current 16-bit block */ + current_block_value = htonl(addr->addr[current_block_index >> 1]); + if ((current_block_index & 0x1) == 0) + { + current_block_value = current_block_value >> 16; + } + current_block_value &= 0xffff; + + /* Check for empty block. */ + if (current_block_value == 0) + { + if (current_block_index == 7 && empty_block_flag == 1) + { + /* special case, we must render a ':' for the last block. */ + buf[i++] = ':'; + if (i >= buflen) + { + return NULL; + } + break; + } + if (empty_block_flag == 0) + { + /* generate empty block "::", but only if more than one contiguous zero block, + * according to current formatting suggestions RFC 5952. */ + next_block_value = htonl(addr->addr[(current_block_index + 1) >> 1]); + if ((current_block_index & 0x1) == 0x01) + { + next_block_value = next_block_value >> 16; + } + next_block_value &= 0xffff; + if (next_block_value == 0) + { + empty_block_flag = 1; + buf[i++] = ':'; + if (i >= buflen) + { + return NULL; + } + continue; /* move on to next block. */ + } + } + else if (empty_block_flag == 1) + { + /* move on to next block. */ + continue; + } + } + else if (empty_block_flag == 1) + { + /* Set this flag value so we don't produce multiple empty blocks. */ + empty_block_flag = 2; + } + + if (current_block_index > 0) + { + buf[i++] = ':'; + if (i >= buflen) + { + return NULL; + } + } + + if ((current_block_value & 0xf000) == 0) + { + zero_flag = 1; + } + else + { + buf[i++] = xchar(((current_block_value & 0xf000) >> 12)); + zero_flag = 0; + if (i >= buflen) + { + return NULL; + } + } + + if (((current_block_value & 0xf00) == 0) && (zero_flag)) + { + /* do nothing */ + } + else + { + buf[i++] = xchar(((current_block_value & 0xf00) >> 8)); + zero_flag = 0; + if (i >= buflen) + { + return NULL; + } + } + + if (((current_block_value & 0xf0) == 0) && (zero_flag)) + { + /* do nothing */ + } + else + { + buf[i++] = xchar(((current_block_value & 0xf0) >> 4)); + zero_flag = 0; + if (i >= buflen) + { + return NULL; + } + } + + buf[i++] = xchar((current_block_value & 0xf)); + if (i >= buflen) + { + return NULL; + } + } + + buf[i] = 0; + + return buf; +} + +/** + * Convert numeric IPv6 address into ASCII representation. + * returns ptr to static buffer; not reentrant! + * + * @param addr ip6 address in network order to convert + * @return pointer to a global static (!) buffer that holds the ASCII + * representation of addr + */ +char * +netdev_ip6addr_ntoa(const ip6_addr_t *addr) +{ + static char str[40]; + return netdev_ip6addr_ntoa_r(addr, str, 40); +} + +#endif /* NETDEV_IPV6 */ + +const char * +netdev_inet_ntop(int af, const void *src, char *dst, int32_t size) +{ +#define AF_INET 2 +#define AF_INET6 10 + + const char *ret = NULL; + int size_int = (int)size; + if (size_int < 0) + { + return NULL; + } + switch (af) + { +#if NTEDEV_IPV4 + case AF_INET: + return netdev_ip4addr_ntoa_r((const ip4_addr_t *)src, dst, size_int); +#endif +#if NETDEV_IPV6 + case AF_INET6: + return netdev_ip6addr_ntoa_r((const ip6_addr_t *)src, dst, size_int); +#endif + default: + break; + } + return ret; +} + +int +netdev_inet_pton(int af, const char *src, void *dst) +{ +#define AF_INET 2 +#define AF_INET6 10 + + int err; + switch (af) + { +#if NETDEV_IPV4 + case AF_INET: + err = netdev_ip4addr_aton(src, (ip4_addr_t *)dst); + break; +#endif +#if NETDEV_IPV6 + case AF_INET6: + { + /* convert into temporary variable since ip6_addr_t might be larger + than in6_addr when scopes are enabled */ + ip6_addr_t addr; + err = netdev_ip6addr_aton(src, &addr); + if (err) + { + rt_memcpy(dst, &addr.addr, sizeof(addr.addr)); + } + break; + } +#endif + default: + err = -1; + break; + } + return err; +} |
