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