xref: /haiku/src/kits/network/libnetapi/NetworkInterface.cpp (revision e7d5c75dce28921de0dc981ed840205a67a0c0e5)
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 
15 
16 static status_t
17 do_ifaliasreq(const char* name, int32 option, BNetworkInterfaceAddress& address,
18 	bool readBack = false)
19 {
20 	int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
21 	if (socket < 0)
22 		return errno;
23 
24 	FileDescriptorCloser closer(socket);
25 
26 	ifaliasreq request;
27 	strlcpy(request.ifra_name, name, IF_NAMESIZE);
28 	request.ifra_index = address.Index();
29 	request.ifra_flags = address.Flags();
30 
31 	memcpy(&request.ifra_addr, &address.Address().SockAddr(),
32 		address.Address().Length());
33 	memcpy(&request.ifra_mask, &address.Mask().SockAddr(),
34 		address.Mask().Length());
35 	memcpy(&request.ifra_broadaddr, &address.Broadcast().SockAddr(),
36 		address.Broadcast().Length());
37 
38 	if (ioctl(socket, option, &request, sizeof(struct ifaliasreq)) < 0)
39 		return errno;
40 
41 	if (readBack) {
42 		address.SetFlags(request.ifra_flags);
43 		address.Address().SetTo(request.ifra_addr);
44 		address.Mask().SetTo(request.ifra_mask);
45 		address.Broadcast().SetTo(request.ifra_broadaddr);
46 	}
47 
48 	return B_OK;
49 }
50 
51 
52 static status_t
53 do_ifaliasreq(const char* name, int32 option,
54 	const BNetworkInterfaceAddress& address)
55 {
56 	return do_ifaliasreq(name, option,
57 		const_cast<BNetworkInterfaceAddress&>(address));
58 }
59 
60 
61 static status_t
62 do_request(ifreq& request, const char* name, int option)
63 {
64 	int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
65 	if (socket < 0)
66 		return errno;
67 
68 	FileDescriptorCloser closer(socket);
69 
70 	strlcpy(request.ifr_name, name, IF_NAMESIZE);
71 
72 	if (ioctl(socket, option, &request, sizeof(struct ifreq)) < 0)
73 		return errno;
74 
75 	return B_OK;
76 }
77 
78 
79 // #pragma mark -
80 
81 
82 BNetworkInterfaceAddress::BNetworkInterfaceAddress()
83 	:
84 	fIndex(0),
85 	fFlags(0)
86 {
87 }
88 
89 
90 BNetworkInterfaceAddress::~BNetworkInterfaceAddress()
91 {
92 }
93 
94 
95 status_t
96 BNetworkInterfaceAddress::SetTo(BNetworkInterface& interface, int32 index)
97 {
98 	fIndex = index;
99 	return do_ifaliasreq(interface.Name(), B_SOCKET_GET_ALIAS, *this, true);
100 }
101 
102 
103 void
104 BNetworkInterfaceAddress::SetAddress(BNetworkAddress& address)
105 {
106 	fAddress = address;
107 }
108 
109 
110 void
111 BNetworkInterfaceAddress::SetMask(BNetworkAddress& mask)
112 {
113 	fMask = mask;
114 }
115 
116 
117 void
118 BNetworkInterfaceAddress::SetBroadcast(BNetworkAddress& broadcast)
119 {
120 	fBroadcast = broadcast;
121 }
122 
123 
124 void
125 BNetworkInterfaceAddress::SetFlags(uint32 flags)
126 {
127 	fFlags = flags;
128 }
129 
130 
131 // #pragma mark -
132 
133 
134 BNetworkInterface::BNetworkInterface()
135 {
136 	Unset();
137 }
138 
139 
140 BNetworkInterface::BNetworkInterface(const char* name)
141 {
142 	SetTo(name);
143 }
144 
145 
146 BNetworkInterface::BNetworkInterface(uint32 index)
147 {
148 	SetTo(index);
149 }
150 
151 
152 BNetworkInterface::~BNetworkInterface()
153 {
154 }
155 
156 
157 void
158 BNetworkInterface::Unset()
159 {
160 	fName[0] = '\0';
161 }
162 
163 
164 void
165 BNetworkInterface::SetTo(const char* name)
166 {
167 	strlcpy(fName, name, IF_NAMESIZE);
168 }
169 
170 
171 status_t
172 BNetworkInterface::SetTo(uint32 index)
173 {
174 	ifreq request;
175 	request.ifr_index = index;
176 
177 	status_t status = do_request(request, "", SIOCGIFNAME);
178 	if (status != B_OK)
179 		return status;
180 
181 	strlcpy(fName, request.ifr_name, IF_NAMESIZE);
182 	return B_OK;
183 }
184 
185 
186 bool
187 BNetworkInterface::Exists() const
188 {
189 	ifreq request;
190 	return do_request(request, Name(), SIOCGIFINDEX) == B_OK;
191 }
192 
193 
194 const char*
195 BNetworkInterface::Name() const
196 {
197 	return fName;
198 }
199 
200 
201 uint32
202 BNetworkInterface::Flags() const
203 {
204 	ifreq request;
205 	if (do_request(request, Name(), SIOCGIFFLAGS) != B_OK)
206 		return 0;
207 
208 	return request.ifr_flags;
209 }
210 
211 
212 uint32
213 BNetworkInterface::MTU() const
214 {
215 	ifreq request;
216 	if (do_request(request, Name(), SIOCGIFMTU) != B_OK)
217 		return 0;
218 
219 	return request.ifr_mtu;
220 }
221 
222 
223 uint32
224 BNetworkInterface::Type() const
225 {
226 	ifreq request;
227 	if (do_request(request, Name(), SIOCGIFTYPE) != B_OK)
228 		return 0;
229 
230 	return request.ifr_type;
231 }
232 
233 
234 status_t
235 BNetworkInterface::GetStats(ifreq_stats& stats)
236 {
237 	ifreq request;
238 	status_t status = do_request(request, Name(), SIOCGIFSTATS);
239 	if (status != B_OK)
240 		return status;
241 
242 	memcpy(&stats, &request.ifr_stats, sizeof(ifreq_stats));
243 	return B_OK;
244 }
245 
246 
247 bool
248 BNetworkInterface::HasLink() const
249 {
250 	return (Flags() & IFF_LINK) != 0;
251 }
252 
253 
254 status_t
255 BNetworkInterface::SetFlags(uint32 flags)
256 {
257 	ifreq request;
258 	request.ifr_flags = flags;
259 	return do_request(request, Name(), SIOCSIFFLAGS);
260 }
261 
262 
263 status_t
264 BNetworkInterface::SetMTU(uint32 mtu)
265 {
266 	ifreq request;
267 	request.ifr_mtu = mtu;
268 	return do_request(request, Name(), SIOCSIFMTU);
269 }
270 
271 
272 int32
273 BNetworkInterface::CountAddresses() const
274 {
275 	ifreq request;
276 	if (do_request(request, Name(), B_SOCKET_COUNT_ALIASES) != B_OK)
277 		return 0;
278 
279 	return request.ifr_count;
280 }
281 
282 
283 status_t
284 BNetworkInterface::GetAddressAt(int32 index, BNetworkInterfaceAddress& address)
285 {
286 	return address.SetTo(*this, index);
287 }
288 
289 
290 status_t
291 BNetworkInterface::AddAddress(const BNetworkInterfaceAddress& address)
292 {
293 	return do_ifaliasreq(Name(), B_SOCKET_ADD_ALIAS, address);
294 }
295 
296 
297 status_t
298 BNetworkInterface::SetAddress(const BNetworkInterfaceAddress& address)
299 {
300 	return do_ifaliasreq(Name(), B_SOCKET_SET_ALIAS, address);
301 }
302 
303 
304 status_t
305 BNetworkInterface::RemoveAddress(const BNetworkInterfaceAddress& address)
306 {
307 	ifreq request;
308 	memcpy(&request.ifr_addr, &address.Address().SockAddr(),
309 		address.Address().Length());
310 
311 	return do_request(request, Name(), B_SOCKET_REMOVE_ALIAS);
312 }
313 
314 
315 status_t
316 BNetworkInterface::RemoveAddressAt(int32 index)
317 {
318 	BNetworkInterfaceAddress address;
319 	status_t status = GetAddressAt(index, address);
320 	if (status != B_OK)
321 		return status;
322 
323 	return RemoveAddress(address);
324 }
325 
326 
327 status_t
328 BNetworkInterface::GetHardwareAddress(BNetworkAddress& address)
329 {
330 	int socket = ::socket(AF_LINK, SOCK_DGRAM, 0);
331 	if (socket < 0)
332 		return errno;
333 
334 	FileDescriptorCloser closer(socket);
335 
336 	ifreq request;
337 	strlcpy(request.ifr_name, Name(), IF_NAMESIZE);
338 
339 	if (ioctl(socket, SIOCGIFADDR, &request, sizeof(struct ifreq)) < 0)
340 		return errno;
341 
342 	address.SetTo(request.ifr_addr);
343 	return B_OK;
344 }
345