/*
* net.c
*
* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Author(s): David Cantrell
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "../isys/isys.h"
#include "../isys/net.h"
#include "../isys/wireless.h"
#include "../isys/iface.h"
#include "../isys/str.h"
#include "lang.h"
#include "loader.h"
#include "loadermisc.h"
#include "log.h"
#include "method.h"
#include "net.h"
#include "windows.h"
/* boot flags */
extern uint64_t flags;
/**
* Callback function for the CIDR entry boxes on the manual TCP/IP
* configuration window.
*
* @param co The entry field that triggered the callback.
* @param dptr Pointer to intfconfig_s data structure for this field.
* @see intfconfig_s
*/
static void cidrCallback(newtComponent co, void * dptr) {
struct intfconfig_s * data = dptr;
int cidr, upper = 0;
struct in_addr addr;
if (co == data->cidr4Entry) {
if (data->cidr4 == NULL && data->ipv4 == NULL)
return;
if (inet_pton(AF_INET, data->cidr4, &addr) >= 1)
return;
cidr = atoi(data->cidr4);
if (strcmp(data->ipv4, ""))
upper = 32;
} else if (co == data->cidr6Entry) {
if (data->cidr6 == NULL && data->ipv6 == NULL)
return;
cidr = atoi(data->cidr6);
if (strcmp(data->ipv6, ""))
upper = 128;
}
if (upper != 0) {
if (cidr < 1 || cidr > upper) {
newtWinMessage(_("Invalid Prefix"), _("Retry"),
_("Prefix must be between 1 and 32 "
"for IPv4 networks or between 1 and 128 "
"for IPv6 networks"));
}
}
}
static void ipCallback(newtComponent co, void * dptr) {
int i;
char *buf, *octet;
struct intfconfig_s * data = dptr;
if (co == data->ipv4Entry) {
/* do we need to guess a netmask for the user? */
if (data->cidr4 == NULL && data->ipv4 != NULL) {
buf = strdup(data->ipv4);
octet = strtok(buf, ".");
i = atoi(octet);
free(buf);
free(octet);
if (i >= 0 && i <= 127)
newtEntrySet(data->cidr4Entry, "8", 1);
else if (i >= 128 && i <= 191)
newtEntrySet(data->cidr4Entry, "16", 1);
else if (i >= 192 && i <= 222)
newtEntrySet(data->cidr4Entry, "24", 1);
}
return;
} else if (co == data->ipv6Entry) {
/* users must provide a mask, we can't guess for ipv6 */
return;
}
}
static void setMethodSensitivity(void *dptr, int radio_button_count) {
int i = 0;
for (i = 0; i < radio_button_count; i++) {
newtCheckboxSetFlags(*((newtComponent *) dptr), NEWT_FLAG_DISABLED,
NEWT_FLAGS_TOGGLE);
dptr += sizeof (newtComponent);
}
return;
}
static void v4MethodCallback(newtComponent co, void *dptr) {
setMethodSensitivity(dptr, 2);
return;
}
static void v6MethodCallback(newtComponent co, void *dptr) {
setMethodSensitivity(dptr, 3);
return;
}
static int waitForLink(char * dev) {
extern int num_link_checks;
extern int post_link_sleep;
int tries = 0;
/* try to wait for a valid link -- if the status is unknown or
* up continue, else sleep for 1 second and try again for up
* to five times */
logMessage(DEBUGLVL, "waiting for link %s...", dev);
while (tries < num_link_checks) {
if (get_link_status(dev) != 0)
break;
sleep(1);
tries++;
}
logMessage(DEBUGLVL, " %d seconds.", tries);
if (tries < num_link_checks){
/* Networks with STP set up will give link when the port
* is isolated from the network, and won't forward packets
* until they decide we're not a switch. */
logMessage(DEBUGLVL, "sleep (nicdelay) for %d secs first", post_link_sleep);
sleep(post_link_sleep);
logMessage(DEBUGLVL, "continuing...");
return 0;
}
logMessage(WARNING, " no network link detected on %s", dev);
return 1;
}
static void parseEthtoolSettings(struct loaderData_s * loaderData) {
char * option, * buf;
ethtool_duplex duplex = ETHTOOL_DUPLEX_UNSPEC;
ethtool_speed speed = ETHTOOL_SPEED_UNSPEC;
buf = strdup(loaderData->ethtool);
option = strtok(buf, " ");
while (option) {
if (option[strlen(option) - 1] == '\"')
option[strlen(option) - 1] = '\0';
if (option[0] == '\"')
option++;
if (!strncmp(option, "duplex", 6)) {
if (!strncmp(option + 7, "full", 4))
duplex = ETHTOOL_DUPLEX_FULL;
else if (!strncmp(option + 7, "half", 4))
duplex = ETHTOOL_DUPLEX_HALF;
else
logMessage(WARNING, "Unknown duplex setting: %s", option + 7);
option = strtok(NULL, " ");
} else if (!strncmp("speed", option, 5)) {
if (!strncmp(option + 6, "1000", 4))
speed = ETHTOOL_SPEED_1000;
else if (!strncmp(option + 6, "100", 3))
speed = ETHTOOL_SPEED_100;
else if (!strncmp(option + 6, "10", 2))
speed = ETHTOOL_SPEED_10;
else
logMessage(WARNING, "Unknown speed setting: %s", option + 6);
option = strtok(NULL, " ");
} else {
logMessage(WARNING, "Unknown ethtool setting: %s", option);
}
option = strtok(NULL, " ");
}
setEthtoolSettings(loaderData->netDev, speed, duplex);
free(buf);
}
void initLoopback(void) {
struct ifreq req;
int s;
s = socket(AF_INET, SOCK_DGRAM, 0);
memset(&req, 0, sizeof(req));
strcpy(req.ifr_name, "lo");
if (ioctl(s, SIOCGIFFLAGS, &req)) {
logMessage(LOG_ERR, "ioctl SIOCGIFFLAGS failed: %d %s\n", errno,
strerror(errno));
close(s);
return;
}
req.ifr_flags |= (IFF_UP | IFF_RUNNING);
if (ioctl(s, SIOCSIFFLAGS, &req)) {
logMessage(LOG_ERR, "ioctl SIOCSIFFLAGS failed: %d %s\n", errno,
strerror(errno));
close(s);
return;
}
close(s);
return;
}
static int getWirelessConfig(struct networkDeviceConfig *cfg, char * ifname) {
char * wepkey = "";
char * essid = "";
int rc = 0;
char * buf;
if (cfg->wepkey != NULL) {
wepkey = strdup(cfg->wepkey);
}
if (cfg->essid != NULL) {
essid = strdup(cfg->essid);
} else {
essid = get_essid(ifname);
}
rc = asprintf(&buf, _("%s is a wireless network adapter. Please "
"provide the ESSID and encryption key needed "
"to access your wireless network. If no key "
"is needed, leave this field blank and the "
"install will continue."), ifname);
do {
struct newtWinEntry entry[] = { { N_("ESSID"), (const char **)&essid, 0 },
{ N_("Encryption Key"), (const char **) &wepkey, 0 },
{ NULL, NULL, 0 } };
rc = newtWinEntries(_("Wireless Settings"), buf,
40, 5, 10, 30, entry, _("OK"), _("Back"), NULL);
if (rc == 2) {
free(buf);
return LOADER_BACK;
}
/* set stuff up */
} while (rc == 2);
free(buf);
if (cfg->wepkey != NULL)
free(cfg->wepkey);
if (wepkey && (strlen(wepkey) > 0))
cfg->wepkey = strdup(wepkey);
else
cfg->wepkey = NULL;
if (cfg->essid != NULL)
free(cfg->essid);
if (essid && (strlen(essid) > 0))
cfg->essid = strdup(essid);
else
cfg->essid = NULL;
return LOADER_OK;
}
static int getDnsServers(struct networkDeviceConfig * cfg) {
int rc;
struct in_addr addr;
struct in6_addr addr6;
const char * ns = "";
struct newtWinEntry entry[] = { { N_("Nameserver IP"), &ns, 0 },
{ NULL, NULL, 0 } };
do {
rc = newtWinEntries(_("Missing Nameserver"),
_("Your IP address request returned configuration "
"information, but it did not include a nameserver address. "
"If you do not have this information, you can leave "
"the field blank and the install will continue."),
61, 0, 0, 45, entry, _("OK"), _("Back"), NULL);
if (rc == 2) return LOADER_BACK;
rc = 0;
if (!ns || !*ns) {
cfg->dev.numDns = 0;
break;
} else {
if (inet_pton(AF_INET, ns, &addr) >= 1)
cfg->dev.dnsServers[0] = ip_addr_in(&addr);
else if (inet_pton(AF_INET6, ns, &addr6) >= 1)
cfg->dev.dnsServers[0] = ip_addr_in6(&addr6);
else
rc = 2;
}
if (rc) {
newtWinMessage(_("Invalid IP Information"), _("Retry"),
_("You entered an invalid IP address."));
} else {
cfg->dev.set |= PUMP_NETINFO_HAS_DNS;
cfg->dev.numDns = 1;
}
} while (rc == 2);
return LOADER_OK;
}
void printLoaderDataIPINFO(struct loaderData_s *loaderData) {
logMessage(DEBUGLVL, "loaderData->ipinfo_set = |%d|", loaderData->ipinfo_set);
logMessage(DEBUGLVL, "loaderData->ipv4 = |%s|", loaderData->ipv4);
logMessage(DEBUGLVL, "loaderData->ipv6info_set = |%d|", loaderData->ipv6info_set);
logMessage(DEBUGLVL, "loaderData->ipv6 = |%s|", loaderData->ipv6);
logMessage(DEBUGLVL, "loaderData->dhcpTimeout = |%d|", loaderData->dhcpTimeout);
logMessage(DEBUGLVL, "loaderData->netmask = |%s|", loaderData->netmask);
logMessage(DEBUGLVL, "loaderData->gateway = |%s|", loaderData->gateway);
logMessage(DEBUGLVL, "loaderData->dns = |%s|", loaderData->dns);
logMessage(DEBUGLVL, "loaderData->hostname = |%s|", loaderData->hostname);
logMessage(DEBUGLVL, "loaderData->noDns = |%d|", loaderData->noDns);
logMessage(DEBUGLVL, "loaderData->netDev_set = |%d|", loaderData->netDev_set);
logMessage(DEBUGLVL, "loaderData->netDev = |%s|", loaderData->netDev);
logMessage(DEBUGLVL, "loaderData->netCls_set = |%d|", loaderData->netCls_set);
logMessage(DEBUGLVL, "loaderData->netCls = |%s|", loaderData->netCls);
}
/* given loader data from kickstart, populate network configuration struct */
void setupNetworkDeviceConfig(struct networkDeviceConfig * cfg,
struct loaderData_s * loaderData) {
struct in_addr addr;
struct in6_addr addr6;
char * c;
/* set to 1 to get ks network struct logged */
#if 0
printLoaderDataIPINFO(loaderData);
#endif
if (loaderData->ethtool) {
parseEthtoolSettings(loaderData);
}
if (loaderData->netCls_set) {
cfg->vendor_class = loaderData->netCls;
} else {
cfg->vendor_class = NULL;
}
if (loaderData->ipinfo_set) {
if (is_wireless_interface(loaderData->netDev)) {
if (loaderData->essid) {
logMessage(INFO, "setting specified essid of %s",
loaderData->essid);
cfg->essid = strdup(loaderData->essid);
}
if (loaderData->wepkey) {
logMessage(INFO, "setting specified wepkey");
cfg->wepkey = strdup(loaderData->wepkey);
}
/* go ahead and set up the wireless interface in case
* we're using dhcp */
setupWireless(cfg);
}
/* this is how we specify dhcp */
if (!strncmp(loaderData->ipv4, "dhcp", 4)) {
char *ret = NULL;
/* JKFIXME: this soooo doesn't belong here. and it needs to
* be broken out into a function too */
logMessage(INFO, "sending dhcp request through device %s",
loaderData->netDev);
if (!FL_CMDLINE(flags)) {
startNewt();
winStatus(55, 3, NULL,
_("Sending request for IP information for %s..."),
loaderData->netDev, 0);
} else {
printf("Sending request for IP information for %s...\n",
loaderData->netDev);
}
if (!FL_TESTING(flags)) {
waitForLink(loaderData->netDev);
cfg->noDns = loaderData->noDns;
cfg->dhcpTimeout = loaderData->dhcpTimeout;
ret = doDhcp(cfg);
}
if (!FL_CMDLINE(flags))
newtPopWindow();
if (ret != NULL) {
logMessage(DEBUGLVL, "dhcp: %s", ret);
return;
}
cfg->isDynamic = 1;
cfg->preset = 1;
} else if (loaderData->ipv4) {
if (inet_pton(AF_INET, loaderData->ipv4, &addr) >= 1) {
cfg->dev.ip = ip_addr_in(&addr);
cfg->dev.ipv4 = ip_addr_in(&addr);
cfg->dev.set |= PUMP_INTFINFO_HAS_IP|PUMP_INTFINFO_HAS_IPV4_IP;
cfg->isDynamic = 0;
cfg->preset = 1;
}
} else if (loaderData->ipv6) {
if (inet_pton(AF_INET6, loaderData->ipv6, &addr6) >= 1) {
cfg->dev.ip = ip_addr_in6(&addr6);
cfg->dev.ipv6 = ip_addr_in6(&addr6);
cfg->dev.set |= PUMP_INTFINFO_HAS_IP|PUMP_INTFINFO_HAS_IPV6_IP;
cfg->isDynamic = 0;
cfg->preset = 1;
}
} else { /* invalid ip information, disable the setting of ip info */
loaderData->ipinfo_set = 0;
cfg->isDynamic = 0;
loaderData->ipv4 = NULL;
loaderData->ipv6 = NULL;
}
}
if (loaderData->netmask && (inet_pton(AF_INET, loaderData->netmask, &addr) >= 1)) {
cfg->dev.netmask = ip_addr_in(&addr);
cfg->dev.set |= PUMP_INTFINFO_HAS_NETMASK;
}
if (loaderData->gateway && (inet_pton(AF_INET, loaderData->gateway, &addr) >= 1)) {
cfg->dev.gateway = ip_addr_in(&addr);
cfg->dev.set |= PUMP_NETINFO_HAS_GATEWAY;
}
if (loaderData->gateway && (inet_pton(AF_INET6, loaderData->gateway, &addr6) >= 1)) {
cfg->dev.gateway = ip_addr_in6(&addr6);
cfg->dev.set |= PUMP_NETINFO_HAS_GATEWAY;
}
if (loaderData->dns) {
char * buf;
char ret[48];
buf = strdup(loaderData->dns);
/* Scan the dns parameter for multiple comma-separated IP addresses */
c = strtok(buf, ",");
while ((cfg->dev.numDns < MAXNS) && (c != NULL)) {
if (inet_pton(AF_INET, c, &addr) >= 1) {
cfg->dev.dnsServers[cfg->dev.numDns] = ip_addr_in(&addr);
cfg->dev.numDns++;
inet_ntop(AF_INET, &addr, ret, INET_ADDRSTRLEN);
logMessage(DEBUGLVL, "adding dns4 %s", ret);
c = strtok(NULL, ",");
} else if (inet_pton(AF_INET6, c, &addr6) >= 1) {
cfg->dev.dnsServers[cfg->dev.numDns] = ip_addr_in6(&addr6);
cfg->dev.numDns++;
inet_ntop(AF_INET6, &addr6, ret, INET6_ADDRSTRLEN);
logMessage(DEBUGLVL, "adding dns6 %s", ret);
c = strtok(NULL, ",");
}
}
logMessage(INFO, "dnsservers is %s", loaderData->dns);
if (cfg->dev.numDns)
cfg->dev.set |= PUMP_NETINFO_HAS_DNS;
}
if (loaderData->hostname) {
logMessage(INFO, "setting specified hostname of %s",
loaderData->hostname);
cfg->dev.hostname = strdup(loaderData->hostname);
cfg->dev.set |= PUMP_NETINFO_HAS_HOSTNAME;
}
if (loaderData->mtu) {
cfg->mtu = loaderData->mtu;
cfg->dev.mtu = loaderData->mtu;
cfg->dev.set |= PUMP_INTFINFO_HAS_MTU;
}
if (loaderData->peerid) {
cfg->peerid = strdup(loaderData->peerid);
}
if (loaderData->subchannels) {
cfg->subchannels = strdup(loaderData->subchannels);
}
if (loaderData->ctcprot) {
cfg->ctcprot = strdup(loaderData->ctcprot);
}
if (loaderData->portname) {
cfg->portname = strdup(loaderData->portname);
}
if (loaderData->nettype) {
cfg->nettype = strdup(loaderData->nettype);
}
if (loaderData->ethtool) {
parseEthtoolSettings(loaderData);
}
cfg->noDns = loaderData->noDns;
cfg->dhcpTimeout = loaderData->dhcpTimeout;
}
int readNetConfig(char * device, struct networkDeviceConfig * cfg,
char * dhcpclass, int methodNum) {
struct networkDeviceConfig newCfg;
int ret;
int i = 0;
struct netconfopts opts;
struct in_addr addr, nm, nw;
struct in6_addr addr6;
struct intfconfig_s ipcomps;
memset(&ipcomps, '\0', sizeof(ipcomps));
ipcomps.ipv4 = NULL;
ipcomps.ipv6 = NULL;
ipcomps.cidr4 = NULL;
ipcomps.cidr6 = NULL;
ipcomps.gw = NULL;
ipcomps.ns = NULL;
/* init opts */
opts.ipv4Choice = 0;
opts.ipv6Choice = 0;
/* init newCfg */
memset(&newCfg, '\0', sizeof(newCfg));
strcpy(newCfg.dev.device, device);
newCfg.essid = NULL;
newCfg.wepkey = NULL;
newCfg.isDynamic = cfg->isDynamic;
newCfg.noDns = cfg->noDns;
newCfg.dhcpTimeout = cfg->dhcpTimeout;
newCfg.preset = cfg->preset;
if (dhcpclass) {
newCfg.vendor_class = strdup(dhcpclass);
} else {
newCfg.vendor_class = NULL;
}
/* JKFIXME: we really need a way to override this and be able to change
* our network config */
if (!FL_TESTING(flags) && cfg->preset) {
logMessage(INFO, "doing kickstart... setting it up");
if (configureNetwork(cfg)) {
newtWinMessage(_("Network Error"), _("Retry"),
_("There was an error configuring your network "
"interface."));
return LOADER_BACK;
}
findHostAndDomain(cfg);
if (!cfg->noDns)
writeResolvConf(cfg);
return LOADER_NOOP;
}
/* handle wireless device configuration */
if (is_wireless_interface(device)) {
logMessage(INFO, "%s is a wireless adapter", device);
if (getWirelessConfig(cfg, device) == LOADER_BACK)
return LOADER_BACK;
if (cfg->essid != NULL)
newCfg.essid = strdup(cfg->essid);
if (cfg->wepkey != NULL)
newCfg.wepkey = strdup(cfg->wepkey);
} else {
logMessage(INFO, "%s is not a wireless adapter", device);
}
/* dhcp/manual network configuration loop */
i = 1;
while (i == 1) {
ret = configureTCPIP(device, cfg, &newCfg, &opts, methodNum);
if (ret == LOADER_NOOP) {
/* dhcp selected, proceed */
i = 0;
} else if (ret == LOADER_OK) {
/* do manual configuration */
ret = manualNetConfig(device, cfg, &newCfg, &ipcomps, &opts);
if (ret == LOADER_BACK) {
continue;
} else if (ret == LOADER_OK) {
i = 0;
}
} else if (ret == LOADER_BACK) {
return LOADER_BACK;
}
}
cfg->ipv4method = newCfg.ipv4method;
cfg->ipv6method = newCfg.ipv6method;
/* preserve extra dns servers for the sake of being nice */
if (cfg->dev.numDns > newCfg.dev.numDns) {
for (i = newCfg.dev.numDns; i < cfg->dev.numDns; i++) {
memcpy(&newCfg.dev.dnsServers[i], &cfg->dev.dnsServers[i],
sizeof (newCfg.dev.dnsServers[i]));
}
newCfg.dev.numDns = cfg->dev.numDns;
}
cfg->isDynamic = newCfg.isDynamic;
memcpy(&cfg->dev,&newCfg.dev,sizeof(newCfg.dev));
if (!(cfg->dev.set & PUMP_NETINFO_HAS_GATEWAY)) {
if (ipcomps.gw && *ipcomps.gw) {
if (inet_pton(AF_INET, ipcomps.gw, &addr) >= 1) {
cfg->dev.gateway = ip_addr_in(&addr);
cfg->dev.set |= PUMP_NETINFO_HAS_GATEWAY;
} else if (inet_pton(AF_INET6, ipcomps.gw, &addr6) >= 1) {
cfg->dev.gateway = ip_addr_in6(&addr6);
cfg->dev.set |= PUMP_NETINFO_HAS_GATEWAY;
}
}
}
/* calculate any missing IPv4 pieces */
if (opts.ipv4Choice == '*') {
addr = ip_in_addr(&cfg->dev.ipv4);
nm = ip_in_addr(&cfg->dev.netmask);
if (!(cfg->dev.set & PUMP_INTFINFO_HAS_NETWORK)) {
cfg->dev.network = ip_addr_v4(ntohl((addr.s_addr) & nm.s_addr));
cfg->dev.set |= PUMP_INTFINFO_HAS_NETWORK;
}
if (!(cfg->dev.set & PUMP_INTFINFO_HAS_BROADCAST)) {
nw = ip_in_addr(&cfg->dev.network);
cfg->dev.broadcast = ip_addr_v4(ntohl(nw.s_addr | ~nm.s_addr));
cfg->dev.set |= PUMP_INTFINFO_HAS_BROADCAST;
}
}
/* make sure we don't have a dhcp_nic handle for static */
if ((cfg->isDynamic == 0) && (cfg->dev.dhcp_nic != NULL)) {
dhcp_nic_free(cfg->dev.dhcp_nic);
cfg->dev.dhcp_nic = NULL;
}
/* dump some network debugging info */
debugNetworkInfo(cfg);
/* bring up the interface */
if (!FL_TESTING(flags)) {
if (configureNetwork(cfg)) {
newtWinMessage(_("Network Error"), _("Retry"),
_("There was an error configuring your network "
"interface."));
return LOADER_BACK;
}
findHostAndDomain(cfg);
writeResolvConf(cfg);
}
return LOADER_OK;
}
int configureTCPIP(char * device, struct networkDeviceConfig * cfg,
struct networkDeviceConfig * newCfg,
struct netconfopts * opts, int methodNum) {
int i = 0, z = 0, skipForm = 0;
char *dret = NULL;
newtComponent f, okay, back, answer;
newtComponent ipv4Checkbox, ipv6Checkbox, v4Method[2], v6Method[3];
newtGrid grid, checkgrid, buttons;
newCfg->ipv4method = -1;
newCfg->ipv6method = -1;
/* UI WINDOW 1: ask for ipv4 choice, ipv6 choice, and conf methods */
/* IPv4 checkbox */
if (!opts->ipv4Choice) {
if (FL_NOIPV4(flags) && !FL_IP_PARAM(flags))
opts->ipv4Choice = ' ';
else
opts->ipv4Choice = '*';
}
ipv4Checkbox = newtCheckbox(-1, -1, _("Enable IPv4 support"),
opts->ipv4Choice, NULL, &(opts->ipv4Choice));
v4Method[0] = newtRadiobutton(-1, -1, DHCP_METHOD_STR, 1, NULL);
v4Method[1] = newtRadiobutton(-1, -1, MANUAL_METHOD_STR, 0, v4Method[0]);
/* IPv6 checkbox */
if (!opts->ipv6Choice) {
if (FL_NOIPV6(flags) && !FL_IPV6_PARAM(flags))
opts->ipv6Choice = ' ';
else
opts->ipv6Choice = '*';
}
ipv6Checkbox = newtCheckbox(-1, -1, _("Enable IPv6 support"),
opts->ipv6Choice, NULL, &(opts->ipv6Choice));
v6Method[0] = newtRadiobutton(-1, -1, AUTO_METHOD_STR, 1, NULL);
v6Method[1] = newtRadiobutton(-1, -1, DHCPV6_METHOD_STR, 0, v6Method[0]);
v6Method[2] = newtRadiobutton(-1, -1, MANUAL_METHOD_STR, 0, v6Method[1]);
/* button bar at the bottom of the window */
buttons = newtButtonBar(_("OK"), &okay, _("Back"), &back, NULL);
/* checkgrid contains the toggle options for net configuration */
checkgrid = newtCreateGrid(1, 8);
newtGridSetField(checkgrid, 0, 0, NEWT_GRID_COMPONENT, ipv4Checkbox,
0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
for (i = 1; i < 3; i++)
newtGridSetField(checkgrid, 0, i, NEWT_GRID_COMPONENT, v4Method[i-1],
7, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
newtGridSetField(checkgrid, 0, 4, NEWT_GRID_COMPONENT, ipv6Checkbox,
0, 1, 0, 0, NEWT_ANCHOR_LEFT, 0);
for (i = 5; i < 8; i++)
newtGridSetField(checkgrid, 0, i, NEWT_GRID_COMPONENT, v6Method[i-5],
7, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
/* main window layout */
grid = newtCreateGrid(1, 2);
newtGridSetField(grid, 0, 0, NEWT_GRID_SUBGRID, checkgrid,
0, 0, 0, 1, 0, 0);
newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, buttons,
0, 0, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
f = newtForm(NULL, NULL, 0);
newtGridAddComponentsToForm(grid, f, 1);
newtGridWrappedWindow(grid, _("Configure TCP/IP"));
newtGridFree(grid, 1);
/* callbacks */
newtComponentAddCallback(ipv4Checkbox, v4MethodCallback, &v4Method);
newtComponentAddCallback(ipv6Checkbox, v6MethodCallback, &v6Method);
/* match radio button sensitivity to initial checkbox choices */
if (opts->ipv4Choice == ' ')
setMethodSensitivity(&v4Method, 2);
if (opts->ipv6Choice == ' ')
setMethodSensitivity(&v6Method, 3);
/* If the user provided any of the following boot paramters, skip
* prompting for network configuration information:
* ip= ipv6=
* noipv4 noipv6
* ip= noipv6
* ipv6= noipv4
* we also skip this form for anyone doing a kickstart install
*/
if ((FL_IP_PARAM(flags) && FL_IPV6_PARAM(flags)) ||
(FL_IP_PARAM(flags) && FL_NOIPV6(flags)) ||
(FL_IPV6_PARAM(flags) && FL_NOIPV4(flags)) ||
(FL_NOIPV4(flags) && FL_NOIPV6(flags)) ||
(FL_IS_KICKSTART(flags))) {
skipForm = 1;
newtPopWindow();
}
/* run the form */
do {
if (!skipForm) {
answer = newtRunForm(f);
if (answer == back) {
newtFormDestroy(f);
newtPopWindow();
return LOADER_BACK;
}
/* need at least one stack */
if (opts->ipv4Choice == ' ' && opts->ipv6Choice == ' ') {
newtWinMessage(_("Missing Protocol"), _("Retry"),
_("You must select at least one protocol (IPv4 "
"or IPv6)."));
continue;
}
/* NFS only works over IPv4 */
if (opts->ipv4Choice == ' ' && methodNum == METHOD_NFS) {
newtWinMessage(_("IPv4 Needed for NFS"), _("Retry"),
_("NFS installation method requires IPv4 support."));
continue;
}
}
/* what TCP/IP stacks do we use? what conf methods? */
if (opts->ipv4Choice == '*') {
flags &= ~LOADER_FLAGS_NOIPV4;
for (z = 0; z < 2; z++)
if (newtRadioGetCurrent(v4Method[0]) == v4Method[z])
newCfg->ipv4method = z;
} else {
flags |= LOADER_FLAGS_NOIPV4;
}
if (opts->ipv6Choice == '*') {
flags &= ~LOADER_FLAGS_NOIPV6;
for (z = 0; z < 3; z++)
if (newtRadioGetCurrent(v6Method[0]) == v6Method[z])
newCfg->ipv6method = z;
} else {
flags |= LOADER_FLAGS_NOIPV6;
}
/* do interface configuration (call DHCP here, or return for manual) */
if ((!FL_NOIPV4(flags) && newCfg->ipv4method == IPV4_DHCP_METHOD) ||
(!FL_NOIPV6(flags) && (newCfg->ipv6method == IPV6_AUTO_METHOD ||
newCfg->ipv6method == IPV6_DHCP_METHOD))) {
/* do DHCP if selected */
if (!FL_TESTING(flags)) {
winStatus(55, 3, NULL,
_("Sending request for IP information for %s..."),
device, 0);
waitForLink(device);
dret = doDhcp(newCfg);
newtPopWindow();
}
if (dret == NULL) {
newCfg->isDynamic = 1;
if (!(newCfg->dev.set & PUMP_NETINFO_HAS_DNS)) {
logMessage(WARNING,
"dhcp worked, but did not return a DNS server");
/*
* prompt for a nameserver IP address when:
* - DHCP for IPv4, DHCP/AUTO for IPv6 and both enabled
* - IPv4 disabled and DHCP/AUTO for IPv6
* - IPv6 disabled and DHCP for IPv4
*/
if ((newCfg->ipv4method == IPV4_DHCP_METHOD
&& (newCfg->ipv6method == IPV6_AUTO_METHOD ||
newCfg->ipv6method == IPV6_DHCP_METHOD))
|| (newCfg->ipv4method == IPV4_DHCP_METHOD
&& FL_NOIPV6(flags))
|| (FL_NOIPV4(flags)
&& (newCfg->ipv6method == IPV6_AUTO_METHOD ||
newCfg->ipv6method == IPV6_DHCP_METHOD))) {
i = getDnsServers(newCfg);
i = i ? 0 : 1;
} else {
i = 1;
}
} else {
i = 1;
}
} else {
logMessage(DEBUGLVL, "dhcp: %s", dret);
i = 0;
}
} else {
/* manual IP configuration for IPv4 and IPv6 */
newtFormDestroy(f);
newtPopWindow();
return LOADER_OK;
}
} while (i != 1);
newtFormDestroy(f);
newtPopWindow();
if ((!FL_NOIPV4(flags) && newCfg->ipv4method == IPV4_MANUAL_METHOD) ||
(!FL_NOIPV6(flags) && newCfg->ipv6method == IPV6_MANUAL_METHOD))
return LOADER_OK;
else
return LOADER_NOOP;
}
int manualNetConfig(char * device, struct networkDeviceConfig * cfg,
struct networkDeviceConfig * newCfg,
struct intfconfig_s * ipcomps, struct netconfopts * opts) {
int i, rows, pos, prefix, cidr, q, have[2], stack[2];
char *buf = NULL;
char ret[48];
ip_addr_t *tip;
struct in_addr addr;
struct in6_addr addr6;
newtComponent f, okay, back, answer;
newtGrid egrid = NULL;
newtGrid qgrid = NULL;
newtGrid rgrid = NULL;
newtGrid buttons, grid;
newtComponent text = NULL;
/* so we don't perform this test over and over */
stack[IPV4] = opts->ipv4Choice == '*'
&& newCfg->ipv4method == IPV4_MANUAL_METHOD;
stack[IPV6] = opts->ipv6Choice == '*'
&& newCfg->ipv6method == IPV6_MANUAL_METHOD;
/* UI WINDOW 2 (optional): manual IP config for non-DHCP installs */
rows = 2;
for (i = 0; i < 2; i++)
if (stack[i]) rows++;
egrid = newtCreateGrid(4, rows);
pos = 0;
/* IPv4 entry items */
if (stack[IPV4]) {
newtGridSetField(egrid, 0, pos, NEWT_GRID_COMPONENT,
newtLabel(-1, -1, _("IPv4 address:")),
0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
ipcomps->ipv4Entry = newtEntry(-1, -1, NULL, 16, &ipcomps->ipv4, 0);
ipcomps->cidr4Entry = newtEntry(-1, -1, NULL, 16, &ipcomps->cidr4, 0);
/* use a nested grid for ipv4 addr & netmask */
qgrid = newtCreateGrid(3, 1);
newtGridSetField(qgrid, 0, 0, NEWT_GRID_COMPONENT,
ipcomps->ipv4Entry, 1, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
newtGridSetField(qgrid, 1, 0, NEWT_GRID_COMPONENT,
newtLabel(-1, -1, _("/")),
1, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
newtGridSetField(qgrid, 2, 0, NEWT_GRID_COMPONENT,
ipcomps->cidr4Entry, 1, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
newtGridSetField(egrid, 1, pos, NEWT_GRID_SUBGRID, qgrid,
0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
newtComponentAddCallback(ipcomps->ipv4Entry, ipCallback, ipcomps);
newtComponentAddCallback(ipcomps->cidr4Entry, cidrCallback, ipcomps);
/* populate fields if we have data already */
tip = NULL;
if (cfg->dev.set & PUMP_INTFINFO_HAS_IPV4_IP)
tip = &(cfg->dev.ipv4);
else if (newCfg->dev.set & PUMP_INTFINFO_HAS_IPV4_IP)
tip = &(newCfg->dev.ipv4);
if (tip) {
inet_ntop(tip->sa_family, IP_ADDR(tip), ret, IP_STRLEN(tip));
newtEntrySet(ipcomps->ipv4Entry, ret, 1);
}
tip = NULL;
if (cfg->dev.set & PUMP_INTFINFO_HAS_NETMASK)
tip = &(cfg->dev.netmask);
else if (newCfg->dev.set & PUMP_INTFINFO_HAS_NETMASK)
tip = &(newCfg->dev.netmask);
if (tip) {
inet_ntop(tip->sa_family, IP_ADDR(tip), ret, IP_STRLEN(tip));
newtEntrySet(ipcomps->cidr4Entry, ret, 1);
}
pos++;
}
/* IPv6 entry items */
if (stack[IPV6]) {
newtGridSetField(egrid, 0, pos, NEWT_GRID_COMPONENT,
newtLabel(-1, -1, _("IPv6 address:")),
0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
ipcomps->ipv6Entry = newtEntry(-1, -1, NULL, 41, &ipcomps->ipv6, 0);
ipcomps->cidr6Entry = newtEntry(-1, -1, NULL, 4, &ipcomps->cidr6, 0);
/* use a nested grid for ipv6 addr & netmask */
rgrid = newtCreateGrid(3, 1);
newtGridSetField(rgrid, 0, 0, NEWT_GRID_COMPONENT,
ipcomps->ipv6Entry, 1, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
newtGridSetField(rgrid, 1, 0, NEWT_GRID_COMPONENT,
newtLabel(-1, -1, _("/")),
1, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
newtGridSetField(rgrid, 2, 0, NEWT_GRID_COMPONENT,
ipcomps->cidr6Entry, 1, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
newtGridSetField(egrid, 1, pos, NEWT_GRID_SUBGRID, rgrid,
0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
newtComponentAddCallback(ipcomps->ipv6Entry, ipCallback, ipcomps);
newtComponentAddCallback(ipcomps->cidr6Entry, cidrCallback, ipcomps);
/* populate fields if we have data already */
tip = NULL;
if (cfg->dev.set & PUMP_INTFINFO_HAS_IPV6_IP)
tip = &(cfg->dev.ipv6);
else if (newCfg->dev.set & PUMP_INTFINFO_HAS_IPV6_IP)
tip = &(newCfg->dev.ipv6);
if (tip) {
inet_ntop(tip->sa_family, IP_ADDR(tip), ret, IP_STRLEN(tip));
newtEntrySet(ipcomps->ipv6Entry, ret, 1);
}
if (cfg->dev.set & PUMP_INTFINFO_HAS_IPV6_PREFIX)
q = asprintf(&buf, "%d", cfg->dev.ipv6_prefixlen);
else if (newCfg->dev.set & PUMP_INTFINFO_HAS_IPV6_PREFIX)
q = asprintf(&buf, "%d", newCfg->dev.ipv6_prefixlen);
if (buf) {
newtEntrySet(ipcomps->cidr6Entry, buf, 1);
free(buf);
}
pos++;
}
/* common entry items */
ipcomps->gwEntry = newtEntry(-1, -1, NULL, 41, &ipcomps->gw, 0);
ipcomps->nsEntry = newtEntry(-1, -1, NULL, 41, &ipcomps->ns, 0);
newtGridSetField(egrid, 0, pos, NEWT_GRID_COMPONENT,
newtLabel(-1, -1, _("Gateway:")),
0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
newtGridSetField(egrid, 1, pos, NEWT_GRID_COMPONENT,
ipcomps->gwEntry, 1, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
pos++;
newtGridSetField(egrid, 0, pos, NEWT_GRID_COMPONENT,
newtLabel(-1, -1, _("Name Server:")),
0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
newtGridSetField(egrid, 1, pos, NEWT_GRID_COMPONENT,
ipcomps->nsEntry, 1, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
tip = NULL;
if (cfg->dev.set & PUMP_NETINFO_HAS_GATEWAY)
tip = &(cfg->dev.gateway);
else if (newCfg->dev.set & PUMP_NETINFO_HAS_GATEWAY)
tip = &(newCfg->dev.gateway);
if (tip) {
inet_ntop(tip->sa_family, IP_ADDR(tip), ret, IP_STRLEN(tip));
newtEntrySet(ipcomps->gwEntry, ret, 1);
}
tip = NULL;
if (cfg->dev.numDns)
tip = &(cfg->dev.dnsServers[0]);
else if (newCfg->dev.numDns)
tip = &(newCfg->dev.dnsServers[0]);
if (tip) {
inet_ntop(tip->sa_family, IP_ADDR(tip), ret, IP_STRLEN(tip));
newtEntrySet(ipcomps->nsEntry, ret, 1);
}
newtComponentAddCallback(ipcomps->gwEntry, ipCallback, ipcomps);
newtComponentAddCallback(ipcomps->nsEntry, ipCallback, ipcomps);
/* button bar at the bottom of the window */
buttons = newtButtonBar(_("OK"), &okay, _("Back"), &back, NULL);
/* main window layout */
grid = newtCreateGrid(1, 3);
i = asprintf(&buf, _("Enter the IPv4 and/or the IPv6 address and prefix "
"(address / prefix). For IPv4, the dotted-quad "
"netmask or the CIDR-style prefix are acceptable. "
"The gateway and name server fields must be valid IPv4 "
"or IPv6 addresses."));
text = newtTextboxReflowed(-1, -1, buf, 52, 0, 10, 0);
newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, text,
0, 0, 0, 1, NEWT_ANCHOR_LEFT, 0);
newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, egrid,
0, 0, 0, 1, NEWT_ANCHOR_LEFT, 0);
newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttons,
0, 0, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
f = newtForm(NULL, NULL, 0);
newtGridAddComponentsToForm(grid, f, 1);
newtGridWrappedWindow(grid, _("Manual TCP/IP Configuration"));
newtGridFree(grid, 1);
/* run the form */
while ((have[IPV4] != 2) || (have[IPV6] != 2)) {
have[IPV4] = 0;
have[IPV6] = 0;
for (i = 0; i < 2; i++)
if (!stack[i]) have[i] = 2;
answer = newtRunForm(f);
/* memset(newCfg, 0, sizeof(*newCfg)); */
/* collect IPv4 data */
if (stack[IPV4]) {
if (ipcomps->ipv4) {
if (inet_pton(AF_INET, ipcomps->ipv4, &addr) >= 1) {
newCfg->dev.ipv4 = ip_addr_in(&addr);
newCfg->dev.set |= PUMP_INTFINFO_HAS_IPV4_IP;
have[IPV4]++;
}
}
if (ipcomps->cidr4) {
if (inet_pton(AF_INET, ipcomps->cidr4, &addr) >= 1) {
newCfg->dev.netmask = ip_addr_in(&addr);
newCfg->dev.set |= PUMP_INTFINFO_HAS_NETMASK;
have[IPV4]++;
} else {
cidr = atoi(ipcomps->cidr4);
if (cidr >= 1 && cidr <= 32) {
if (inet_pton(AF_INET, "255.255.255.255", &addr) >= 1) {
addr.s_addr = htonl(ntohl(addr.s_addr) << (32 - cidr));
newCfg->dev.netmask = ip_addr_in(&addr);
newCfg->dev.set |= PUMP_INTFINFO_HAS_NETMASK;
have[IPV4]++;
}
}
}
}
}
/* collect IPv6 data */
if (stack[IPV6]) {
if (ipcomps->ipv6) {
if (inet_pton(AF_INET6, ipcomps->ipv6, &addr6) >= 1) {
newCfg->dev.ipv6 = ip_addr_in6(&addr6);
newCfg->dev.set |= PUMP_INTFINFO_HAS_IPV6_IP;
have[IPV6]++;
}
}
if (ipcomps->cidr6) {
prefix = atoi(ipcomps->cidr6);
if (prefix > 0 || prefix <= 128) {
newCfg->dev.ipv6_prefixlen = prefix;
newCfg->dev.set |= PUMP_INTFINFO_HAS_IPV6_PREFIX;
have[IPV6]++;
}
}
}
/* collect common network settings */
if (ipcomps->gw) {
if (inet_pton(AF_INET, ipcomps->gw, &addr) >= 1) {
newCfg->dev.gateway = ip_addr_in(&addr);
newCfg->dev.set |= PUMP_NETINFO_HAS_GATEWAY;
} else if (inet_pton(AF_INET6, ipcomps->gw, &addr6) >= 1) {
newCfg->dev.gateway = ip_addr_in6(&addr6);
newCfg->dev.set |= PUMP_NETINFO_HAS_GATEWAY;
}
}
/* The cfg->dev.ip field needs to store the IPv4 address if
* there is one.
*/
if (ipcomps->ipv4) {
if (inet_pton(AF_INET, ipcomps->ipv4, &addr) >= 1) {
newCfg->dev.ip = ip_addr_in(&addr);
newCfg->dev.set |= PUMP_INTFINFO_HAS_IP;
}
}
/* gather nameservers */
if (ipcomps->ns) {
if (inet_pton(AF_INET, ipcomps->ns, &addr) >= 1) {
cfg->dev.dnsServers[0] = ip_addr_in(&addr);
cfg->dev.set |= PUMP_NETINFO_HAS_DNS;
if (cfg->dev.numDns < 1)
cfg->dev.numDns = 1;
} else if (inet_pton(AF_INET6, ipcomps->ns, &addr6) >= 1) {
cfg->dev.dnsServers[0] = ip_addr_in6(&addr6);
cfg->dev.set |= PUMP_NETINFO_HAS_DNS;
if (cfg->dev.numDns < 1)
cfg->dev.numDns = 1;
}
}
/* user selected back, but we've saved what they entered already */
if (answer == back) {
newtFormDestroy(f);
newtPopWindow();
free(buf);
return LOADER_BACK;
}
/* we might be done now */
if (have[IPV4] != 2) {
newtWinMessage(_("Missing Information"), _("Retry"),
_("You must enter both a valid IPv4 address and a "
"network mask or CIDR prefix."));
}
if (have[IPV6] != 2) {
newtWinMessage(_("Missing Information"), _("Retry"),
_("You must enter both a valid IPv6 address and a "
"CIDR prefix."));
}
strcpy(newCfg->dev.device, device);
newCfg->isDynamic = 0;
}
free(buf);
newtFormDestroy(f);
newtPopWindow();
return LOADER_OK;
}
void debugNetworkInfo(struct networkDeviceConfig *cfg) {
int i;
char *buf = NULL;
logMessage(DEBUGLVL, "device = %s", cfg->dev.device);
if (cfg->dev.set & PUMP_INTFINFO_HAS_IPV4_IP)
logMessage(DEBUGLVL, "ipv4 = %s", ip_text(cfg->dev.ipv4, buf, 0));
if (cfg->dev.set & PUMP_INTFINFO_HAS_BROADCAST)
logMessage(DEBUGLVL,"broadcast = %s",ip_text(cfg->dev.broadcast,buf,0));
if (cfg->dev.set & PUMP_INTFINFO_HAS_NETMASK)
logMessage(DEBUGLVL, "netmask = %s", ip_text(cfg->dev.netmask, buf, 0));
if (cfg->dev.set & PUMP_INTFINFO_HAS_NETWORK)
logMessage(DEBUGLVL, "network = %s", ip_text(cfg->dev.network, buf, 0));
if (cfg->dev.set & PUMP_INTFINFO_HAS_IPV6_IP)
logMessage(DEBUGLVL, "ipv6 = %s", ip_text(cfg->dev.ipv6, buf, 0));
if (cfg->dev.set & PUMP_INTFINFO_HAS_IPV6_PREFIX)
logMessage(DEBUGLVL, "ipv6_prefixlen = %d", cfg->dev.ipv6_prefixlen);
if (cfg->dev.set & PUMP_NETINFO_HAS_GATEWAY)
logMessage(DEBUGLVL, "gateway = %s", ip_text(cfg->dev.gateway, buf, 0));
if (cfg->dev.set & PUMP_NETINFO_HAS_DNS)
for (i=0; i < cfg->dev.numDns; i++)
logMessage(DEBUGLVL, "dns[%d] = %s", i,
ip_text(cfg->dev.dnsServers[i], buf, 0));
}
int setupWireless(struct networkDeviceConfig *dev) {
/* wireless config needs to be set up before we can bring the interface
* up */
if (!is_wireless_interface(dev->dev.device))
return 0;
if (dev->essid) {
logMessage(INFO, "setting essid for %s to %s", dev->dev.device,
dev->essid);
if (set_essid(dev->dev.device, dev->essid) < 0) {
logMessage(ERROR, "failed to set essid: %s", strerror(errno));
}
if (dev->wepkey) {
logMessage(INFO, "setting encryption key for %s", dev->dev.device);
if (set_wep_key(dev->dev.device, dev->wepkey) < 0) {
logMessage(ERROR, "failed to set wep key: %s", strerror(errno));
}
}
}
return 0;
}
void netlogger(void *arg, int priority, char *fmt, va_list va) {
int p;
char *buf = NULL;
if (priority == LOG_ERR)
p = ERROR;
else if (priority == LOG_INFO)
p = INFO;
else if (priority == LOG_DEBUG)
p = DEBUGLVL;
else if (priority == LOG_FATAL)
p = CRITICAL;
else
p = INFO;
if (vasprintf(&buf, fmt, va) != -1) {
logMessage(p, "%s", buf);
free(buf);
} else {
logMessage(ERROR, "unable to log network message");
}
return;
}
char *doDhcp(struct networkDeviceConfig *dev) {
struct pumpNetIntf *i;
char *r = NULL, *class = NULL;
time_t timeout;
int loglevel;
DHCP_Preference pref = 0;
struct utsname kv;
i = &dev->dev;
if (dev->dhcpTimeout < 0)
timeout = 45;
else
timeout = dev->dhcpTimeout;
if (dev->vendor_class != NULL) {
class = dev->vendor_class;
} else {
if (uname(&kv) == -1) {
logMessage(ERROR, "failure running uname() in doDhcp()");
class = "anaconda";
} else {
int ret;
ret = asprintf(&class, "anaconda-%s %s %s",
kv.sysname, kv.release, kv.machine);
logMessage(DEBUGLVL, "sending %s as dhcp vendor-class", class);
}
}
if (getLogLevel() == DEBUGLVL)
loglevel = LOG_DEBUG;
else
loglevel = LOG_INFO;
/* dhcp preferences are in /usr/include/libdhcp/dhcp_nic.h */
/* calling function should catch ipv4Choice & ipv6Choice both being ' ' */
if (FL_NOIPV4(flags) || dev->ipv4method == IPV4_MANUAL_METHOD) {
/* IPv4 disabled entirely -or- manual IPv4 config selected */
pref |= DHCPv4_DISABLE;
}
/* IPv6 enabled -and- auto neighbor discovery selected */
/* IPv6 disabled entirely -or- manual IPv6 config selected */
if ((!FL_NOIPV6(flags) && dev->ipv6method == IPV6_AUTO_METHOD) ||
(FL_NOIPV6(flags) || dev->ipv6method == IPV6_MANUAL_METHOD)) {
pref |= DHCPv6_DISABLE | DHCPv6_DISABLE_ADDRESSES;
}
/* disable some things for this DHCP call */
pref |= DHCPv6_DISABLE_RESOLVER | DHCPv4_DISABLE_HOSTNAME_SET;
/* don't try to run the client if DHCPv4 and DHCPv6 are disabled */
if (!(pref & DHCPv4_DISABLE) || !(pref & DHCPv6_DISABLE)){
logMessage(loglevel, "requesting dhcp timeout %ld", (long)timeout);
r = pumpDhcpClassRun(i,0L,class,pref,0,timeout,netlogger,loglevel);
}
/* set hostname if we have that */
if (dev->dev.hostname) {
if (sethostname(dev->dev.hostname, strlen(dev->dev.hostname))) {
logMessage(ERROR,"error setting hostname to %s",dev->dev.hostname);
}
}
return r;
}
int configureNetwork(struct networkDeviceConfig * dev) {
char *rc;
setupWireless(dev);
rc = pumpSetupInterface(&dev->dev);
if (rc != NULL) {
logMessage(INFO, "result of pumpSetupInterface is %s", rc);
return 1;
}
/* we need to wait for a link after setting up the interface as some
* switches decide to reconfigure themselves after that (#115825)
*/
waitForLink((char *)&dev->dev.device);
return 0;
}
int writeNetInfo(const char * fn, struct networkDeviceConfig * dev) {
FILE * f;
int i;
struct device ** devices;
char ret[48];
ip_addr_t *tip;
devices = getDevices(DEVICE_NETWORK);
if (!devices)
return 0;
for (i = 0; devices[i]; i++)
if (!strcmp(devices[i]->device, dev->dev.device)) break;
if (!(f = fopen(fn, "w"))) return -1;
fprintf(f, "DEVICE=%s\n", dev->dev.device);
fprintf(f, "ONBOOT=yes\n");
if (dev->isDynamic) {
fprintf(f, "BOOTPROTO=dhcp\n");
} else {
fprintf(f, "BOOTPROTO=static\n");
tip = &(dev->dev.ipv4);
inet_ntop(tip->sa_family, IP_ADDR(tip), ret, IP_STRLEN(tip));
fprintf(f, "IPADDR=%s\n", ret);
tip = &(dev->dev.netmask);
inet_ntop(tip->sa_family, IP_ADDR(tip), ret, IP_STRLEN(tip));
fprintf(f, "NETMASK=%s\n", ret);
if (dev->dev.set & PUMP_NETINFO_HAS_GATEWAY) {
tip = &(dev->dev.gateway);
inet_ntop(tip->sa_family, IP_ADDR(tip), ret, IP_STRLEN(tip));
fprintf(f, "GATEWAY=%s\n", ret);
}
if (dev->dev.set & PUMP_INTFINFO_HAS_BROADCAST) {
tip = &(dev->dev.broadcast);
inet_ntop(tip->sa_family, IP_ADDR(tip), ret, IP_STRLEN(tip));
fprintf(f, "BROADCAST=%s\n", ret);
}
}
if (!FL_NOIPV6(flags)) {
if (dev->ipv6method == IPV6_AUTO_METHOD) {
fprintf(f, "IPV6_AUTOCONF=yes\n");
} else if (dev->ipv6method == IPV6_DHCP_METHOD) {
fprintf(f, "IPV6ADDR=dhcp\n");
} else {
tip = &(dev->dev.ipv6);
inet_ntop(tip->sa_family, IP_ADDR(tip), ret, IP_STRLEN(tip));
fprintf(f, "IPV6ADDR=%s/%d\n", ret, dev->dev.ipv6_prefixlen);
}
}
if (dev->dev.set & PUMP_NETINFO_HAS_HOSTNAME)
fprintf(f, "HOSTNAME=%s\n", dev->dev.hostname);
if (dev->dev.set & PUMP_NETINFO_HAS_DOMAIN)
fprintf(f, "DOMAIN=%s\n", dev->dev.domain);
if (dev->mtu)
fprintf(f, "MTU=%d\n", dev->mtu);
if (dev->peerid)
fprintf(f, "PEERID=%s\n", dev->peerid);
if (dev->subchannels)
fprintf(f, "SUBCHANNELS=%s\n", dev->subchannels);
if (dev->portname)
fprintf(f, "PORTNAME=%s\n", dev->portname);
if (dev->nettype)
fprintf(f, "NETTYPE=%s\n", dev->nettype);
if (dev->ctcprot)
fprintf(f, "CTCPROT=%s\n", dev->ctcprot);
if (dev->essid)
fprintf(f, "ESSID=%s\n", dev->essid);
if (dev->wepkey)
fprintf(f, "KEY=%s\n", dev->wepkey);
fclose(f);
return 0;
}
int writeResolvConf(struct networkDeviceConfig * net) {
char * filename = "/etc/resolv.conf";
FILE * f;
int i;
char ret[48];
ip_addr_t *tip;
#if defined(__s390__) || defined(__s390x__)
return 0;
#endif
if (!(net->dev.set & PUMP_NETINFO_HAS_DOMAIN) && !net->dev.numDns)
return LOADER_ERROR;
f = fopen(filename, "w");
if (!f) {
logMessage(ERROR, "Cannot create %s: %s\n", filename, strerror(errno));
return LOADER_ERROR;
}
if (net->dev.set & PUMP_NETINFO_HAS_DOMAIN)
fprintf(f, "search %s\n", net->dev.domain);
for (i = 0; i < net->dev.numDns; i++) {
tip = &(net->dev.dnsServers[i]);
inet_ntop(tip->sa_family, IP_ADDR(tip), ret, IP_STRLEN(tip));
fprintf(f, "nameserver %s\n", ret);
}
fclose(f);
res_init(); /* reinit the resolver so DNS changes take affect */
return 0;
}
int findHostAndDomain(struct networkDeviceConfig * dev) {
char * name, * chptr;
char ret[48];
ip_addr_t *tip;
struct hostent *host;
if (!FL_TESTING(flags)) {
writeResolvConf(dev);
}
if (dev->dev.numDns == 0) {
logMessage(ERROR, "no DNS servers, can't look up hostname");
return 1;
}
if (!(dev->dev.set & PUMP_NETINFO_HAS_HOSTNAME)) {
if (!FL_CMDLINE(flags))
winStatus(50, 3, NULL,
_("Determining host name and domain..."));
else
printf("Determining host name and domain...\n");
tip = &(dev->dev.ip);
inet_ntop(tip->sa_family, IP_ADDR(tip), ret, IP_STRLEN(tip));
host = gethostbyaddr(IP_ADDR(tip), IP_STRLEN(tip), tip->sa_family);
if (!FL_CMDLINE(flags))
newtPopWindow();
if (!host) {
logMessage(WARNING, "reverse name lookup of %s failed", ret);
return 1;
}
name = strdup(host->h_name);
logMessage(INFO, "reverse name lookup worked (hostname is %s)", name);
dev->dev.hostname = strdup(name);
dev->dev.set |= PUMP_NETINFO_HAS_HOSTNAME;
} else {
name = dev->dev.hostname;
}
if (!(dev->dev.set & PUMP_NETINFO_HAS_DOMAIN)) {
for (chptr = name; *chptr && (*chptr != '.'); chptr++) ;
if (*chptr == '.') {
if (dev->dev.domain) free(dev->dev.domain);
dev->dev.domain = strdup(chptr + 1);
dev->dev.set |= PUMP_NETINFO_HAS_DOMAIN;
}
}
return 0;
}
void setKickstartNetwork(struct loaderData_s * loaderData, int argc,
char ** argv) {
char * arg, * bootProto = NULL, * device = NULL, *ethtool = NULL, * class = NULL;
char * essid = NULL, * wepkey = NULL, * onboot = NULL;
int noDns = 0, noksdev = 0, rc, mtu = 0, noipv4 = 0, noipv6 = 0, dhcpTimeout = -1;
poptContext optCon;
struct networkDeviceConfig cfg;
struct poptOption ksOptions[] = {
{ "bootproto", '\0', POPT_ARG_STRING, &bootProto, 0, NULL, NULL },
{ "device", '\0', POPT_ARG_STRING, &device, 0, NULL, NULL },
{ "dhcpclass", '\0', POPT_ARG_STRING, &class, 0, NULL, NULL },
{ "gateway", '\0', POPT_ARG_STRING, NULL, 'g', NULL, NULL },
{ "ip", '\0', POPT_ARG_STRING, NULL, 'i', NULL, NULL },
{ "mtu", '\0', POPT_ARG_INT, &mtu, 0, NULL, NULL },
{ "nameserver", '\0', POPT_ARG_STRING, NULL, 'n', NULL, NULL },
{ "netmask", '\0', POPT_ARG_STRING, NULL, 'm', NULL, NULL },
{ "noipv4", '\0', POPT_ARG_NONE, &noipv4, 0, NULL, NULL },
{ "noipv6", '\0', POPT_ARG_NONE, &noipv6, 0, NULL, NULL },
{ "nodns", '\0', POPT_ARG_NONE, &noDns, 0, NULL, NULL },
{ "hostname", '\0', POPT_ARG_STRING, NULL, 'h', NULL, NULL},
{ "ethtool", '\0', POPT_ARG_STRING, ðtool, 0, NULL, NULL },
{ "essid", '\0', POPT_ARG_STRING, &essid, 0, NULL, NULL },
{ "wepkey", '\0', POPT_ARG_STRING, &wepkey, 0, NULL, NULL },
{ "onboot", '\0', POPT_ARG_STRING, &onboot, 0, NULL, NULL },
{ "notksdevice", '\0', POPT_ARG_NONE, &noksdev, 0, NULL, NULL },
{ "dhcptimeout", '\0', POPT_ARG_INT, &dhcpTimeout, 0, NULL, NULL },
{ 0, 0, 0, 0, 0, 0, 0 }
};
optCon = poptGetContext(NULL, argc, (const char **) argv,
ksOptions, 0);
while ((rc = poptGetNextOpt(optCon)) >= 0) {
arg = (char *) poptGetOptArg(optCon);
switch (rc) {
case 'g':
loaderData->gateway = strdup(arg);
break;
case 'i':
loaderData->ipv4 = strdup(arg);
break;
case 'n':
loaderData->dns = strdup(arg);
break;
case 'm':
loaderData->netmask = strdup(arg);
break;
case 'h':
if (loaderData->hostname)
free(loaderData->hostname);
loaderData->hostname = strdup(arg);
break;
}
}
if (rc < -1) {
newtWinMessage(_("Kickstart Error"), _("OK"),
_("Bad argument to kickstart network command %s: %s"),
poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
poptStrerror(rc));
} else {
poptFreeContext(optCon);
}
/* if they've specified dhcp/bootp or haven't specified anything,
* use dhcp for the interface */
if ((bootProto && (!strncmp(bootProto, "dhcp", 4) ||
!strncmp(bootProto, "bootp", 4))) ||
(!bootProto && !loaderData->ipv4)) {
loaderData->ipv4 = strdup("dhcp");
loaderData->ipinfo_set = 1;
} else if (loaderData->ipv4) {
/* JKFIXME: this assumes a bit... */
loaderData->ipinfo_set = 1;
}
/* now make sure the specified bootproto is valid */
if (bootProto && strcmp(bootProto, "dhcp") && strcmp(bootProto, "bootp") &&
strcmp(bootProto, "static") && strcmp(bootProto, "query")) {
newtWinMessage(_("Kickstart Error"), _("OK"),
_("Bad bootproto %s specified in network command"),
bootProto);
}
if (!noksdev) {
if (device) {
loaderData->netDev = strdup(device);
loaderData->netDev_set = 1;
}
if (class) {
loaderData->netCls = strdup(class);
loaderData->netCls_set = 1;
}
if (ethtool) {
if (loaderData->ethtool)
free(loaderData->ethtool);
loaderData->ethtool = strdup(ethtool);
free(ethtool);
}
if (essid) {
if (loaderData->essid)
free(loaderData->essid);
loaderData->essid = strdup(essid);
free(essid);
}
if (wepkey) {
if (loaderData->wepkey)
free(loaderData->wepkey);
loaderData->wepkey = strdup(wepkey);
free(wepkey);
}
if (mtu) {
loaderData->mtu = mtu;
}
if (noipv4)
flags |= LOADER_FLAGS_NOIPV4;
if (noipv6)
flags |= LOADER_FLAGS_NOIPV6;
}
if (noDns) {
loaderData->noDns = 1;
}
/* Make sure the network is always up if there's a network line in the
* kickstart file, as %post/%pre scripts might require that.
*/
if (loaderData->method != METHOD_NFS && loaderData->method != METHOD_URL) {
initLoopback();
if (kickstartNetworkUp(loaderData, &cfg))
logMessage(ERROR, "unable to bring up network");
}
}
/* if multiple interfaces get one to use from user. */
/* NOTE - uses kickstart data available in loaderData */
int chooseNetworkInterface(struct loaderData_s * loaderData) {
int i, rc;
unsigned int max = 40;
int deviceNums = 0;
int deviceNum;
char ** devices;
char ** deviceNames;
int foundDev = 0;
struct device ** devs;
char * ksMacAddr = NULL;
devs = getDevices(DEVICE_NETWORK);
if (!devs) {
logMessage(ERROR, "no network devices in choose network device!");
return LOADER_ERROR;
}
for (i = 0; devs[i]; i++);
devices = alloca((i + 1) * sizeof(*devices));
deviceNames = alloca((i + 1) * sizeof(*devices));
if (loaderData->netDev && (loaderData->netDev_set) == 1) {
if ((loaderData->bootIf && (loaderData->bootIf_set) == 1) && !strcasecmp(loaderData->netDev, "bootif")) {
ksMacAddr = strdup(loaderData->bootIf);
} else {
ksMacAddr = strdup(loaderData->netDev);
}
ksMacAddr = str2upper(ksMacAddr);
}
for (i = 0; devs[i]; i++) {
if (!devs[i]->device)
continue;
/* require passing a flag for wireless while our wireless support
* sucks */
if (is_wireless_interface(devs[i]->device) && !FL_ALLOW_WIRELESS(flags))
continue;
if (devs[i]->description) {
deviceNames[deviceNums] = alloca(strlen(devs[i]->device) +
strlen(devs[i]->description) + 4);
sprintf(deviceNames[deviceNums],"%s - %s",
devs[i]->device, devs[i]->description);
if (strlen(deviceNames[deviceNums]) > max)
max = strlen(deviceNames[deviceNums]);
devices[deviceNums] = devs[i]->device;
} else {
devices[deviceNums] = devs[i]->device;
deviceNames[deviceNums] = devs[i]->device;
}
deviceNums++;
/* this device has been set and we don't really need to ask
* about it again... */
if (loaderData->netDev && (loaderData->netDev_set == 1)) {
if (!strcmp(loaderData->netDev, devs[i]->device)) {
foundDev = 1;
} else if (ksMacAddr != NULL) {
/* maybe it's a mac address */
char *devmacaddr = NULL;
devmacaddr = iface_mac2str(devs[i]->device);
if ((devmacaddr != NULL) && !strcmp(ksMacAddr, devmacaddr)) {
foundDev = 1;
free(loaderData->netDev);
loaderData->netDev = devs[i]->device;
if (devmacaddr != NULL)
free(devmacaddr);
break;
}
if (devmacaddr != NULL)
free(devmacaddr);
}
}
}
if (ksMacAddr)
free(ksMacAddr);
if (foundDev == 1)
return LOADER_NOOP;
devices[deviceNums] = NULL;
deviceNames[deviceNums] = NULL;
qsort(devices, deviceNums, sizeof(*devices), simpleStringCmp);
qsort(deviceNames, deviceNums, sizeof(*devices), simpleStringCmp);
/* ASSERT: we should *ALWAYS* have a network device when we get here */
if (!deviceNums) {
logMessage(CRITICAL, "no network device in chooseNetworkInterface");
return LOADER_ERROR;
}
/* JKFIXME: if we only have one interface and it doesn't have link,
* do we go ahead? */
if (deviceNums == 1) {
logMessage(INFO, "only have one network device: %s", devices[0]);
loaderData->netDev = devices[0];
return LOADER_NOOP;
}
if ((loaderData->netDev && (loaderData->netDev_set == 1)) &&
!strcmp(loaderData->netDev, "link")) {
logMessage(INFO, "looking for first netDev with link");
for (rc = 0; rc < 5; rc++) {
for (i = 0; i < deviceNums; i++) {
if (get_link_status(devices[i]) == 1) {
loaderData->netDev = devices[i];
logMessage(INFO, "%s has link, using it", devices[i]);
return LOADER_NOOP;
}
}
sleep(1);
}
logMessage(WARNING, "wanted netdev with link, but none present. prompting");
}
startNewt();
if (max > 70)
max = 70;
/* JKFIXME: should display link status */
deviceNum = 0;
rc = newtWinMenu(_("Networking Device"),
_("You have multiple network devices on this system. "
"Which would you like to install through?"), max, 10, 10,
deviceNums < 6 ? deviceNums : 6, deviceNames,
&deviceNum, _("OK"), _("Back"), NULL);
if (rc == 2)
return LOADER_BACK;
loaderData->netDev = devices[deviceNum];
/* turn off the non-active interface. this should keep things from
* breaking when we need the interface to do the install as long as
* you keep using that device */
for (i = 0; devs[i]; i++) {
if (strcmp(loaderData->netDev, devices[i]))
if (!FL_TESTING(flags))
pumpDisableInterface(devs[i]->device);
}
return LOADER_OK;
}
/* JKFIXME: bad name. this function brings up networking early on a
* kickstart install so that we can do things like grab the ks.cfg from
* the network */
int kickstartNetworkUp(struct loaderData_s * loaderData,
struct networkDeviceConfig *netCfgPtr) {
int rc;
/* we may have networking already, so return to the caller */
if ((loaderData->ipinfo_set == 1) || (loaderData->ipv6info_set == 1))
return 0;
initLoopback();
memset(netCfgPtr, 0, sizeof(*netCfgPtr));
do {
do {
/* this is smart and does the right thing based on whether or not
* we have ksdevice= specified */
rc = chooseNetworkInterface(loaderData);
if (rc == LOADER_ERROR) {
/* JKFIXME: ask for a driver disk? */
logMessage(ERROR, "no network drivers for doing kickstart");
return -1;
} else if (rc == LOADER_BACK) {
return -1;
}
/* insert device into pump structure */
strcpy(netCfgPtr->dev.device, loaderData->netDev);
break;
} while (1);
/* we don't want to end up asking about interface more than once
* if we're in a kickstart-ish case (#100724) */
loaderData->netDev_set = 1;
/* JKFIXME: this is kind of crufty, we depend on the fact that the
* ip is set and then just get the network up. we should probably
* add a way to do asking about static here and not be such a hack */
if (!loaderData->ipv4) {
loaderData->ipv4 = strdup("dhcp");
}
loaderData->ipinfo_set = 1;
setupNetworkDeviceConfig(netCfgPtr, loaderData);
rc = readNetConfig(loaderData->netDev, netCfgPtr, loaderData->netCls,
loaderData->method);
if (rc == LOADER_ERROR) {
logMessage(ERROR, "unable to setup networking");
return -1;
}
else if (rc == LOADER_BACK) {
/* Going back to the interface selection screen, so unset anything
* we set before attempting to bring the incorrect interface up.
*/
loaderData->netDev_set = 0;
free(loaderData->ipv4);
loaderData->ipinfo_set = 0;
}
else
break;
} while (1);
return 0;
}
void splitHostname (char *str, char **host, char **port)
{
char *rightbrack = strchr(str, ']');
*host = NULL;
*port = NULL;
if (*str == '[' && rightbrack) {
/* An IPv6 address surrounded by brackets, optionally with a colon and
* port number.
*/
char *colon = strrchr(rightbrack, ':');
if (colon) {
*host = strndup(str+1, rightbrack-1-str);
*port = strdup(colon+1);
}
else
*host = strndup(str+1, rightbrack-1-str);
} else if (strcount(str, ':') > 1) {
/* An IPv6 address without brackets. Don't make the user surround the
* address with brackets if there's no port number.
*/
*host = strdup(str);
} else {
/* An IPv4 address, optionally with a colon and port number. */
char *colon = strrchr(str, ':');
if (colon) {
*host = strndup(str, colon-str);
*port = strdup(colon+1);
}
else
*host = strdup(str);
}
}
/* vim:set shiftwidth=4 softtabstop=4: */