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