void configure_interface(int socket, const char* name, char* const* args, int32 argCount) { ifreq request; if (!prepare_request(request, name)) return; uint32 index = 0; if (ioctl(socket, SIOCGIFINDEX, &request, sizeof(request)) >= 0) index = request.ifr_index; bool hasAddress = false, hasMask = false, hasPeer = false; bool hasBroadcast = false, doAutoConfig = false; struct sockaddr address, mask, peer, broadcast; int mtu = -1, metric = -1, media = -1; int addFlags = 0, currentFlags = 0, removeFlags = 0; // try to parse address family int32 familyIndex; int32 i = 0; if (get_address_family(args[i], familyIndex)) i++; if (kFamilies[familyIndex].family != AF_INET) { close(socket); // replace socket with one of the correct address family socket = ::socket(kFamilies[familyIndex].family, SOCK_DGRAM, 0); if (socket < 0) { fprintf(stderr, "%s: Address family \"%s\" is not available.\n", kProgramName, kFamilies[familyIndex].name); exit(1); } } if (index == 0) { // the interface does not exist yet, we have to add it first request.ifr_parameter.base_name[0] = '\0'; request.ifr_parameter.device[0] = '\0'; request.ifr_parameter.sub_type = 0; // the default device is okay for us if (ioctl(socket, SIOCAIFADDR, &request, sizeof(request)) < 0) { fprintf(stderr, "%s: Could not add interface: %s\n", kProgramName, strerror(errno)); exit(1); } } // try to parse address if (parse_address(familyIndex, args[i], address)) { hasAddress = true; i++; if (parse_address(familyIndex, args[i], mask)) { hasMask = true; i++; } } // parse parameters and flags while (i < argCount) { if (!strcmp(args[i], "peer")) { if (!parse_address(familyIndex, args[i + 1], peer)) { fprintf(stderr, "%s: Option 'peer' needs valid address " "parameter\n", kProgramName); exit(1); } hasPeer = true; i++; } else if (!strcmp(args[i], "nm") || !strcmp(args[i], "netmask")) { if (hasMask) { fprintf(stderr, "%s: Netmask is specified twice\n", kProgramName); exit(1); } if (!parse_address(familyIndex, args[i + 1], mask)) { fprintf(stderr, "%s: Option 'netmask' needs valid address " "parameter\n", kProgramName); exit(1); } hasMask = true; i++; } else if (!strcmp(args[i], "bc") || !strcmp(args[i], "broadcast")) { if (hasBroadcast) { fprintf(stderr, "%s: broadcast address is specified twice\n", kProgramName); exit(1); } if (!parse_address(familyIndex, args[i + 1], broadcast)) { fprintf(stderr, "%s: Option 'broadcast' needs valid address " "parameter\n", kProgramName); exit(1); } hasBroadcast = true; addFlags |= IFF_BROADCAST; i++; } else if (!strcmp(args[i], "mtu")) { mtu = args[i + 1] ? strtol(args[i + 1], NULL, 0) : 0; if (mtu <= 500) { fprintf(stderr, "%s: Option 'mtu' expected valid max transfer " "unit size\n", kProgramName); exit(1); } i++; } else if (!strcmp(args[i], "metric")) { if (i + 1 >= argCount) { fprintf(stderr, "%s: Option 'metric' exptected parameter\n", kProgramName); exit(1); } metric = strtol(args[i + 1], NULL, 0); i++; } else if (!strcmp(args[i], "media")) { if (ioctl(socket, SIOCGIFMEDIA, &request, sizeof(struct ifreq)) < 0) { fprintf(stderr, "%s: Unable to detect media type\n", kProgramName); exit(1); } if (i + 1 >= argCount) { fprintf(stderr, "%s: Option 'media' exptected parameter\n", kProgramName); exit(1); } if (!media_parse_subtype(args[i + 1], IFM_TYPE(request.ifr_media), &media)) { fprintf(stderr, "%s: Invalid parameter for option 'media': " "'%s'\n", kProgramName, args[i + 1]); exit(1); } i++; } else if (!strcmp(args[i], "up") || !strcmp(args[i], "-down")) { addFlags |= IFF_UP; } else if (!strcmp(args[i], "down") || !strcmp(args[i], "-up")) { removeFlags |= IFF_UP; } else if (!strcmp(args[i], "bcast")) { addFlags |= IFF_BROADCAST; } else if (!strcmp(args[i], "-bcast")) { removeFlags |= IFF_BROADCAST; } else if (!strcmp(args[i], "promisc")) { addFlags |= IFF_PROMISC; } else if (!strcmp(args[i], "-promisc")) { removeFlags |= IFF_PROMISC; } else if (!strcmp(args[i], "allmulti")) { addFlags |= IFF_ALLMULTI; } else if (!strcmp(args[i], "-allmulti")) { removeFlags |= IFF_ALLMULTI; } else if (!strcmp(args[i], "loopback")) { addFlags |= IFF_LOOPBACK; } else if (!strcmp(args[i], "auto-config")) { doAutoConfig = true; } else usage(1); i++; } if ((addFlags & removeFlags) != 0) { fprintf(stderr, "%s: Contradicting flags specified\n", kProgramName); exit(1); } if (doAutoConfig && (hasAddress || hasMask || hasBroadcast || hasPeer)) { fprintf(stderr, "%s: Contradicting changes specified\n", kProgramName); exit(1); } // set address/mask/broadcast/peer if (hasAddress) { memcpy(&request.ifr_addr, &address, address.sa_len); if (ioctl(socket, SIOCSIFADDR, &request, sizeof(struct ifreq)) < 0) { fprintf(stderr, "%s: Setting address failed: %s\n", kProgramName, strerror(errno)); exit(1); } } if (ioctl(socket, SIOCGIFFLAGS, &request, sizeof(struct ifreq)) < 0) { fprintf(stderr, "%s: Getting flags failed: %s\n", kProgramName, strerror(errno)); exit(1); } currentFlags = request.ifr_flags; if (hasMask) { memcpy(&request.ifr_mask, &mask, mask.sa_len); if (ioctl(socket, SIOCSIFNETMASK, &request, sizeof(struct ifreq)) < 0) { fprintf(stderr, "%s: Setting subnet mask failed: %s\n", kProgramName, strerror(errno)); exit(1); } } if (hasBroadcast) { memcpy(&request.ifr_broadaddr, &broadcast, broadcast.sa_len); if (ioctl(socket, SIOCSIFBRDADDR, &request, sizeof(struct ifreq)) < 0) { fprintf(stderr, "%s: Setting broadcast address failed: %s\n", kProgramName, strerror(errno)); exit(1); } } if (hasPeer) { memcpy(&request.ifr_dstaddr, &peer, peer.sa_len); if (ioctl(socket, SIOCSIFDSTADDR, &request, sizeof(struct ifreq)) < 0) { fprintf(stderr, "%s: Setting peer address failed: %s\n", kProgramName, strerror(errno)); exit(1); } } // set flags if (hasAddress || hasMask || hasBroadcast || hasPeer) removeFlags = IFF_AUTO_CONFIGURED | IFF_CONFIGURING; if (addFlags || removeFlags) { request.ifr_flags = (currentFlags & ~removeFlags) | addFlags; if (ioctl(socket, SIOCSIFFLAGS, &request, sizeof(struct ifreq)) < 0) { fprintf(stderr, "%s: Setting flags failed: %s\n", kProgramName, strerror(errno)); } } // set options if (mtu != -1) { request.ifr_mtu = mtu; if (ioctl(socket, SIOCSIFMTU, &request, sizeof(struct ifreq)) < 0) { fprintf(stderr, "%s: Setting MTU failed: %s\n", kProgramName, strerror(errno)); } } if (metric != -1) { request.ifr_metric = metric; if (ioctl(socket, SIOCSIFMETRIC, &request, sizeof(struct ifreq)) < 0) { fprintf(stderr, "%s: Setting metric failed: %s\n", kProgramName, strerror(errno)); } } if (media != -1) { request.ifr_media = media; if (ioctl(socket, SIOCSIFMEDIA, &request, sizeof(struct ifreq)) < 0) { fprintf(stderr, "%s: Setting media failed: %s\n", kProgramName, strerror(errno)); } } // start auto configuration, if asked for if (doAutoConfig) { BMessage message(kMsgConfigureInterface); message.AddString("device", name); BMessage address; address.AddString("family", "inet"); address.AddBool("auto_config", true); message.AddMessage("address", &address); BMessenger networkServer(kNetServerSignature); if (networkServer.IsValid()) { BMessage reply; status_t status = networkServer.SendMessage(&message, &reply); if (status != B_OK) { fprintf(stderr, "%s: Sending auto-config message failed: %s\n", kProgramName, strerror(status)); } else if (reply.FindInt32("status", &status) == B_OK && status != B_OK) { fprintf(stderr, "%s: Auto-configuring failed: %s\n", kProgramName, strerror(status)); } } else { fprintf(stderr, "%s: The net_server needs to run for the auto " "configuration!\n", kProgramName); } } }
void configure_interface(const char* name, char* const* args, int32 argCount) { // try to parse address family int32 i = 0; int family = get_address_family(args[i]); if (family != AF_UNSPEC) i++; // try to parse address BNetworkAddress address; BNetworkAddress mask; if (parse_address(family, args[i], address)) { i++; if (parse_address(family, args[i], mask)) i++; } BNetworkInterface interface(name); if (!interface.Exists()) { // the interface does not exist yet, we have to add it first BNetworkRoster& roster = BNetworkRoster::Default(); status_t status = roster.AddInterface(interface); if (status != B_OK) { fprintf(stderr, "%s: Could not add interface: %s\n", kProgramName, strerror(status)); exit(1); } } BNetworkAddress broadcast; BNetworkAddress peer; int mtu = -1, metric = -1, media = -1; int addFlags = 0, currentFlags = 0, removeFlags = 0; bool doAutoConfig = false; // parse parameters and flags while (i < argCount) { if (!strcmp(args[i], "peer")) { if (!parse_address(family, args[i + 1], peer)) { fprintf(stderr, "%s: Option 'peer' needs valid address " "parameter\n", kProgramName); exit(1); } i++; } else if (!strcmp(args[i], "nm") || !strcmp(args[i], "netmask")) { if (!mask.IsEmpty()) { fprintf(stderr, "%s: Netmask or prefix length is specified " "twice\n", kProgramName); exit(1); } if (!parse_address(family, args[i + 1], mask)) { fprintf(stderr, "%s: Option 'netmask' needs valid address " "parameter\n", kProgramName); exit(1); } i++; } else if (!strcmp(args[i], "prefixlen") || !strcmp(args[i], "plen") || !strcmp(args[i], "prefix-length")) { if (!mask.IsEmpty()) { fprintf(stderr, "%s: Netmask or prefix length is specified " "twice\n", kProgramName); exit(1); } // default to AF_INET if no address family has been specified yet if (family == AF_UNSPEC) family = AF_INET; if (!prefix_length_to_mask(family, args[i + 1], mask)) { fprintf(stderr, "%s: Option 'prefix-length %s' is invalid for " "this address family\n", kProgramName, args[i + 1]); exit(1); } i++; } else if (!strcmp(args[i], "bc") || !strcmp(args[i], "broadcast")) { if (!broadcast.IsEmpty()) { fprintf(stderr, "%s: broadcast address is specified twice\n", kProgramName); exit(1); } if (!parse_address(family, args[i + 1], broadcast)) { fprintf(stderr, "%s: Option 'broadcast' needs valid address " "parameter\n", kProgramName); exit(1); } addFlags |= IFF_BROADCAST; i++; } else if (!strcmp(args[i], "mtu")) { mtu = args[i + 1] ? strtol(args[i + 1], NULL, 0) : 0; if (mtu <= 500) { fprintf(stderr, "%s: Option 'mtu' expected valid max transfer " "unit size\n", kProgramName); exit(1); } i++; } else if (!strcmp(args[i], "metric")) { if (i + 1 >= argCount) { fprintf(stderr, "%s: Option 'metric' expected parameter\n", kProgramName); exit(1); } metric = strtol(args[i + 1], NULL, 0); i++; } else if (!strcmp(args[i], "media")) { media = interface.Media(); if (media < 0) { fprintf(stderr, "%s: Unable to detect media type\n", kProgramName); exit(1); } if (i + 1 >= argCount) { fprintf(stderr, "%s: Option 'media' expected parameter\n", kProgramName); exit(1); } if (!media_parse_subtype(args[i + 1], IFM_TYPE(media), &media)) { fprintf(stderr, "%s: Invalid parameter for option 'media': " "'%s'\n", kProgramName, args[i + 1]); exit(1); } i++; } else if (!strcmp(args[i], "up") || !strcmp(args[i], "-down")) { addFlags |= IFF_UP; } else if (!strcmp(args[i], "down") || !strcmp(args[i], "-up")) { removeFlags |= IFF_UP; } else if (!strcmp(args[i], "bcast")) { addFlags |= IFF_BROADCAST; } else if (!strcmp(args[i], "-bcast")) { removeFlags |= IFF_BROADCAST; } else if (!strcmp(args[i], "promisc")) { addFlags |= IFF_PROMISC; } else if (!strcmp(args[i], "-promisc")) { removeFlags |= IFF_PROMISC; } else if (!strcmp(args[i], "allmulti")) { addFlags |= IFF_ALLMULTI; } else if (!strcmp(args[i], "-allmulti")) { removeFlags |= IFF_ALLMULTI; } else if (!strcmp(args[i], "loopback")) { addFlags |= IFF_LOOPBACK; } else if (!strcmp(args[i], "auto-config")) { doAutoConfig = true; } else usage(1); i++; } if ((addFlags & removeFlags) != 0) { fprintf(stderr, "%s: Contradicting flags specified\n", kProgramName); exit(1); } if (doAutoConfig && (!address.IsEmpty() || !mask.IsEmpty() || !broadcast.IsEmpty() || !peer.IsEmpty())) { fprintf(stderr, "%s: Contradicting changes specified\n", kProgramName); exit(1); } // set address/mask/broadcast/peer if (!address.IsEmpty() || !mask.IsEmpty() || !broadcast.IsEmpty()) { BNetworkInterfaceAddress interfaceAddress; interfaceAddress.SetAddress(address); interfaceAddress.SetMask(mask); if (!broadcast.IsEmpty()) interfaceAddress.SetBroadcast(broadcast); else if (!peer.IsEmpty()) interfaceAddress.SetDestination(peer); status_t status = interface.SetAddress(interfaceAddress); if (status != B_OK) { fprintf(stderr, "%s: Setting address failed: %s\n", kProgramName, strerror(status)); exit(1); } } currentFlags = interface.Flags(); // set flags if (!address.IsEmpty() || !mask.IsEmpty() || !broadcast.IsEmpty() || !peer.IsEmpty()) removeFlags = IFF_AUTO_CONFIGURED | IFF_CONFIGURING; if (addFlags || removeFlags) { status_t status = interface.SetFlags((currentFlags & ~removeFlags) | addFlags); if (status != B_OK) { fprintf(stderr, "%s: Setting flags failed: %s\n", kProgramName, strerror(status)); } } // set options if (mtu != -1) { status_t status = interface.SetMTU(mtu); if (status != B_OK) { fprintf(stderr, "%s: Setting MTU failed: %s\n", kProgramName, strerror(status)); } } if (metric != -1) { status_t status = interface.SetMetric(metric); if (status != B_OK) { fprintf(stderr, "%s: Setting metric failed: %s\n", kProgramName, strerror(status)); } } if (media != -1) { status_t status = interface.SetMedia(media); if (status != B_OK) { fprintf(stderr, "%s: Setting media failed: %s\n", kProgramName, strerror(status)); } } // start auto configuration, if asked for if (doAutoConfig) { status_t status = interface.AutoConfigure(family); if (status == B_BAD_PORT_ID) { fprintf(stderr, "%s: The net_server needs to run for the auto " "configuration!\n", kProgramName); } else if (status != B_OK) { fprintf(stderr, "%s: Auto-configuring failed: %s\n", kProgramName, strerror(status)); } } }