xref: /haiku/src/kits/network/libnetapi/NetworkInterface.cpp (revision a629567a9001547736cfe892cdf992be16868fed)
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 #include <Messenger.h>
15 #include <NetServer.h>
16 #include <RouteSupport.h>
17 
18 static int
19 family_from_interface_address(const BNetworkInterfaceAddress& address)
20 {
21 	if (address.Address().Family() != AF_UNSPEC)
22 		return address.Address().Family();
23 	if (address.Mask().Family() != AF_UNSPEC)
24 		return address.Mask().Family();
25 	if (address.Destination().Family() != AF_UNSPEC)
26 		return address.Destination().Family();
27 
28 	return AF_INET;
29 }
30 
31 
32 static int
33 family_from_route(const route_entry& route)
34 {
35 	if (route.destination != NULL && route.destination->sa_family != AF_UNSPEC)
36 		return route.destination->sa_family;
37 	if (route.mask != NULL && route.mask->sa_family != AF_UNSPEC)
38 		return route.mask->sa_family;
39 	if (route.gateway != NULL && route.gateway->sa_family != AF_UNSPEC)
40 		return route.gateway->sa_family;
41 	if (route.source != NULL && route.source->sa_family != AF_UNSPEC)
42 		return route.source->sa_family;
43 
44 	return AF_UNSPEC;
45 }
46 
47 
48 static status_t
49 do_ifaliasreq(const char* name, int32 option, BNetworkInterfaceAddress& address,
50 	bool readBack = false)
51 {
52 	int family = AF_INET;
53 	if (!readBack)
54 		family = family_from_interface_address(address);
55 
56 	int socket = ::socket(family, SOCK_DGRAM, 0);
57 	if (socket < 0)
58 		return errno;
59 
60 	FileDescriptorCloser closer(socket);
61 
62 	ifaliasreq request;
63 	strlcpy(request.ifra_name, name, IF_NAMESIZE);
64 	request.ifra_index = address.Index();
65 	request.ifra_flags = address.Flags();
66 
67 	memcpy(&request.ifra_addr, &address.Address().SockAddr(),
68 		address.Address().Length());
69 	memcpy(&request.ifra_mask, &address.Mask().SockAddr(),
70 		address.Mask().Length());
71 	memcpy(&request.ifra_broadaddr, &address.Broadcast().SockAddr(),
72 		address.Broadcast().Length());
73 
74 	if (ioctl(socket, option, &request, sizeof(struct ifaliasreq)) < 0)
75 		return errno;
76 
77 	if (readBack) {
78 		address.SetFlags(request.ifra_flags);
79 		address.Address().SetTo(request.ifra_addr);
80 		address.Mask().SetTo(request.ifra_mask);
81 		address.Broadcast().SetTo(request.ifra_broadaddr);
82 	}
83 
84 	return B_OK;
85 }
86 
87 
88 static status_t
89 do_ifaliasreq(const char* name, int32 option,
90 	const BNetworkInterfaceAddress& address)
91 {
92 	return do_ifaliasreq(name, option,
93 		const_cast<BNetworkInterfaceAddress&>(address));
94 }
95 
96 
97 template<typename T> status_t
98 do_request(int family, T& request, const char* name, int option)
99 {
100 	int socket = ::socket(family, SOCK_DGRAM, 0);
101 	if (socket < 0)
102 		return errno;
103 
104 	FileDescriptorCloser closer(socket);
105 
106 	strlcpy(((struct ifreq&)request).ifr_name, name, IF_NAMESIZE);
107 
108 	if (ioctl(socket, option, &request, sizeof(T)) < 0)
109 		return errno;
110 
111 	return B_OK;
112 }
113 
114 
115 // #pragma mark -
116 
117 
118 BNetworkInterfaceAddress::BNetworkInterfaceAddress()
119 	:
120 	fIndex(-1),
121 	fFlags(0)
122 {
123 }
124 
125 
126 BNetworkInterfaceAddress::~BNetworkInterfaceAddress()
127 {
128 }
129 
130 
131 status_t
132 BNetworkInterfaceAddress::SetTo(const BNetworkInterface& interface, int32 index)
133 {
134 	fIndex = index;
135 	return do_ifaliasreq(interface.Name(), B_SOCKET_GET_ALIAS, *this, true);
136 }
137 
138 
139 void
140 BNetworkInterfaceAddress::SetAddress(const BNetworkAddress& address)
141 {
142 	fAddress = address;
143 }
144 
145 
146 void
147 BNetworkInterfaceAddress::SetMask(const BNetworkAddress& mask)
148 {
149 	fMask = mask;
150 }
151 
152 
153 void
154 BNetworkInterfaceAddress::SetBroadcast(const BNetworkAddress& broadcast)
155 {
156 	fBroadcast = broadcast;
157 }
158 
159 
160 void
161 BNetworkInterfaceAddress::SetDestination(const BNetworkAddress& destination)
162 {
163 	fBroadcast = destination;
164 }
165 
166 
167 void
168 BNetworkInterfaceAddress::SetFlags(uint32 flags)
169 {
170 	fFlags = flags;
171 }
172 
173 
174 // #pragma mark -
175 
176 
177 BNetworkInterface::BNetworkInterface()
178 {
179 	Unset();
180 }
181 
182 
183 BNetworkInterface::BNetworkInterface(const char* name)
184 {
185 	SetTo(name);
186 }
187 
188 
189 BNetworkInterface::BNetworkInterface(uint32 index)
190 {
191 	SetTo(index);
192 }
193 
194 
195 BNetworkInterface::~BNetworkInterface()
196 {
197 }
198 
199 
200 void
201 BNetworkInterface::Unset()
202 {
203 	fName[0] = '\0';
204 }
205 
206 
207 void
208 BNetworkInterface::SetTo(const char* name)
209 {
210 	strlcpy(fName, name, IF_NAMESIZE);
211 }
212 
213 
214 status_t
215 BNetworkInterface::SetTo(uint32 index)
216 {
217 	ifreq request;
218 	request.ifr_index = index;
219 
220 	status_t status = do_request(AF_INET, request, "", SIOCGIFNAME);
221 	if (status != B_OK)
222 		return status;
223 
224 	strlcpy(fName, request.ifr_name, IF_NAMESIZE);
225 	return B_OK;
226 }
227 
228 
229 bool
230 BNetworkInterface::Exists() const
231 {
232 	ifreq request;
233 	return do_request(AF_INET, request, Name(), SIOCGIFINDEX) == B_OK;
234 }
235 
236 
237 const char*
238 BNetworkInterface::Name() const
239 {
240 	return fName;
241 }
242 
243 
244 uint32
245 BNetworkInterface::Index() const
246 {
247 	ifreq request;
248 	if (do_request(AF_INET, request, Name(), SIOCGIFINDEX) != B_OK)
249 		return 0;
250 
251 	return request.ifr_index;
252 }
253 
254 
255 uint32
256 BNetworkInterface::Flags() const
257 {
258 	ifreq request;
259 	if (do_request(AF_INET, request, Name(), SIOCGIFFLAGS) != B_OK)
260 		return 0;
261 
262 	return request.ifr_flags;
263 }
264 
265 
266 uint32
267 BNetworkInterface::MTU() const
268 {
269 	ifreq request;
270 	if (do_request(AF_INET, request, Name(), SIOCGIFMTU) != B_OK)
271 		return 0;
272 
273 	return request.ifr_mtu;
274 }
275 
276 
277 int32
278 BNetworkInterface::Media() const
279 {
280 	ifmediareq request;
281 	request.ifm_count = 0;
282 	request.ifm_ulist = NULL;
283 
284 	if (do_request(AF_INET, request, Name(), SIOCGIFMEDIA) != B_OK)
285 		return -1;
286 
287 	return request.ifm_current;
288 }
289 
290 
291 uint32
292 BNetworkInterface::Metric() const
293 {
294 	ifreq request;
295 	if (do_request(AF_INET, request, Name(), SIOCGIFMETRIC) != B_OK)
296 		return 0;
297 
298 	return request.ifr_metric;
299 }
300 
301 
302 uint32
303 BNetworkInterface::Type() const
304 {
305 	ifreq request;
306 	if (do_request(AF_INET, request, Name(), SIOCGIFTYPE) != B_OK)
307 		return 0;
308 
309 	return request.ifr_type;
310 }
311 
312 
313 status_t
314 BNetworkInterface::GetStats(ifreq_stats& stats)
315 {
316 	ifreq request;
317 	status_t status = do_request(AF_INET, request, Name(), SIOCGIFSTATS);
318 	if (status != B_OK)
319 		return status;
320 
321 	memcpy(&stats, &request.ifr_stats, sizeof(ifreq_stats));
322 	return B_OK;
323 }
324 
325 
326 bool
327 BNetworkInterface::HasLink() const
328 {
329 	return (Flags() & IFF_LINK) != 0;
330 }
331 
332 
333 status_t
334 BNetworkInterface::SetFlags(uint32 flags)
335 {
336 	ifreq request;
337 	request.ifr_flags = flags;
338 	return do_request(AF_INET, request, Name(), SIOCSIFFLAGS);
339 }
340 
341 
342 status_t
343 BNetworkInterface::SetMTU(uint32 mtu)
344 {
345 	ifreq request;
346 	request.ifr_mtu = mtu;
347 	return do_request(AF_INET, request, Name(), SIOCSIFMTU);
348 }
349 
350 
351 status_t
352 BNetworkInterface::SetMedia(int32 media)
353 {
354 	ifreq request;
355 	request.ifr_media = media;
356 	return do_request(AF_INET, request, Name(), SIOCSIFMEDIA);
357 }
358 
359 
360 status_t
361 BNetworkInterface::SetMetric(uint32 metric)
362 {
363 	ifreq request;
364 	request.ifr_metric = metric;
365 	return do_request(AF_INET, request, Name(), SIOCSIFMETRIC);
366 }
367 
368 
369 int32
370 BNetworkInterface::CountAddresses() const
371 {
372 	ifreq request;
373 	if (do_request(AF_INET, request, Name(), B_SOCKET_COUNT_ALIASES) != B_OK)
374 		return 0;
375 
376 	return request.ifr_count;
377 }
378 
379 
380 status_t
381 BNetworkInterface::GetAddressAt(int32 index, BNetworkInterfaceAddress& address)
382 {
383 	return address.SetTo(*this, index);
384 }
385 
386 
387 int32
388 BNetworkInterface::FindAddress(const BNetworkAddress& address)
389 {
390 	int socket = ::socket(address.Family(), SOCK_DGRAM, 0);
391 	if (socket < 0)
392 		return -1;
393 
394 	FileDescriptorCloser closer(socket);
395 
396 	ifaliasreq request;
397 	memset(&request, 0, sizeof(ifaliasreq));
398 
399 	strlcpy(request.ifra_name, Name(), IF_NAMESIZE);
400 	request.ifra_index = -1;
401 	memcpy(&request.ifra_addr, &address.SockAddr(), address.Length());
402 
403 	if (ioctl(socket, B_SOCKET_GET_ALIAS, &request, sizeof(struct ifaliasreq))
404 			< 0) {
405 		return -1;
406 	}
407 
408 	return request.ifra_index;
409 }
410 
411 
412 int32
413 BNetworkInterface::FindFirstAddress(int family)
414 {
415 	int socket = ::socket(family, SOCK_DGRAM, 0);
416 	if (socket < 0)
417 		return -1;
418 
419 	FileDescriptorCloser closer(socket);
420 
421 	ifaliasreq request;
422 	memset(&request, 0, sizeof(ifaliasreq));
423 
424 	strlcpy(request.ifra_name, Name(), IF_NAMESIZE);
425 	request.ifra_index = -1;
426 	request.ifra_addr.ss_family = AF_UNSPEC;
427 
428 	if (ioctl(socket, B_SOCKET_GET_ALIAS, &request, sizeof(struct ifaliasreq))
429 			< 0) {
430 		return -1;
431 	}
432 
433 	return request.ifra_index;
434 }
435 
436 
437 status_t
438 BNetworkInterface::AddAddress(const BNetworkInterfaceAddress& address)
439 {
440 	return do_ifaliasreq(Name(), B_SOCKET_ADD_ALIAS, address);
441 }
442 
443 
444 status_t
445 BNetworkInterface::AddAddress(const BNetworkAddress& local)
446 {
447 	BNetworkInterfaceAddress address;
448 	address.SetAddress(local);
449 
450 	return do_ifaliasreq(Name(), B_SOCKET_ADD_ALIAS, address);
451 }
452 
453 
454 status_t
455 BNetworkInterface::SetAddress(const BNetworkInterfaceAddress& address)
456 {
457 	return do_ifaliasreq(Name(), B_SOCKET_SET_ALIAS, address);
458 }
459 
460 
461 status_t
462 BNetworkInterface::RemoveAddress(const BNetworkInterfaceAddress& address)
463 {
464 	ifreq request;
465 	memcpy(&request.ifr_addr, &address.Address().SockAddr(),
466 		address.Address().Length());
467 
468 	return do_request(family_from_interface_address(address), request, Name(),
469 		B_SOCKET_REMOVE_ALIAS);
470 }
471 
472 
473 status_t
474 BNetworkInterface::RemoveAddress(const BNetworkAddress& address)
475 {
476 	ifreq request;
477 	memcpy(&request.ifr_addr, &address.SockAddr(), address.Length());
478 
479 	return do_request(address.Family(), request, Name(), B_SOCKET_REMOVE_ALIAS);
480 }
481 
482 
483 status_t
484 BNetworkInterface::RemoveAddressAt(int32 index)
485 {
486 	BNetworkInterfaceAddress address;
487 	status_t status = GetAddressAt(index, address);
488 	if (status != B_OK)
489 		return status;
490 
491 	return RemoveAddress(address);
492 }
493 
494 
495 status_t
496 BNetworkInterface::GetHardwareAddress(BNetworkAddress& address)
497 {
498 	int socket = ::socket(AF_LINK, SOCK_DGRAM, 0);
499 	if (socket < 0)
500 		return errno;
501 
502 	FileDescriptorCloser closer(socket);
503 
504 	ifreq request;
505 	strlcpy(request.ifr_name, Name(), IF_NAMESIZE);
506 
507 	if (ioctl(socket, SIOCGIFADDR, &request, sizeof(struct ifreq)) < 0)
508 		return errno;
509 
510 	address.SetTo(request.ifr_addr);
511 	return B_OK;
512 }
513 
514 
515 status_t
516 BNetworkInterface::AddRoute(const route_entry& route)
517 {
518 	int family = family_from_route(route);
519 	if (family == AF_UNSPEC)
520 		return B_BAD_VALUE;
521 
522 	ifreq request;
523 	request.ifr_route = route;
524 	return do_request(family, request, Name(), SIOCADDRT);
525 }
526 
527 
528 status_t
529 BNetworkInterface::AddDefaultRoute(const BNetworkAddress& gateway)
530 {
531 	route_entry route;
532 	memset(&route, 0, sizeof(route_entry));
533 	route.flags = RTF_STATIC | RTF_DEFAULT | RTF_GATEWAY;
534 	route.gateway = const_cast<sockaddr*>(&gateway.SockAddr());
535 
536 	return AddRoute(route);
537 }
538 
539 
540 status_t
541 BNetworkInterface::RemoveRoute(const route_entry& route)
542 {
543 	int family = family_from_route(route);
544 	if (family == AF_UNSPEC)
545 		return B_BAD_VALUE;
546 
547 	return RemoveRoute(family, route);
548 }
549 
550 
551 status_t
552 BNetworkInterface::RemoveRoute(int family, const route_entry& route)
553 {
554 	ifreq request;
555 	request.ifr_route = route;
556 	return do_request(family, request, Name(), SIOCDELRT);
557 }
558 
559 
560 status_t
561 BNetworkInterface::RemoveDefaultRoute(int family)
562 {
563 	route_entry route;
564 	memset(&route, 0, sizeof(route_entry));
565 	route.flags = RTF_STATIC | RTF_DEFAULT;
566 
567 	return RemoveRoute(family, route);
568 }
569 
570 
571 status_t
572 BNetworkInterface::GetRoutes(int family, BObjectList<route_entry>& routes) const
573 {
574 	return BPrivate::get_routes(Name(), family, routes);
575 }
576 
577 
578 status_t
579 BNetworkInterface::GetDefaultRoute(int family, BNetworkAddress& gateway) const
580 {
581 	BObjectList<route_entry> routes(1, true);
582 	status_t status = GetRoutes(family, routes);
583 	if (status != B_OK)
584 		return status;
585 
586 	for (int32 i = routes.CountItems() - 1; i >= 0; i--) {
587 		route_entry* entry = routes.ItemAt(i);
588 		if (entry->flags & RTF_DEFAULT) {
589 			gateway.SetTo(*entry->gateway);
590 			break;
591 		}
592 	}
593 
594 	return B_OK;
595 }
596 
597 
598 status_t
599 BNetworkInterface::AutoConfigure(int family)
600 {
601 	BMessage message(kMsgConfigureInterface);
602 	message.AddString("device", Name());
603 
604 	BMessage address;
605 	address.AddInt32("family", family);
606 	address.AddBool("auto_config", true);
607 	message.AddMessage("address", &address);
608 
609 	BMessenger networkServer(kNetServerSignature);
610 	BMessage reply;
611 	status_t status = networkServer.SendMessage(&message, &reply);
612 	if (status == B_OK)
613 		reply.FindInt32("status", &status);
614 
615 	return status;
616 }
617