1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2014 Intel Corporation. 3 * Copyright (c) 2009, Olivier MATZ <[email protected]> 4 * All rights reserved. 5 */ 6 7 #include <stdio.h> 8 #include <stdlib.h> 9 #include <stdarg.h> 10 #include <inttypes.h> 11 #include <ctype.h> 12 #include <string.h> 13 #include <errno.h> 14 #include <arpa/inet.h> 15 #include <netinet/in.h> 16 #ifndef __linux__ 17 #ifndef __FreeBSD__ 18 #include <net/socket.h> 19 #else 20 #include <sys/socket.h> 21 #endif 22 #endif 23 24 #include <rte_string_fns.h> 25 26 #include "cmdline_parse.h" 27 #include "cmdline_parse_ipaddr.h" 28 29 struct cmdline_token_ops cmdline_token_ipaddr_ops = { 30 .parse = cmdline_parse_ipaddr, 31 .complete_get_nb = NULL, 32 .complete_get_elt = NULL, 33 .get_help = cmdline_get_help_ipaddr, 34 }; 35 36 #define PREFIXMAX 128 37 #define V4PREFIXMAX 32 38 39 int 40 cmdline_parse_ipaddr(cmdline_parse_token_hdr_t *tk, const char *buf, void *res, 41 unsigned ressize) 42 { 43 struct cmdline_token_ipaddr *tk2; 44 unsigned int token_len = 0; 45 char ip_str[INET6_ADDRSTRLEN+4+1]; /* '+4' is for prefixlen (if any) */ 46 cmdline_ipaddr_t ipaddr; 47 char *prefix, *prefix_end; 48 long prefixlen = 0; 49 50 if (res && ressize < sizeof(cmdline_ipaddr_t)) 51 return -1; 52 53 if (!buf || !tk || ! *buf) 54 return -1; 55 56 tk2 = (struct cmdline_token_ipaddr *)tk; 57 58 while (!cmdline_isendoftoken(buf[token_len])) 59 token_len++; 60 61 /* if token is too big... */ 62 if (token_len >= INET6_ADDRSTRLEN+4) 63 return -1; 64 65 strlcpy(ip_str, buf, token_len + 1); 66 67 /* convert the network prefix */ 68 if (tk2->ipaddr_data.flags & CMDLINE_IPADDR_NETWORK) { 69 prefix = strrchr(ip_str, '/'); 70 if (prefix == NULL) 71 return -1; 72 *prefix = '\0'; 73 prefix ++; 74 errno = 0; 75 prefixlen = strtol(prefix, &prefix_end, 10); 76 if (errno || (*prefix_end != '\0') 77 || prefixlen < 0 || prefixlen > PREFIXMAX) 78 return -1; 79 ipaddr.prefixlen = prefixlen; 80 } 81 else { 82 ipaddr.prefixlen = 0; 83 } 84 85 /* convert the IP addr */ 86 if ((tk2->ipaddr_data.flags & CMDLINE_IPADDR_V4) && 87 inet_pton(AF_INET, ip_str, &ipaddr.addr.ipv4) == 1 && 88 prefixlen <= V4PREFIXMAX) { 89 ipaddr.family = AF_INET; 90 if (res) 91 memcpy(res, &ipaddr, sizeof(ipaddr)); 92 return token_len; 93 } 94 if ((tk2->ipaddr_data.flags & CMDLINE_IPADDR_V6) && 95 inet_pton(AF_INET6, ip_str, &ipaddr.addr.ipv6) == 1) { 96 ipaddr.family = AF_INET6; 97 if (res) 98 memcpy(res, &ipaddr, sizeof(ipaddr)); 99 return token_len; 100 } 101 return -1; 102 103 } 104 105 int cmdline_get_help_ipaddr(cmdline_parse_token_hdr_t *tk, char *dstbuf, 106 unsigned int size) 107 { 108 struct cmdline_token_ipaddr *tk2; 109 110 if (!tk || !dstbuf) 111 return -1; 112 113 tk2 = (struct cmdline_token_ipaddr *)tk; 114 115 switch (tk2->ipaddr_data.flags) { 116 case CMDLINE_IPADDR_V4: 117 snprintf(dstbuf, size, "IPv4"); 118 break; 119 case CMDLINE_IPADDR_V6: 120 snprintf(dstbuf, size, "IPv6"); 121 break; 122 case CMDLINE_IPADDR_V4|CMDLINE_IPADDR_V6: 123 snprintf(dstbuf, size, "IPv4/IPv6"); 124 break; 125 case CMDLINE_IPADDR_NETWORK|CMDLINE_IPADDR_V4: 126 snprintf(dstbuf, size, "IPv4 network"); 127 break; 128 case CMDLINE_IPADDR_NETWORK|CMDLINE_IPADDR_V6: 129 snprintf(dstbuf, size, "IPv6 network"); 130 break; 131 case CMDLINE_IPADDR_NETWORK|CMDLINE_IPADDR_V4|CMDLINE_IPADDR_V6: 132 snprintf(dstbuf, size, "IPv4/IPv6 network"); 133 break; 134 default: 135 snprintf(dstbuf, size, "IPaddr (bad flags)"); 136 break; 137 } 138 return 0; 139 } 140