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