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