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