xref: /haiku/src/kits/network/libnetapi/NetworkInterface.cpp (revision b46615c55ad2c8fe6de54412055a0713da3d610a)
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 
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 	return request.ifra_index;
408 }
409 
410 
411 int32
412 BNetworkInterface::FindFirstAddress(int family)
413 {
414 	int socket = ::socket(family, SOCK_DGRAM, 0);
415 	if (socket < 0)
416 		return -1;
417 
418 	FileDescriptorCloser closer(socket);
419 
420 	ifaliasreq request;
421 	memset(&request, 0, sizeof(ifaliasreq));
422 
423 	strlcpy(request.ifra_name, Name(), IF_NAMESIZE);
424 	request.ifra_index = -1;
425 	request.ifra_addr.ss_family = AF_UNSPEC;
426 
427 	if (ioctl(socket, B_SOCKET_GET_ALIAS, &request, sizeof(struct ifaliasreq))
428 			< 0)
429 		return -1;
430 
431 	return request.ifra_index;
432 }
433 
434 
435 status_t
436 BNetworkInterface::AddAddress(const BNetworkInterfaceAddress& address)
437 {
438 	return do_ifaliasreq(Name(), B_SOCKET_ADD_ALIAS, address);
439 }
440 
441 
442 status_t
443 BNetworkInterface::AddAddress(const BNetworkAddress& local)
444 {
445 	BNetworkInterfaceAddress address;
446 	address.SetAddress(local);
447 
448 	return do_ifaliasreq(Name(), B_SOCKET_ADD_ALIAS, address);
449 }
450 
451 
452 status_t
453 BNetworkInterface::SetAddress(const BNetworkInterfaceAddress& address)
454 {
455 	return do_ifaliasreq(Name(), B_SOCKET_SET_ALIAS, address);
456 }
457 
458 
459 status_t
460 BNetworkInterface::RemoveAddress(const BNetworkInterfaceAddress& address)
461 {
462 	ifreq request;
463 	memcpy(&request.ifr_addr, &address.Address().SockAddr(),
464 		address.Address().Length());
465 
466 	return do_request(family_from_interface_address(address), request, Name(),
467 		B_SOCKET_REMOVE_ALIAS);
468 }
469 
470 
471 status_t
472 BNetworkInterface::RemoveAddress(const BNetworkAddress& address)
473 {
474 	ifreq request;
475 	memcpy(&request.ifr_addr, &address.SockAddr(), address.Length());
476 
477 	return do_request(address.Family(), request, Name(), B_SOCKET_REMOVE_ALIAS);
478 }
479 
480 
481 status_t
482 BNetworkInterface::RemoveAddressAt(int32 index)
483 {
484 	BNetworkInterfaceAddress address;
485 	status_t status = GetAddressAt(index, address);
486 	if (status != B_OK)
487 		return status;
488 
489 	return RemoveAddress(address);
490 }
491 
492 
493 status_t
494 BNetworkInterface::GetHardwareAddress(BNetworkAddress& address)
495 {
496 	int socket = ::socket(AF_LINK, SOCK_DGRAM, 0);
497 	if (socket < 0)
498 		return errno;
499 
500 	FileDescriptorCloser closer(socket);
501 
502 	ifreq request;
503 	strlcpy(request.ifr_name, Name(), IF_NAMESIZE);
504 
505 	if (ioctl(socket, SIOCGIFADDR, &request, sizeof(struct ifreq)) < 0)
506 		return errno;
507 
508 	address.SetTo(request.ifr_addr);
509 	return B_OK;
510 }
511 
512 
513 status_t
514 BNetworkInterface::AddRoute(const route_entry& route)
515 {
516 	int family = family_from_route(route);
517 	if (family == AF_UNSPEC)
518 		return B_BAD_VALUE;
519 
520 	ifreq request;
521 	request.ifr_route = route;
522 	return do_request(family, request, Name(), SIOCADDRT);
523 }
524 
525 
526 status_t
527 BNetworkInterface::AddDefaultRoute(const BNetworkAddress& gateway)
528 {
529 	route_entry route;
530 	memset(&route, 0, sizeof(route_entry));
531 	route.flags = RTF_STATIC | RTF_DEFAULT | RTF_GATEWAY;
532 	route.gateway = const_cast<sockaddr*>(&gateway.SockAddr());
533 
534 	return AddRoute(route);
535 }
536 
537 
538 status_t
539 BNetworkInterface::RemoveRoute(const route_entry& route)
540 {
541 	int family = family_from_route(route);
542 	if (family == AF_UNSPEC)
543 		return B_BAD_VALUE;
544 
545 	return RemoveRoute(family, route);
546 }
547 
548 
549 status_t
550 BNetworkInterface::RemoveRoute(int family, const route_entry& route)
551 {
552 	ifreq request;
553 	request.ifr_route = route;
554 	return do_request(family, request, Name(), SIOCDELRT);
555 }
556 
557 
558 status_t
559 BNetworkInterface::RemoveDefaultRoute(int family)
560 {
561 	route_entry route;
562 	memset(&route, 0, sizeof(route_entry));
563 	route.flags = RTF_STATIC | RTF_DEFAULT;
564 
565 	return RemoveRoute(family, route);
566 }
567 
568 
569 status_t
570 BNetworkInterface::AutoConfigure(int family)
571 {
572 	BMessage message(kMsgConfigureInterface);
573 	message.AddString("device", Name());
574 
575 	BMessage address;
576 	address.AddInt32("family", family);
577 	address.AddBool("auto_config", true);
578 	message.AddMessage("address", &address);
579 
580 	BMessenger networkServer(kNetServerSignature);
581 	BMessage reply;
582 	status_t status = networkServer.SendMessage(&message, &reply);
583 	if (status == B_OK)
584 		reply.FindInt32("status", &status);
585 
586 	return status;
587 }
588