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