compat: Added support for SRP on RHEL7.5
[compat-rdma/compat.git] / include / linux / inet.h
1 #ifndef _COMPAT_LINUX_INET_H
2 #define _COMPAT_LINUX_INET_H
3
4 #include "../../compat/config.h"
5 #include <linux/version.h>
6
7 #include_next <linux/inet.h>
8
9 #if (defined(RHEL_MAJOR) && RHEL_MAJOR -0 == 7 && RHEL_MINOR -0 >= 2) || \
10         (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
11 #ifndef HAVE_INET_PTON_WITH_SCOPE
12
13 #include <net/net_namespace.h>
14 #include <linux/socket.h>
15 #include <net/ipv6.h>
16
17
18 static int inet4_pton(const char *src, u16 port_num,
19                 struct sockaddr_storage *addr)
20 {
21         struct sockaddr_in *addr4 = (struct sockaddr_in *)addr;
22         int srclen = strlen(src);
23
24         if (srclen > INET_ADDRSTRLEN)
25                 return -EINVAL;
26
27         if (in4_pton(src, srclen, (u8 *)&addr4->sin_addr.s_addr,
28                      '\n', NULL) == 0)
29                 return -EINVAL;
30
31         addr4->sin_family = AF_INET;
32         addr4->sin_port = htons(port_num);
33
34         return 0;
35 }
36
37 static int inet6_pton(struct net *net, const char *src, u16 port_num,
38                 struct sockaddr_storage *addr)
39 {
40         struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
41         const char *scope_delim;
42         int srclen = strlen(src);
43
44         if (srclen > INET6_ADDRSTRLEN)
45                 return -EINVAL;
46
47         if (in6_pton(src, srclen, (u8 *)&addr6->sin6_addr.s6_addr,
48                      '%', &scope_delim) == 0)
49                 return -EINVAL;
50
51         if (ipv6_addr_type(&addr6->sin6_addr) & IPV6_ADDR_LINKLOCAL &&
52             src + srclen != scope_delim && *scope_delim == '%') {
53                 struct net_device *dev;
54                 char scope_id[16];
55                 size_t scope_len = min_t(size_t, sizeof(scope_id) - 1,
56                                          src + srclen - scope_delim - 1);
57
58                 memcpy(scope_id, scope_delim + 1, scope_len);
59                 scope_id[scope_len] = '\0';
60
61                 dev = dev_get_by_name(net, scope_id);
62                 if (dev) {
63                         addr6->sin6_scope_id = dev->ifindex;
64                         dev_put(dev);
65                 } else if (kstrtouint(scope_id, 0, &addr6->sin6_scope_id)) {
66                         return -EINVAL;
67                 }
68         }
69
70         addr6->sin6_family = AF_INET6;
71         addr6->sin6_port = htons(port_num);
72
73         return 0;
74 }
75
76 /**
77  * inet_pton_with_scope - convert an IPv4/IPv6 and port to socket address
78  * @net: net namespace (used for scope handling)
79  * @af: address family, AF_INET, AF_INET6 or AF_UNSPEC for either
80  * @src: the start of the address string
81  * @port: the start of the port string (or NULL for none)
82  * @addr: output socket address
83  *
84  * Return zero on success, return errno when any error occurs.
85  */
86 static inline int inet_pton_with_scope(struct net *net, __kernel_sa_family_t af,
87                 const char *src, const char *port, struct sockaddr_storage *addr)
88 {
89         u16 port_num;
90         int ret = -EINVAL;
91
92         if (port) {
93                 if (kstrtou16(port, 0, &port_num))
94                         return -EINVAL;
95         } else {
96                 port_num = 0;
97         }
98
99         switch (af) {
100         case AF_INET:
101                 ret = inet4_pton(src, port_num, addr);
102                 break;
103         case AF_INET6:
104                 ret = inet6_pton(net, src, port_num, addr);
105                 break;
106         case AF_UNSPEC:
107                 ret = inet4_pton(src, port_num, addr);
108                 if (ret)
109                         ret = inet6_pton(net, src, port_num, addr);
110                 break;
111         default:
112                 pr_err("unexpected address family %d\n", af);
113         };
114
115         return ret;
116 }
117
118 #endif /* inet_pton_with_scope */
119
120 #endif
121
122 #endif /* _COMPAT_LINUX_INET_H */