xref: /haiku/src/kits/network/libnetapi/NetworkInterface.cpp (revision c90684742e7361651849be4116d0e5de3a817194)
1 /*
2  * Copyright 2010, Axel Dörfler, axeld@pinc-software.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <NetworkInterface.h>
8 
9 #include <errno.h>
10 #include <net/if.h>
11 #include <sys/sockio.h>
12 
13 #include <AutoDeleter.h>
14 
15 
16 static int
17 family_from_interface_address(const BNetworkInterfaceAddress& address)
18 {
19 	if (address.Address().Family() != AF_UNSPEC)
20 		return address.Address().Family();
21 	if (address.Mask().Family() != AF_UNSPEC)
22 		return address.Mask().Family();
23 	if (address.Destination().Family() != AF_UNSPEC)
24 		return address.Destination().Family();
25 
26 	return AF_INET;
27 }
28 
29 
30 static status_t
31 do_ifaliasreq(const char* name, int32 option, BNetworkInterfaceAddress& address,
32 	bool readBack = false)
33 {
34 	int family = AF_INET;
35 	if (!readBack)
36 		family = family_from_interface_address(address);
37 
38 	int socket = ::socket(family, SOCK_DGRAM, 0);
39 	if (socket < 0)
40 		return errno;
41 
42 	FileDescriptorCloser closer(socket);
43 
44 	ifaliasreq request;
45 	strlcpy(request.ifra_name, name, IF_NAMESIZE);
46 	request.ifra_index = address.Index();
47 	request.ifra_flags = address.Flags();
48 
49 	memcpy(&request.ifra_addr, &address.Address().SockAddr(),
50 		address.Address().Length());
51 	memcpy(&request.ifra_mask, &address.Mask().SockAddr(),
52 		address.Mask().Length());
53 	memcpy(&request.ifra_broadaddr, &address.Broadcast().SockAddr(),
54 		address.Broadcast().Length());
55 
56 	if (ioctl(socket, option, &request, sizeof(struct ifaliasreq)) < 0)
57 		return errno;
58 
59 	if (readBack) {
60 		address.SetFlags(request.ifra_flags);
61 		address.Address().SetTo(request.ifra_addr);
62 		address.Mask().SetTo(request.ifra_mask);
63 		address.Broadcast().SetTo(request.ifra_broadaddr);
64 	}
65 
66 	return B_OK;
67 }
68 
69 
70 static status_t
71 do_ifaliasreq(const char* name, int32 option,
72 	const BNetworkInterfaceAddress& address)
73 {
74 	return do_ifaliasreq(name, option,
75 		const_cast<BNetworkInterfaceAddress&>(address));
76 }
77 
78 
79 static status_t
80 do_request(int family, ifreq& request, const char* name, int option)
81 {
82 	int socket = ::socket(family, SOCK_DGRAM, 0);
83 	if (socket < 0)
84 		return errno;
85 
86 	FileDescriptorCloser closer(socket);
87 
88 	strlcpy(request.ifr_name, name, IF_NAMESIZE);
89 
90 	if (ioctl(socket, option, &request, sizeof(struct ifreq)) < 0)
91 		return errno;
92 
93 	return B_OK;
94 }
95 
96 
97 // #pragma mark -
98 
99 
100 BNetworkInterfaceAddress::BNetworkInterfaceAddress()
101 	:
102 	fIndex(-1),
103 	fFlags(0)
104 {
105 }
106 
107 
108 BNetworkInterfaceAddress::~BNetworkInterfaceAddress()
109 {
110 }
111 
112 
113 status_t
114 BNetworkInterfaceAddress::SetTo(const BNetworkInterface& interface, int32 index)
115 {
116 	fIndex = index;
117 	return do_ifaliasreq(interface.Name(), B_SOCKET_GET_ALIAS, *this, true);
118 }
119 
120 
121 void
122 BNetworkInterfaceAddress::SetAddress(const BNetworkAddress& address)
123 {
124 	fAddress = address;
125 }
126 
127 
128 void
129 BNetworkInterfaceAddress::SetMask(const BNetworkAddress& mask)
130 {
131 	fMask = mask;
132 }
133 
134 
135 void
136 BNetworkInterfaceAddress::SetBroadcast(const BNetworkAddress& broadcast)
137 {
138 	fBroadcast = broadcast;
139 }
140 
141 
142 void
143 BNetworkInterfaceAddress::SetDestination(const BNetworkAddress& destination)
144 {
145 	fBroadcast = destination;
146 }
147 
148 
149 void
150 BNetworkInterfaceAddress::SetFlags(uint32 flags)
151 {
152 	fFlags = flags;
153 }
154 
155 
156 // #pragma mark -
157 
158 
159 BNetworkInterface::BNetworkInterface()
160 {
161 	Unset();
162 }
163 
164 
165 BNetworkInterface::BNetworkInterface(const char* name)
166 {
167 	SetTo(name);
168 }
169 
170 
171 BNetworkInterface::BNetworkInterface(uint32 index)
172 {
173 	SetTo(index);
174 }
175 
176 
177 BNetworkInterface::~BNetworkInterface()
178 {
179 }
180 
181 
182 void
183 BNetworkInterface::Unset()
184 {
185 	fName[0] = '\0';
186 }
187 
188 
189 void
190 BNetworkInterface::SetTo(const char* name)
191 {
192 	strlcpy(fName, name, IF_NAMESIZE);
193 }
194 
195 
196 status_t
197 BNetworkInterface::SetTo(uint32 index)
198 {
199 	ifreq request;
200 	request.ifr_index = index;
201 
202 	status_t status = do_request(AF_INET, request, "", SIOCGIFNAME);
203 	if (status != B_OK)
204 		return status;
205 
206 	strlcpy(fName, request.ifr_name, IF_NAMESIZE);
207 	return B_OK;
208 }
209 
210 
211 bool
212 BNetworkInterface::Exists() const
213 {
214 	ifreq request;
215 	return do_request(AF_INET, request, Name(), SIOCGIFINDEX) == B_OK;
216 }
217 
218 
219 const char*
220 BNetworkInterface::Name() const
221 {
222 	return fName;
223 }
224 
225 
226 uint32
227 BNetworkInterface::Flags() const
228 {
229 	ifreq request;
230 	if (do_request(AF_INET, request, Name(), SIOCGIFFLAGS) != B_OK)
231 		return 0;
232 
233 	return request.ifr_flags;
234 }
235 
236 
237 uint32
238 BNetworkInterface::MTU() const
239 {
240 	ifreq request;
241 	if (do_request(AF_INET, request, Name(), SIOCGIFMTU) != B_OK)
242 		return 0;
243 
244 	return request.ifr_mtu;
245 }
246 
247 
248 int32
249 BNetworkInterface::Media() const
250 {
251 	ifreq request;
252 	if (do_request(AF_INET, request, Name(), SIOCGIFMEDIA) != B_OK)
253 		return -1;
254 
255 	return request.ifr_media;
256 }
257 
258 
259 uint32
260 BNetworkInterface::Metric() const
261 {
262 	ifreq request;
263 	if (do_request(AF_INET, request, Name(), SIOCGIFMETRIC) != B_OK)
264 		return 0;
265 
266 	return request.ifr_metric;
267 }
268 
269 
270 uint32
271 BNetworkInterface::Type() const
272 {
273 	ifreq request;
274 	if (do_request(AF_INET, request, Name(), SIOCGIFTYPE) != B_OK)
275 		return 0;
276 
277 	return request.ifr_type;
278 }
279 
280 
281 status_t
282 BNetworkInterface::GetStats(ifreq_stats& stats)
283 {
284 	ifreq request;
285 	status_t status = do_request(AF_INET, request, Name(), SIOCGIFSTATS);
286 	if (status != B_OK)
287 		return status;
288 
289 	memcpy(&stats, &request.ifr_stats, sizeof(ifreq_stats));
290 	return B_OK;
291 }
292 
293 
294 bool
295 BNetworkInterface::HasLink() const
296 {
297 	return (Flags() & IFF_LINK) != 0;
298 }
299 
300 
301 status_t
302 BNetworkInterface::SetFlags(uint32 flags)
303 {
304 	ifreq request;
305 	request.ifr_flags = flags;
306 	return do_request(AF_INET, request, Name(), SIOCSIFFLAGS);
307 }
308 
309 
310 status_t
311 BNetworkInterface::SetMTU(uint32 mtu)
312 {
313 	ifreq request;
314 	request.ifr_mtu = mtu;
315 	return do_request(AF_INET, request, Name(), SIOCSIFMTU);
316 }
317 
318 
319 status_t
320 BNetworkInterface::SetMedia(int32 media)
321 {
322 	ifreq request;
323 	request.ifr_media = media;
324 	return do_request(AF_INET, request, Name(), SIOCSIFMEDIA);
325 }
326 
327 
328 status_t
329 BNetworkInterface::SetMetric(uint32 metric)
330 {
331 	ifreq request;
332 	request.ifr_metric = metric;
333 	return do_request(AF_INET, request, Name(), SIOCSIFMETRIC);
334 }
335 
336 
337 int32
338 BNetworkInterface::CountAddresses() const
339 {
340 	ifreq request;
341 	if (do_request(AF_INET, request, Name(), B_SOCKET_COUNT_ALIASES) != B_OK)
342 		return 0;
343 
344 	return request.ifr_count;
345 }
346 
347 
348 status_t
349 BNetworkInterface::GetAddressAt(int32 index, BNetworkInterfaceAddress& address)
350 {
351 	return address.SetTo(*this, index);
352 }
353 
354 
355 int32
356 BNetworkInterface::FindAddress(const BNetworkAddress& address)
357 {
358 	int socket = ::socket(address.Family(), SOCK_DGRAM, 0);
359 	if (socket < 0)
360 		return errno;
361 
362 	FileDescriptorCloser closer(socket);
363 
364 	ifaliasreq request;
365 	memset(&request, 0, sizeof(ifaliasreq));
366 
367 	strlcpy(request.ifra_name, Name(), IF_NAMESIZE);
368 	request.ifra_index = -1;
369 	memcpy(&request.ifra_addr, &address.SockAddr(), address.Length());
370 
371 	if (ioctl(socket, B_SOCKET_GET_ALIAS, &request, sizeof(struct ifaliasreq))
372 			< 0)
373 		return errno;
374 
375 	return request.ifra_index;
376 }
377 
378 
379 int32
380 BNetworkInterface::FindFirstAddress(int family)
381 {
382 	int socket = ::socket(family, SOCK_DGRAM, 0);
383 	if (socket < 0)
384 		return errno;
385 
386 	FileDescriptorCloser closer(socket);
387 
388 	ifaliasreq request;
389 	memset(&request, 0, sizeof(ifaliasreq));
390 
391 	strlcpy(request.ifra_name, Name(), IF_NAMESIZE);
392 	request.ifra_index = -1;
393 	request.ifra_addr.ss_family = AF_UNSPEC;
394 
395 	if (ioctl(socket, B_SOCKET_GET_ALIAS, &request, sizeof(struct ifaliasreq))
396 			< 0)
397 		return errno;
398 
399 	return request.ifra_index;
400 }
401 
402 
403 status_t
404 BNetworkInterface::AddAddress(const BNetworkInterfaceAddress& address)
405 {
406 	return do_ifaliasreq(Name(), B_SOCKET_ADD_ALIAS, address);
407 }
408 
409 
410 status_t
411 BNetworkInterface::AddAddress(const BNetworkAddress& local)
412 {
413 	BNetworkInterfaceAddress address;
414 	address.SetAddress(local);
415 
416 	return do_ifaliasreq(Name(), B_SOCKET_ADD_ALIAS, address);
417 }
418 
419 
420 status_t
421 BNetworkInterface::SetAddress(const BNetworkInterfaceAddress& address)
422 {
423 	return do_ifaliasreq(Name(), B_SOCKET_SET_ALIAS, address);
424 }
425 
426 
427 status_t
428 BNetworkInterface::RemoveAddress(const BNetworkInterfaceAddress& address)
429 {
430 	ifreq request;
431 	memcpy(&request.ifr_addr, &address.Address().SockAddr(),
432 		address.Address().Length());
433 
434 	return do_request(family_from_interface_address(address), request, Name(),
435 		B_SOCKET_REMOVE_ALIAS);
436 }
437 
438 
439 status_t
440 BNetworkInterface::RemoveAddress(const BNetworkAddress& address)
441 {
442 	ifreq request;
443 	memcpy(&request.ifr_addr, &address.SockAddr(), address.Length());
444 
445 	return do_request(address.Family(), request, Name(), B_SOCKET_REMOVE_ALIAS);
446 }
447 
448 
449 status_t
450 BNetworkInterface::RemoveAddressAt(int32 index)
451 {
452 	BNetworkInterfaceAddress address;
453 	status_t status = GetAddressAt(index, address);
454 	if (status != B_OK)
455 		return status;
456 
457 	return RemoveAddress(address);
458 }
459 
460 
461 status_t
462 BNetworkInterface::GetHardwareAddress(BNetworkAddress& address)
463 {
464 	int socket = ::socket(AF_LINK, SOCK_DGRAM, 0);
465 	if (socket < 0)
466 		return errno;
467 
468 	FileDescriptorCloser closer(socket);
469 
470 	ifreq request;
471 	strlcpy(request.ifr_name, Name(), IF_NAMESIZE);
472 
473 	if (ioctl(socket, SIOCGIFADDR, &request, sizeof(struct ifreq)) < 0)
474 		return errno;
475 
476 	address.SetTo(request.ifr_addr);
477 	return B_OK;
478 }
479