1 /**
2  * @file net/if.c  Network interface code
3  *
4  * Copyright (C) 2010 Creytiv.com
5  */
6 #include <re_types.h>
7 #include <re_fmt.h>
8 #include <re_mbuf.h>
9 #include <re_sa.h>
10 #include <re_net.h>
11 
12 
13 #define DEBUG_MODULE "netif"
14 #define DEBUG_LEVEL 5
15 #include <re_dbg.h>
16 
17 
18 /** Interface address entry */
19 struct ifentry {
20 	int af;        /**< Address family */
21 	char *ifname;  /**< Interface name */
22 	struct sa *ip; /**< IP address     */
23 	size_t sz;     /**< Size of buffer */
24 	bool found;    /**< Found flag     */
25 };
26 
27 
if_getname_handler(const char * ifname,const struct sa * sa,void * arg)28 static bool if_getname_handler(const char *ifname, const struct sa *sa,
29 			       void *arg)
30 {
31 	struct ifentry *ife = arg;
32 
33 	if (ife->af != sa_af(sa))
34 		return false;
35 
36 	if (0 == sa_cmp(sa, ife->ip, SA_ADDR)) {
37 		str_ncpy(ife->ifname, ifname, ife->sz);
38 		ife->found = true;
39 		return true;
40 	}
41 
42 	return false;
43 }
44 
45 
46 /**
47  * Get the name of the interface for a given IP address
48  *
49  * @param ifname Buffer for returned network interface name
50  * @param sz     Size of buffer
51  * @param af     Address Family
52  * @param ip     Given IP address
53  *
54  * @return 0 if success, otherwise errorcode
55  */
net_if_getname(char * ifname,size_t sz,int af,const struct sa * ip)56 int net_if_getname(char *ifname, size_t sz, int af, const struct sa *ip)
57 {
58 	struct ifentry ife;
59 	int err;
60 
61 	if (!ifname || !sz || !ip)
62 		return EINVAL;
63 
64 	ife.af     = af;
65 	ife.ifname = ifname;
66 	ife.ip     = (struct sa *)ip;
67 	ife.sz     = sz;
68 	ife.found  = false;
69 
70 	err = net_if_list(if_getname_handler, &ife);
71 
72 	return ife.found ? err : ENODEV;
73 }
74 
75 
if_getaddr_handler(const char * ifname,const struct sa * sa,void * arg)76 static bool if_getaddr_handler(const char *ifname,
77 			       const struct sa *sa, void *arg)
78 {
79 	struct ifentry *ife = arg;
80 
81 	/* Match name of interface? */
82 	if (str_isset(ife->ifname) && 0 != str_casecmp(ife->ifname, ifname))
83 		return false;
84 
85 	if (!sa_isset(sa, SA_ADDR))
86 		return false;
87 
88 #if 1
89 	/* skip loopback and link-local IP */
90 	if (sa_is_loopback(sa) || sa_is_linklocal(sa))
91 		return false;
92 #endif
93 
94 	/* Match address family */
95 	if (ife->af != sa_af(sa))
96 		return false;
97 
98 	/* Match - copy address */
99 	sa_cpy(ife->ip, sa);
100 	ife->found = true;
101 
102 	return ife->found;
103 }
104 
105 
106 /**
107  * Get IP address for a given network interface
108  *
109  * @param ifname  Network interface name (optional)
110  * @param af      Address Family
111  * @param ip      Returned IP address
112  *
113  * @return 0 if success, otherwise errorcode
114  *
115  * @deprecated Works for IPv4 only
116  */
net_if_getaddr(const char * ifname,int af,struct sa * ip)117 int net_if_getaddr(const char *ifname, int af, struct sa *ip)
118 {
119 	struct ifentry ife;
120 	int err;
121 
122 	if (!ip)
123 		return EINVAL;
124 
125 	ife.af     = af;
126 	ife.ifname = (char *)ifname;
127 	ife.ip     = ip;
128 	ife.sz     = 0;
129 	ife.found  = false;
130 
131 #ifdef HAVE_GETIFADDRS
132 	err = net_getifaddrs(if_getaddr_handler, &ife);
133 #else
134 	err = net_if_list(if_getaddr_handler, &ife);
135 #endif
136 
137 	return ife.found ? err : ENODEV;
138 }
139 
140 
if_debug_handler(const char * ifname,const struct sa * sa,void * arg)141 static bool if_debug_handler(const char *ifname, const struct sa *sa,
142 			     void *arg)
143 {
144 	struct re_printf *pf = arg;
145 
146 	(void)re_hprintf(pf, " %10s:  %j\n", ifname, sa);
147 
148 	return false;
149 }
150 
151 
152 /**
153  * Debug network interfaces
154  *
155  * @param pf     Print handler for debug output
156  * @param unused Unused parameter
157  *
158  * @return 0 if success, otherwise errorcode
159  */
net_if_debug(struct re_printf * pf,void * unused)160 int net_if_debug(struct re_printf *pf, void *unused)
161 {
162 	int err;
163 
164 	(void)unused;
165 
166 	err = re_hprintf(pf, "net interfaces:\n");
167 
168 #ifdef HAVE_GETIFADDRS
169 	err |= net_getifaddrs(if_debug_handler, pf);
170 #else
171 	err |= net_if_list(if_debug_handler, pf);
172 #endif
173 
174 	return err;
175 }
176 
177 
linklocal_handler(const char * ifname,const struct sa * sa,void * arg)178 static bool linklocal_handler(const char *ifname, const struct sa *sa,
179 			      void *arg)
180 {
181 	void **argv = arg;
182 	int af = *(int *)argv[1];
183 
184 	if (argv[0] && 0 != str_casecmp(argv[0], ifname))
185 		return false;
186 
187 	if (af != AF_UNSPEC && af != sa_af(sa))
188 		return false;
189 
190 	if (sa_is_linklocal(sa)) {
191 		*((struct sa *)argv[2]) = *sa;
192 		return true;
193 	}
194 
195 	return false;
196 }
197 
198 
199 /**
200  * Get the Link-local address for a specific network interface
201  *
202  * @param ifname Name of the interface
203  * @param af     Address family
204  * @param ip     Returned link-local address
205  *
206  * @return 0 if success, otherwise errorcode
207  */
net_if_getlinklocal(const char * ifname,int af,struct sa * ip)208 int net_if_getlinklocal(const char *ifname, int af, struct sa *ip)
209 {
210 	struct sa addr;
211 	void *argv[3];
212 	int err;
213 
214 	if (!ip)
215 		return EINVAL;
216 
217 	sa_init(&addr, sa_af(ip));
218 
219 	argv[0] = (void *)ifname;
220 	argv[1] = &af;
221 	argv[2] = &addr;
222 
223 	err = net_if_apply(linklocal_handler, argv);
224 	if (err)
225 		return err;
226 
227 	if (!sa_isset(&addr, SA_ADDR))
228 		return ENOENT;
229 
230 	*ip = addr;
231 
232 	return 0;
233 }
234