initramfs: fix initramfs size calculation
[linux-drm-fsl-dcu.git] / net / sunrpc / addr.c
1 /*
2  * Copyright 2009, Oracle.  All rights reserved.
3  *
4  * Convert socket addresses to presentation addresses and universal
5  * addresses, and vice versa.
6  *
7  * Universal addresses are introduced by RFC 1833 and further refined by
8  * recent RFCs describing NFSv4.  The universal address format is part
9  * of the external (network) interface provided by rpcbind version 3
10  * and 4, and by NFSv4.  Such an address is a string containing a
11  * presentation format IP address followed by a port number in
12  * "hibyte.lobyte" format.
13  *
14  * IPv6 addresses can also include a scope ID, typically denoted by
15  * a '%' followed by a device name or a non-negative integer.  Refer to
16  * RFC 4291, Section 2.2 for details on IPv6 presentation formats.
17  */
18
19 #include <net/ipv6.h>
20 #include <linux/sunrpc/clnt.h>
21 #include <linux/slab.h>
22
23 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
24
25 static size_t rpc_ntop6_noscopeid(const struct sockaddr *sap,
26                                   char *buf, const int buflen)
27 {
28         const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
29         const struct in6_addr *addr = &sin6->sin6_addr;
30
31         /*
32          * RFC 4291, Section 2.2.2
33          *
34          * Shorthanded ANY address
35          */
36         if (ipv6_addr_any(addr))
37                 return snprintf(buf, buflen, "::");
38
39         /*
40          * RFC 4291, Section 2.2.2
41          *
42          * Shorthanded loopback address
43          */
44         if (ipv6_addr_loopback(addr))
45                 return snprintf(buf, buflen, "::1");
46
47         /*
48          * RFC 4291, Section 2.2.3
49          *
50          * Special presentation address format for mapped v4
51          * addresses.
52          */
53         if (ipv6_addr_v4mapped(addr))
54                 return snprintf(buf, buflen, "::ffff:%pI4",
55                                         &addr->s6_addr32[3]);
56
57         /*
58          * RFC 4291, Section 2.2.1
59          */
60         return snprintf(buf, buflen, "%pI6c", addr);
61 }
62
63 static size_t rpc_ntop6(const struct sockaddr *sap,
64                         char *buf, const size_t buflen)
65 {
66         const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
67         char scopebuf[IPV6_SCOPE_ID_LEN];
68         size_t len;
69         int rc;
70
71         len = rpc_ntop6_noscopeid(sap, buf, buflen);
72         if (unlikely(len == 0))
73                 return len;
74
75         if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL))
76                 return len;
77         if (sin6->sin6_scope_id == 0)
78                 return len;
79
80         rc = snprintf(scopebuf, sizeof(scopebuf), "%c%u",
81                         IPV6_SCOPE_DELIMITER, sin6->sin6_scope_id);
82         if (unlikely((size_t)rc > sizeof(scopebuf)))
83                 return 0;
84
85         len += rc;
86         if (unlikely(len > buflen))
87                 return 0;
88
89         strcat(buf, scopebuf);
90         return len;
91 }
92
93 #else   /* !(defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)) */
94
95 static size_t rpc_ntop6_noscopeid(const struct sockaddr *sap,
96                                   char *buf, const int buflen)
97 {
98         return 0;
99 }
100
101 static size_t rpc_ntop6(const struct sockaddr *sap,
102                         char *buf, const size_t buflen)
103 {
104         return 0;
105 }
106
107 #endif  /* !(defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)) */
108
109 static int rpc_ntop4(const struct sockaddr *sap,
110                      char *buf, const size_t buflen)
111 {
112         const struct sockaddr_in *sin = (struct sockaddr_in *)sap;
113
114         return snprintf(buf, buflen, "%pI4", &sin->sin_addr);
115 }
116
117 /**
118  * rpc_ntop - construct a presentation address in @buf
119  * @sap: socket address
120  * @buf: construction area
121  * @buflen: size of @buf, in bytes
122  *
123  * Plants a %NUL-terminated string in @buf and returns the length
124  * of the string, excluding the %NUL.  Otherwise zero is returned.
125  */
126 size_t rpc_ntop(const struct sockaddr *sap, char *buf, const size_t buflen)
127 {
128         switch (sap->sa_family) {
129         case AF_INET:
130                 return rpc_ntop4(sap, buf, buflen);
131         case AF_INET6:
132                 return rpc_ntop6(sap, buf, buflen);
133         }
134
135         return 0;
136 }
137 EXPORT_SYMBOL_GPL(rpc_ntop);
138
139 static size_t rpc_pton4(const char *buf, const size_t buflen,
140                         struct sockaddr *sap, const size_t salen)
141 {
142         struct sockaddr_in *sin = (struct sockaddr_in *)sap;
143         u8 *addr = (u8 *)&sin->sin_addr.s_addr;
144
145         if (buflen > INET_ADDRSTRLEN || salen < sizeof(struct sockaddr_in))
146                 return 0;
147
148         memset(sap, 0, sizeof(struct sockaddr_in));
149
150         if (in4_pton(buf, buflen, addr, '\0', NULL) == 0)
151                 return 0;
152
153         sin->sin_family = AF_INET;
154         return sizeof(struct sockaddr_in);;
155 }
156
157 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
158 static int rpc_parse_scope_id(const char *buf, const size_t buflen,
159                               const char *delim, struct sockaddr_in6 *sin6)
160 {
161         char *p;
162         size_t len;
163
164         if ((buf + buflen) == delim)
165                 return 1;
166
167         if (*delim != IPV6_SCOPE_DELIMITER)
168                 return 0;
169
170         if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL))
171                 return 0;
172
173         len = (buf + buflen) - delim - 1;
174         p = kstrndup(delim + 1, len, GFP_KERNEL);
175         if (p) {
176                 unsigned long scope_id = 0;
177                 struct net_device *dev;
178
179                 dev = dev_get_by_name(&init_net, p);
180                 if (dev != NULL) {
181                         scope_id = dev->ifindex;
182                         dev_put(dev);
183                 } else {
184                         if (strict_strtoul(p, 10, &scope_id) == 0) {
185                                 kfree(p);
186                                 return 0;
187                         }
188                 }
189
190                 kfree(p);
191
192                 sin6->sin6_scope_id = scope_id;
193                 return 1;
194         }
195
196         return 0;
197 }
198
199 static size_t rpc_pton6(const char *buf, const size_t buflen,
200                         struct sockaddr *sap, const size_t salen)
201 {
202         struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
203         u8 *addr = (u8 *)&sin6->sin6_addr.in6_u;
204         const char *delim;
205
206         if (buflen > (INET6_ADDRSTRLEN + IPV6_SCOPE_ID_LEN) ||
207             salen < sizeof(struct sockaddr_in6))
208                 return 0;
209
210         memset(sap, 0, sizeof(struct sockaddr_in6));
211
212         if (in6_pton(buf, buflen, addr, IPV6_SCOPE_DELIMITER, &delim) == 0)
213                 return 0;
214
215         if (!rpc_parse_scope_id(buf, buflen, delim, sin6))
216                 return 0;
217
218         sin6->sin6_family = AF_INET6;
219         return sizeof(struct sockaddr_in6);
220 }
221 #else
222 static size_t rpc_pton6(const char *buf, const size_t buflen,
223                         struct sockaddr *sap, const size_t salen)
224 {
225         return 0;
226 }
227 #endif
228
229 /**
230  * rpc_pton - Construct a sockaddr in @sap
231  * @buf: C string containing presentation format IP address
232  * @buflen: length of presentation address in bytes
233  * @sap: buffer into which to plant socket address
234  * @salen: size of buffer in bytes
235  *
236  * Returns the size of the socket address if successful; otherwise
237  * zero is returned.
238  *
239  * Plants a socket address in @sap and returns the size of the
240  * socket address, if successful.  Returns zero if an error
241  * occurred.
242  */
243 size_t rpc_pton(const char *buf, const size_t buflen,
244                 struct sockaddr *sap, const size_t salen)
245 {
246         unsigned int i;
247
248         for (i = 0; i < buflen; i++)
249                 if (buf[i] == ':')
250                         return rpc_pton6(buf, buflen, sap, salen);
251         return rpc_pton4(buf, buflen, sap, salen);
252 }
253 EXPORT_SYMBOL_GPL(rpc_pton);
254
255 /**
256  * rpc_sockaddr2uaddr - Construct a universal address string from @sap.
257  * @sap: socket address
258  *
259  * Returns a %NUL-terminated string in dynamically allocated memory;
260  * otherwise NULL is returned if an error occurred.  Caller must
261  * free the returned string.
262  */
263 char *rpc_sockaddr2uaddr(const struct sockaddr *sap)
264 {
265         char portbuf[RPCBIND_MAXUADDRPLEN];
266         char addrbuf[RPCBIND_MAXUADDRLEN];
267         unsigned short port;
268
269         switch (sap->sa_family) {
270         case AF_INET:
271                 if (rpc_ntop4(sap, addrbuf, sizeof(addrbuf)) == 0)
272                         return NULL;
273                 port = ntohs(((struct sockaddr_in *)sap)->sin_port);
274                 break;
275         case AF_INET6:
276                 if (rpc_ntop6_noscopeid(sap, addrbuf, sizeof(addrbuf)) == 0)
277                         return NULL;
278                 port = ntohs(((struct sockaddr_in6 *)sap)->sin6_port);
279                 break;
280         default:
281                 return NULL;
282         }
283
284         if (snprintf(portbuf, sizeof(portbuf),
285                      ".%u.%u", port >> 8, port & 0xff) > (int)sizeof(portbuf))
286                 return NULL;
287
288         if (strlcat(addrbuf, portbuf, sizeof(addrbuf)) > sizeof(addrbuf))
289                 return NULL;
290
291         return kstrdup(addrbuf, GFP_KERNEL);
292 }
293 EXPORT_SYMBOL_GPL(rpc_sockaddr2uaddr);
294
295 /**
296  * rpc_uaddr2sockaddr - convert a universal address to a socket address.
297  * @uaddr: C string containing universal address to convert
298  * @uaddr_len: length of universal address string
299  * @sap: buffer into which to plant socket address
300  * @salen: size of buffer
301  *
302  * @uaddr does not have to be '\0'-terminated, but strict_strtoul() and
303  * rpc_pton() require proper string termination to be successful.
304  *
305  * Returns the size of the socket address if successful; otherwise
306  * zero is returned.
307  */
308 size_t rpc_uaddr2sockaddr(const char *uaddr, const size_t uaddr_len,
309                           struct sockaddr *sap, const size_t salen)
310 {
311         char *c, buf[RPCBIND_MAXUADDRLEN + sizeof('\0')];
312         unsigned long portlo, porthi;
313         unsigned short port;
314
315         if (uaddr_len > RPCBIND_MAXUADDRLEN)
316                 return 0;
317
318         memcpy(buf, uaddr, uaddr_len);
319
320         buf[uaddr_len] = '\0';
321         c = strrchr(buf, '.');
322         if (unlikely(c == NULL))
323                 return 0;
324         if (unlikely(strict_strtoul(c + 1, 10, &portlo) != 0))
325                 return 0;
326         if (unlikely(portlo > 255))
327                 return 0;
328
329         *c = '\0';
330         c = strrchr(buf, '.');
331         if (unlikely(c == NULL))
332                 return 0;
333         if (unlikely(strict_strtoul(c + 1, 10, &porthi) != 0))
334                 return 0;
335         if (unlikely(porthi > 255))
336                 return 0;
337
338         port = (unsigned short)((porthi << 8) | portlo);
339
340         *c = '\0';
341         if (rpc_pton(buf, strlen(buf), sap, salen) == 0)
342                 return 0;
343
344         switch (sap->sa_family) {
345         case AF_INET:
346                 ((struct sockaddr_in *)sap)->sin_port = htons(port);
347                 return sizeof(struct sockaddr_in);
348         case AF_INET6:
349                 ((struct sockaddr_in6 *)sap)->sin6_port = htons(port);
350                 return sizeof(struct sockaddr_in6);
351         }
352
353         return 0;
354 }
355 EXPORT_SYMBOL_GPL(rpc_uaddr2sockaddr);