tcpip.c revision 111644
1105197Ssam/* 2105197Ssam * $FreeBSD: head/usr.sbin/sysinstall/tcpip.c 111644 2003-02-27 21:04:34Z sobomax $ 3105197Ssam * 4105197Ssam * Copyright (c) 1995 5105197Ssam * Gary J Palmer. All rights reserved. 6105197Ssam * Copyright (c) 1996 7105197Ssam * Jordan K. Hubbard. All rights reserved. 8105197Ssam * 9105197Ssam * Redistribution and use in source and binary forms, with or without 10105197Ssam * modification, are permitted provided that the following conditions 11105197Ssam * are met: 12105197Ssam * 1. Redistributions of source code must retain the above copyright 13105197Ssam * notice, this list of conditions and the following disclaimer, 14105197Ssam * verbatim and that no modifications are made prior to this 15105197Ssam * point in the file. 16105197Ssam * 2. Redistributions in binary form must reproduce the above copyright 17105197Ssam * notice, this list of conditions and the following disclaimer in the 18105197Ssam * documentation and/or other materials provided with the distribution. 19105197Ssam * 20105197Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 21105197Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22105197Ssam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23105197Ssam * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 24105197Ssam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 25105197Ssam * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 26105197Ssam * OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 27105197Ssam * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 28105197Ssam * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29105197Ssam * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30105197Ssam * 31105197Ssam */ 32105197Ssam 33105197Ssam/* 34105197Ssam * All kinds of hacking also performed by jkh on this code. Don't 35105197Ssam * blame Gary for every bogosity you see here.. :-) 36105197Ssam * 37105197Ssam * -jkh 38105197Ssam */ 39105197Ssam 40105197Ssam#include "sysinstall.h" 41105197Ssam#include <sys/param.h> 42105197Ssam#include <sys/sysctl.h> 43105197Ssam#include <sys/socket.h> 44105197Ssam#include <netinet/in.h> 45119643Ssam#include <netdb.h> 46119643Ssam 47105197Ssam/* The help file for the TCP/IP setup screen */ 48105197Ssam#define TCP_HELPFILE "tcp" 49105197Ssam 50105197Ssam/* These are nasty, but they make the layout structure a lot easier ... */ 51105197Ssam 52105197Ssamstatic char hostname[HOSTNAME_FIELD_LEN], domainname[HOSTNAME_FIELD_LEN], 53105197Ssam gateway[IPADDR_FIELD_LEN], nameserver[INET6_ADDRSTRLEN]; 54105197Ssamstatic int okbutton, cancelbutton; 55105197Ssamstatic char ipaddr[IPADDR_FIELD_LEN], netmask[IPADDR_FIELD_LEN], extras[EXTRAS_FIELD_LEN]; 56105197Ssamstatic char ipv6addr[INET6_ADDRSTRLEN]; 57105197Ssam 58105197Ssam/* What the screen size is meant to be */ 59105197Ssam#define TCP_DIALOG_Y 0 60105197Ssam#define TCP_DIALOG_X 8 61105197Ssam#define TCP_DIALOG_WIDTH COLS - 16 62105197Ssam#define TCP_DIALOG_HEIGHT LINES - 2 63105197Ssam 64105197Ssamstatic Layout layout[] = { 65105197Ssam#define LAYOUT_HOSTNAME 0 66105197Ssam { 1, 2, 25, HOSTNAME_FIELD_LEN - 1, 67105197Ssam "Host:", "Your fully-qualified hostname, e.g. foo.bar.com", 68105197Ssam hostname, STRINGOBJ, NULL }, 69105197Ssam#define LAYOUT_DOMAINNAME 1 70105197Ssam { 1, 35, 20, HOSTNAME_FIELD_LEN - 1, 71105197Ssam "Domain:", 72105197Ssam "The name of the domain that your machine is in, e.g. bar.com", 73105197Ssam domainname, STRINGOBJ, NULL }, 74105197Ssam#define LAYOUT_GATEWAY 2 75105197Ssam { 5, 2, 18, IPADDR_FIELD_LEN - 1, 76105197Ssam "IPv4 Gateway:", 77105197Ssam "IPv4 address of host forwarding packets to non-local destinations", 78105197Ssam gateway, STRINGOBJ, NULL }, 79105197Ssam#define LAYOUT_NAMESERVER 3 80105197Ssam { 5, 35, 18, INET6_ADDRSTRLEN - 1, 81105197Ssam "Name server:", "IPv4 or IPv6 address of your local DNS server", 82105197Ssam nameserver, STRINGOBJ, NULL }, 83105197Ssam#define LAYOUT_IPADDR 4 84105197Ssam { 10, 10, 18, IPADDR_FIELD_LEN - 1, 85105197Ssam "IPv4 Address:", 86105197Ssam "The IPv4 address to be used for this interface", 87105197Ssam ipaddr, STRINGOBJ, NULL }, 88105197Ssam#define LAYOUT_NETMASK 5 89105197Ssam { 10, 35, 18, IPADDR_FIELD_LEN - 1, 90105197Ssam "Netmask:", 91105197Ssam "The netmask for this interface, e.g. 0xffffff00 for a class C network", 92105197Ssam netmask, STRINGOBJ, NULL }, 93105197Ssam#define LAYOUT_EXTRAS 6 94105197Ssam { 14, 10, 37, HOSTNAME_FIELD_LEN - 1, 95105197Ssam "Extra options to ifconfig:", 96105197Ssam "Any interface-specific options to ifconfig you would like to add", 97105197Ssam extras, STRINGOBJ, NULL }, 98105197Ssam#define LAYOUT_OKBUTTON 7 99105197Ssam { 19, 15, 0, 0, 100105197Ssam "OK", "Select this if you are happy with these settings", 101105197Ssam &okbutton, BUTTONOBJ, NULL }, 102105197Ssam#define LAYOUT_CANCELBUTTON 8 103105197Ssam { 19, 35, 0, 0, 104105197Ssam "CANCEL", "Select this if you wish to cancel this screen", 105105197Ssam &cancelbutton, BUTTONOBJ, NULL }, 106105197Ssam { NULL }, 107105197Ssam}; 108105197Ssam 109105197Ssam#define _validByte(b) ((b) >= 0 && (b) <= 255) 110105197Ssam 111105197Ssam/* whine */ 112105197Ssamstatic void 113105197Ssamfeepout(char *msg) 114105197Ssam{ 115105197Ssam beep(); 116105197Ssam msgConfirm("%s", msg); 117105197Ssam} 118105197Ssam 119105197Ssam/* Verify IP address integrity */ 120105197Ssamstatic int 121105197SsamverifyIP(char *ip, unsigned long *mask, unsigned long *out) 122105197Ssam{ 123105197Ssam long a, b, c, d; 124105197Ssam char *endptr; 125105197Ssam 126105197Ssam unsigned long parsedip; 127119643Ssam unsigned long max_addr = (255 << 24) | (255 << 16) | (255 << 8) | 255; 128120585Ssam 129120585Ssam if (ip == NULL) 130120585Ssam return 0; 131120585Ssam a = strtol(ip, &endptr, 10); 132120585Ssam if (*endptr++ != '.') 133120585Ssam return 0; 134120585Ssam b = strtol(endptr, &endptr, 10); 135120585Ssam if (*endptr++ != '.') 136105197Ssam return 0; 137119643Ssam c = strtol(endptr, &endptr, 10); 138120585Ssam if (*endptr++ != '.') 139120585Ssam return 0; 140120585Ssam d = strtol(endptr, &endptr, 10); 141120585Ssam if (*endptr != '\0') 142120585Ssam return 0; 143120585Ssam if (!_validByte(a) || !_validByte(b) || !_validByte(c) || !_validByte(d)) 144120585Ssam return 0; 145120585Ssam parsedip = (a << 24) | (b << 16) | (c << 8) | d; 146119643Ssam if (out) 147105197Ssam *out = parsedip; 148119643Ssam /* 149120585Ssam * The ip address must not be network or broadcast address. 150120585Ssam */ 151120585Ssam if (mask && ((parsedip == (parsedip & *mask)) || 152120585Ssam (parsedip == ((parsedip & *mask) + max_addr - *mask)))) 153120585Ssam return 0; 154120585Ssam return 1; 155120585Ssam} 156105197Ssam 157119643Ssamstatic int 158120585SsamverifyIP6(char *ip) 159120585Ssam{ 160120585Ssam struct addrinfo hints, *res; 161120585Ssam 162120585Ssam memset(&hints, 0, sizeof(hints)); 163120585Ssam hints.ai_family = AF_INET6; 164120585Ssam hints.ai_socktype = SOCK_STREAM; 165105197Ssam hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; 166119643Ssam if (getaddrinfo(ip, NULL, &hints, &res) == 0) { 167120585Ssam freeaddrinfo(res); 168120585Ssam return 1; 169120585Ssam } 170120585Ssam return 0; 171120585Ssam} 172120585Ssam 173120585Ssam/* Verify IPv4 netmask as being well-formed as 174105197Ssam a 0x or AAA.BBB.CCC.DDD mask */ 175105197Ssamstatic int 176105197SsamverifyNetmask(const char *netmask, unsigned long *out) 177105197Ssam{ 178105197Ssam unsigned long mask; 179108533Sschweikh unsigned long tmp; 180105197Ssam char *endptr; 181105197Ssam 182105197Ssam if (netmask[0] == '0' && (netmask[1] == 'x' || netmask[1] == 'X')) { 183105197Ssam /* Parse out hex mask */ 184105197Ssam mask = strtoul(netmask, &endptr, 0); 185105197Ssam if (*endptr != '\0') 186105197Ssam return 0; 187105197Ssam } else { 188105197Ssam /* Parse out quad decimal mask */ 189105197Ssam mask = strtoul(netmask, &endptr, 10); 190105197Ssam if (!_validByte(mask) || *endptr++ != '.') 191105197Ssam return 0; 192105197Ssam tmp = strtoul(endptr, &endptr, 10); 193105197Ssam if (!_validByte(tmp) || *endptr++ != '.') 194105197Ssam return 0; 195105197Ssam mask = (mask << 8) + tmp; 196105197Ssam tmp = strtoul(endptr, &endptr, 10); 197105197Ssam if (!_validByte(tmp) || *endptr++ != '.') 198105197Ssam return 0; 199105197Ssam mask = (mask << 8) + tmp; 200105197Ssam tmp = strtoul(endptr, &endptr, 10); 201105197Ssam if (!_validByte(tmp) || *endptr++ != '\0') 202105197Ssam return 0; 203105197Ssam mask = (mask << 8) + tmp; 204105197Ssam } 205105197Ssam /* Verify that we have a continous netmask */ 206105197Ssam if ((((-mask & mask) - 1) | mask) != 0xffffffff) 207105197Ssam return 0; 208105197Ssam if (out) 209105197Ssam *out = mask; 210105197Ssam return 1; 211105197Ssam} 212105197Ssam 213105197Ssamstatic int 214105197SsamverifyGW(char *gw, unsigned long *ip, unsigned long *mask) 215105197Ssam{ 216105197Ssam unsigned long parsedgw; 217105197Ssam 218105197Ssam if (!verifyIP(gw, mask, &parsedgw)) 219105197Ssam return 0; 220105197Ssam /* Gateway needs to be within the set of IPs reachable through the 221105197Ssam interface */ 222105197Ssam if (ip && mask && ((parsedgw & *mask) != (*ip & *mask))) 223105197Ssam return 0; 224105197Ssam return 1; 225105197Ssam} 226105197Ssam 227105197Ssam/* Check for the settings on the screen - the per-interface stuff is 228105197Ssam moved to the main handling code now to do it on the fly - sigh */ 229105197Ssamstatic int 230105197SsamverifySettings(void) 231105197Ssam{ 232105197Ssam unsigned long parsedip; 233105197Ssam unsigned long parsednetmask; 234105197Ssam 235105197Ssam if (!hostname[0]) 236105197Ssam feepout("Must specify a host name of some sort!"); 237105197Ssam else if (netmask[0] && !verifyNetmask(netmask, &parsednetmask)) 238105197Ssam feepout("Invalid netmask value"); 239105197Ssam else if (nameserver[0] && !verifyIP(nameserver, NULL, NULL) && 240105197Ssam !verifyIP6(nameserver)) 241105197Ssam feepout("Invalid name server IP address specified"); 242105197Ssam else if (ipaddr[0] && !verifyIP(ipaddr, &parsednetmask, &parsedip)) 243105197Ssam feepout("Invalid IPv4 address"); 244105197Ssam else if (gateway[0] && strcmp(gateway, "NO") && 245105197Ssam !verifyGW(gateway, ipaddr[0] ? &parsedip : NULL, 246105197Ssam netmask[0] ? &parsednetmask : NULL)) 247105197Ssam feepout("Invalid gateway IPv4 address specified"); 248105197Ssam else 249105197Ssam return 1; 250105197Ssam return 0; 251105197Ssam} 252105197Ssam 253105197Ssamstatic void 254105197SsamdhcpGetInfo(Device *devp) 255105197Ssam{ 256105197Ssam /* If it fails, do it the old-fashioned way */ 257105197Ssam if (dhcpParseLeases("/var/db/dhclient.leases", hostname, domainname, 258105197Ssam nameserver, ipaddr, gateway, netmask) == -1) { 259105197Ssam FILE *ifp; 260105197Ssam char *cp, cmd[256], data[2048]; 261105197Ssam int i, j; 262105197Ssam 263105197Ssam /* Bah, now we have to kludge getting the information from ifconfig */ 264105197Ssam snprintf(cmd, sizeof cmd, "ifconfig %s", devp->name); 265105197Ssam ifp = popen(cmd, "r"); 266105197Ssam if (ifp) { 267105197Ssam j = fread(data, 1, sizeof(data), ifp); 268105197Ssam fclose(ifp); 269105197Ssam if (j < 0) /* paranoia */ 270105197Ssam j = 0; 271105197Ssam data[j] = '\0'; 272105197Ssam if (isDebug()) 273105197Ssam msgDebug("DHCP configured interface returns %s\n", data); 274105197Ssam /* XXX This is gross as it assumes a certain ordering to 275105197Ssam ifconfig's output! XXX */ 276105197Ssam if ((cp = strstr(data, "inet ")) != NULL) { 277105197Ssam i = 0; 278105197Ssam cp += 5; /* move over keyword */ 279105197Ssam while (*cp != ' ') 280105197Ssam ipaddr[i++] = *(cp++); 281105197Ssam ipaddr[i] = '\0'; 282105197Ssam if (!strncmp(++cp, "netmask", 7)) { 283105197Ssam i = 0; 284105197Ssam cp += 8; 285105197Ssam while (*cp != ' ') 286105197Ssam netmask[i++] = *(cp++); 287105197Ssam netmask[i] = '\0'; 288105197Ssam } 289105197Ssam } 290105197Ssam } 291105197Ssam } 292105197Ssam 293105197Ssam /* If we didn't get a name server value, hunt for it in resolv.conf */ 294105197Ssam if (!nameserver[0] && file_readable("/etc/resolv.conf")) 295105197Ssam configEnvironmentResolv("/etc/resolv.conf"); 296105197Ssam if (hostname[0]) 297105197Ssam variable_set2(VAR_HOSTNAME, hostname, 0); 298105197Ssam} 299105197Ssam 300105197Ssamstatic void 301105197SsamrtsolGetInfo(Device *devp) 302105197Ssam{ 303105197Ssam FILE *ifp; 304105197Ssam char *cp, cmd[256], data[2048]; 305105197Ssam int i; 306105197Ssam 307105197Ssam snprintf(cmd, sizeof cmd, "ifconfig %s", devp->name); 308105197Ssam if ((ifp = popen(cmd, "r")) == NULL) 309105197Ssam return; 310105197Ssam while (fgets(data, sizeof(data), ifp) != NULL) { 311105197Ssam if (isDebug()) 312105197Ssam msgDebug("RTSOL configured interface returns %s\n", data); 313105197Ssam if ((cp = strstr(data, "inet6 ")) != NULL) { 314105197Ssam cp += 6; /* move over keyword */ 315105197Ssam if (strncmp(cp, "fe80:", 5)) { 316105197Ssam i = 0; 317105197Ssam while (*cp != ' ') 318105197Ssam ipv6addr[i++] = *(cp++); 319105197Ssam ipv6addr[i] = '\0'; 320105197Ssam } 321105197Ssam } 322105197Ssam } 323105197Ssam fclose(ifp); 324119643Ssam} 325119643Ssam 326119643Ssam/* This is it - how to get TCP setup values */ 327119643Ssamint 328119643SsamtcpOpenDialog(Device *devp) 329119643Ssam{ 330119643Ssam WINDOW *ds_win, *save = NULL; 331105197Ssam ComposeObj *obj = NULL; 332105197Ssam int n = 0, filled = 0, cancel = FALSE; 333105197Ssam int max, ret = DITEM_SUCCESS; 334105197Ssam int use_dhcp = FALSE; 335105197Ssam int use_rtsol = FALSE; 336105197Ssam char *tmp; 337105197Ssam char title[80]; 338105197Ssam 339105197Ssam save = savescr(); 340105197Ssam /* Initialise vars from previous device values */ 341105197Ssam if (devp->private) { 342105197Ssam DevInfo *di = (DevInfo *)devp->private; 343105197Ssam 344105197Ssam SAFE_STRCPY(ipaddr, di->ipaddr); 345105197Ssam SAFE_STRCPY(netmask, di->netmask); 346105197Ssam SAFE_STRCPY(extras, di->extras); 347105197Ssam use_dhcp = di->use_dhcp; 348105197Ssam use_rtsol = di->use_rtsol; 349105197Ssam } 350105197Ssam else { /* See if there are any defaults */ 351105197Ssam char *cp; 352105197Ssam char *old_interactive = NULL; 353105197Ssam 354105197Ssam /* 355105197Ssam * This is a hack so that the dialogs below are interactive in a 356105197Ssam * script if we have requested interactive behavior. 357105197Ssam */ 358105197Ssam if (variable_get(VAR_NONINTERACTIVE) && 359105197Ssam variable_get(VAR_NETINTERACTIVE)) { 360105197Ssam old_interactive = strdup(VAR_NONINTERACTIVE); 361105197Ssam variable_unset(VAR_NONINTERACTIVE); 362105197Ssam } 363105197Ssam 364105197Ssam 365105197Ssam /* 366105197Ssam * Try a RTSOL scan if such behavior is desired. 367105197Ssam * If the variable was configured and is YES, do it. 368105197Ssam * If it was configured to anything else, treat it as NO. 369105197Ssam * Otherwise, ask the question interactively. 370105197Ssam */ 371105197Ssam if (!variable_get(VAR_NO_INET6) && 372105197Ssam (!variable_cmp(VAR_TRY_RTSOL, "YES") || 373105197Ssam (variable_get(VAR_TRY_RTSOL)==0 && !msgNoYes("Do you want to try IPv6 configuration of the interface?")))) { 374105197Ssam int i; 375105197Ssam size_t len; 376105197Ssam 377105197Ssam i = 0; 378119643Ssam sysctlbyname("net.inet6.ip6.forwarding", NULL, 0, &i, sizeof(i)); 379105197Ssam i = 1; 380105197Ssam sysctlbyname("net.inet6.ip6.accept_rtadv", NULL, 0, &i, sizeof(i)); 381105197Ssam vsystem("ifconfig %s up", devp->name); 382105197Ssam len = sizeof(i); 383105197Ssam sysctlbyname("net.inet6.ip6.dad_count", &i, &len, NULL, 0); 384105197Ssam sleep(i + 1); 385105197Ssam Mkdir("/var/run"); 386105197Ssam msgNotify("Scanning for RA servers..."); 387105197Ssam if (0 == vsystem("rtsol %s", devp->name)) { 388105197Ssam len = sizeof(i); 389105197Ssam sysctlbyname("net.inet6.ip6.dad_count", &i, &len, NULL, 0); 390105197Ssam sleep(i + 1); 391105197Ssam rtsolGetInfo(devp); 392105197Ssam use_rtsol = TRUE; 393105197Ssam } else 394105197Ssam use_rtsol = FALSE; 395105197Ssam } 396105197Ssam 397105197Ssam 398105197Ssam /* 399105197Ssam * First try a DHCP scan if such behavior is desired. 400105197Ssam * If the variable was configured and is YES, do it. 401105197Ssam * If it was configured to anything else, treat it as NO. 402105197Ssam * Otherwise, ask the question interactively. 403105197Ssam */ 404105197Ssam if (!variable_cmp(VAR_TRY_DHCP, "YES") || 405105197Ssam (variable_get(VAR_TRY_DHCP)==0 && !msgNoYes("Do you want to try DHCP configuration of the interface?"))) { 406105197Ssam Mkdir("/var/db"); 407105197Ssam Mkdir("/var/run"); 408105197Ssam Mkdir("/tmp"); 409105197Ssam msgNotify("Scanning for DHCP servers..."); 410105197Ssam vsystem("dhclient -r %s", devp->name); 411105197Ssam if (0 == vsystem("dhclient -1 %s", devp->name)) { 412105197Ssam dhcpGetInfo(devp); 413105197Ssam use_dhcp = TRUE; 414105197Ssam } 415105197Ssam else 416105197Ssam use_dhcp = FALSE; 417105197Ssam } 418105197Ssam 419105197Ssam /* Restore old VAR_NONINTERACTIVE if needed. */ 420105197Ssam if (old_interactive != NULL) { 421105197Ssam variable_set2(VAR_NONINTERACTIVE, old_interactive, 0); 422105197Ssam free(old_interactive); 423105197Ssam } 424119643Ssam 425105197Ssam /* Special hack so it doesn't show up oddly in the tcpip setup menu */ 426105197Ssam if (!strcmp(gateway, "NO")) 427105197Ssam gateway[0] = '\0'; 428105197Ssam 429105197Ssam /* Get old IP address from variable space, if available */ 430105197Ssam if (!ipaddr[0]) { 431105197Ssam if ((cp = variable_get(VAR_IPADDR)) != NULL) 432105197Ssam SAFE_STRCPY(ipaddr, cp); 433105197Ssam else if ((cp = variable_get(string_concat3(devp->name, "_", VAR_IPADDR))) != NULL) 434105197Ssam SAFE_STRCPY(ipaddr, cp); 435105197Ssam } 436105197Ssam 437105197Ssam /* Get old netmask from variable space, if available */ 438105197Ssam if (!netmask[0]) { 439105197Ssam if ((cp = variable_get(VAR_NETMASK)) != NULL) 440105197Ssam SAFE_STRCPY(netmask, cp); 441105197Ssam else if ((cp = variable_get(string_concat3(devp->name, "_", VAR_NETMASK))) != NULL) 442105197Ssam SAFE_STRCPY(netmask, cp); 443105197Ssam } 444105197Ssam 445105197Ssam /* Get old extras string from variable space, if available */ 446105197Ssam if (!extras[0]) { 447105197Ssam if ((cp = variable_get(VAR_EXTRAS)) != NULL) 448105197Ssam SAFE_STRCPY(extras, cp); 449105197Ssam else if ((cp = variable_get(string_concat3(devp->name, "_", VAR_EXTRAS))) != NULL) 450105197Ssam SAFE_STRCPY(extras, cp); 451105197Ssam } 452105197Ssam } 453105197Ssam 454105197Ssam /* Look up values already recorded with the system, or blank the string variables ready to accept some new data */ 455105197Ssam if (!hostname[0]) { 456105197Ssam tmp = variable_get(VAR_HOSTNAME); 457105197Ssam if (tmp) 458105197Ssam SAFE_STRCPY(hostname, tmp); 459105197Ssam } 460105197Ssam if (!domainname[0]) { 461105197Ssam tmp = variable_get(VAR_DOMAINNAME); 462105197Ssam if (tmp) 463105197Ssam SAFE_STRCPY(domainname, tmp); 464105197Ssam } 465105197Ssam if (!gateway[0]) { 466105197Ssam tmp = variable_get(VAR_GATEWAY); 467105197Ssam if (tmp && strcmp(tmp, "NO")) 468105197Ssam SAFE_STRCPY(gateway, tmp); 469105197Ssam } 470105197Ssam if (!nameserver[0]) { 471105197Ssam tmp = variable_get(VAR_NAMESERVER); 472105197Ssam if (tmp) 473105197Ssam SAFE_STRCPY(nameserver, tmp); 474105197Ssam } 475105197Ssam 476105197Ssam /* If non-interactive, jump straight over the dialog crap and into config section */ 477105197Ssam if (variable_get(VAR_NONINTERACTIVE) && 478105197Ssam !variable_get(VAR_NETINTERACTIVE)) { 479105197Ssam if (!hostname[0]) 480105197Ssam msgConfirm("WARNING: hostname variable not set and is a non-optional\n" 481105197Ssam "parameter. Please add this to your installation script\n" 482105197Ssam "or set the netInteractive variable (see sysinstall man page)"); 483105197Ssam else 484105197Ssam goto netconfig; 485105197Ssam } 486105197Ssam 487105197Ssam /* Now do all the screen I/O */ 488105197Ssam dialog_clear_norefresh(); 489105197Ssam 490105197Ssam /* Modify the help line for PLIP config */ 491105197Ssam if (!strncmp(devp->name, "lp", 2)) 492105197Ssam layout[LAYOUT_EXTRAS].help = 493105197Ssam "For PLIP configuration, you must enter the peer's IP address here."; 494105197Ssam 495105197Ssam /* We need a curses window */ 496105197Ssam tmp = " Network Configuration "; 497105197Ssam if (ipv6addr[0]) 498105197Ssam tmp = string_concat(tmp, "(IPv6 ready) "); 499105197Ssam if (!(ds_win = openLayoutDialog(TCP_HELPFILE, tmp, 500105197Ssam TCP_DIALOG_X, TCP_DIALOG_Y, TCP_DIALOG_WIDTH, TCP_DIALOG_HEIGHT))) { 501120585Ssam beep(); 502105197Ssam msgConfirm("Cannot open TCP/IP dialog window!!"); 503105197Ssam restorescr(save); 504120585Ssam return DITEM_FAILURE; 505105197Ssam } 506105197Ssam 507105197Ssam /* Draw interface configuration box */ 508105197Ssam draw_box(ds_win, TCP_DIALOG_Y + 9, TCP_DIALOG_X + 8, TCP_DIALOG_HEIGHT - 13, TCP_DIALOG_WIDTH - 17, 509105197Ssam dialog_attr, border_attr); 510120585Ssam wattrset(ds_win, dialog_attr); 511105197Ssam sprintf(title, " Configuration for Interface %s ", devp->name); 512105197Ssam mvwaddstr(ds_win, TCP_DIALOG_Y + 9, TCP_DIALOG_X + 14, title); 513120585Ssam 514105197Ssam /* Some more initialisation before we go into the main input loop */ 515105197Ssam obj = initLayoutDialog(ds_win, layout, TCP_DIALOG_X, TCP_DIALOG_Y, &max); 516105197Ssam 517105197Ssamreenter: 518105197Ssam cancelbutton = okbutton = 0; 519105197Ssam while (layoutDialogLoop(ds_win, layout, &obj, &n, max, &cancelbutton, &cancel)) { 520105197Ssam /* Prevent this from being irritating if user really means NO */ 521105197Ssam if (filled < 3) { 522105197Ssam /* Insert a default value for the netmask, 0xffffff00 is 523105197Ssam * the most appropriate one (entire class C, or subnetted 524105197Ssam * class A/B network). 525105197Ssam */ 526105197Ssam if (!netmask[0]) { 527105197Ssam strcpy(netmask, "255.255.255.0"); 528105197Ssam RefreshStringObj(layout[LAYOUT_NETMASK].obj); 529105197Ssam ++filled; 530105197Ssam } 531105197Ssam if (!index(hostname, '.') && domainname[0]) { 532105197Ssam strcat(hostname, "."); 533105197Ssam strcat(hostname, domainname); 534105197Ssam RefreshStringObj(layout[LAYOUT_HOSTNAME].obj); 535105197Ssam ++filled; 536105197Ssam } 537105197Ssam else if (((tmp = index(hostname, '.')) != NULL) && !domainname[0]) { 538105197Ssam SAFE_STRCPY(domainname, tmp + 1); 539105197Ssam RefreshStringObj(layout[LAYOUT_DOMAINNAME].obj); 540105197Ssam ++filled; 541120585Ssam } 542120585Ssam } 543120585Ssam } 544105197Ssam if (!cancel && !verifySettings()) 545105197Ssam goto reenter; 546120585Ssam 547105197Ssam /* Clear this crap off the screen */ 548105197Ssam delwin(ds_win); 549105197Ssam dialog_clear_norefresh(); 550105197Ssam use_helpfile(NULL); 551105197Ssam 552105197Ssam /* We actually need to inform the rest of sysinstall about this 553120585Ssam data now if the user hasn't selected cancel. Save the stuff 554105197Ssam out to the environment via the variable_set() mechanism */ 555105197Ssam 556105197Ssamnetconfig: 557105197Ssam if (!cancel) { 558105197Ssam DevInfo *di; 559105197Ssam char temp[512], ifn[255]; 560105197Ssam char *pccard; 561105197Ssam int ipv4_enable = FALSE; 562105197Ssam 563105197Ssam if (hostname[0]) { 564105197Ssam variable_set2(VAR_HOSTNAME, hostname, 1); 565105197Ssam sethostname(hostname, strlen(hostname)); 566105197Ssam } 567105197Ssam if (domainname[0]) 568120585Ssam variable_set2(VAR_DOMAINNAME, domainname, 0); 569105197Ssam if (gateway[0]) 570105197Ssam variable_set2(VAR_GATEWAY, gateway, use_dhcp ? 0 : 1); 571105197Ssam if (nameserver[0]) 572105197Ssam variable_set2(VAR_NAMESERVER, nameserver, 0); 573105197Ssam if (ipaddr[0]) 574120585Ssam variable_set2(VAR_IPADDR, ipaddr, 0); 575105197Ssam if (ipv6addr[0]) 576105197Ssam variable_set2(VAR_IPV6ADDR, ipv6addr, 0); 577120585Ssam 578105197Ssam if (!devp->private) 579105197Ssam devp->private = (DevInfo *)safe_malloc(sizeof(DevInfo)); 580105197Ssam di = devp->private; 581105197Ssam SAFE_STRCPY(di->ipaddr, ipaddr); 582105197Ssam SAFE_STRCPY(di->netmask, netmask); 583105197Ssam SAFE_STRCPY(di->extras, extras); 584105197Ssam di->use_dhcp = use_dhcp; 585105197Ssam di->use_rtsol = use_rtsol; 586105197Ssam 587105197Ssam if (use_dhcp || ipaddr[0]) 588105197Ssam ipv4_enable = TRUE; 589105197Ssam if (ipv4_enable) { 590105197Ssam sprintf(ifn, "%s%s", VAR_IFCONFIG, devp->name); 591105197Ssam if (use_dhcp) 592105197Ssam sprintf(temp, "DHCP"); 593105197Ssam else 594105197Ssam sprintf(temp, "inet %s %s netmask %s", 595105197Ssam ipaddr, extras, netmask); 596105197Ssam variable_set2(ifn, temp, 1); 597120585Ssam } 598120585Ssam#ifdef PCCARD_ARCH 599120585Ssam pccard = variable_get("_pccard_install"); 600105197Ssam if (pccard && strcmp(pccard, "YES") == 0 && ipv4_enable) { 601105197Ssam variable_set2("pccard_ifconfig", temp, 1); 602120585Ssam } 603105197Ssam#endif 604105197Ssam if (use_rtsol) 605105197Ssam variable_set2(VAR_IPV6_ENABLE, "YES", 1); 606105197Ssam if (!use_dhcp) 607105197Ssam configResolv(NULL); /* XXX this will do it on the MFS copy XXX */ 608105197Ssam ret = DITEM_SUCCESS; 609105197Ssam } 610120585Ssam else 611105197Ssam ret = DITEM_FAILURE; 612105197Ssam restorescr(save); 613105197Ssam return ret; 614105197Ssam} 615105197Ssam 616105197Ssamstatic Device *NetDev; 617105197Ssam 618105197Ssamstatic int 619105197SsamnetHook(dialogMenuItem *self) 620105197Ssam{ 621105197Ssam Device **devs; 622105197Ssam 623105197Ssam devs = deviceFindDescr(self->prompt, self->title, DEVICE_TYPE_NETWORK); 624105197Ssam if (devs) { 625105197Ssam if (DITEM_STATUS(tcpOpenDialog(devs[0])) != DITEM_FAILURE) 626105197Ssam NetDev = devs[0]; 627105197Ssam else 628105197Ssam NetDev = NULL; 629105197Ssam } 630105197Ssam return devs ? DITEM_LEAVE_MENU : DITEM_FAILURE; 631120585Ssam} 632105197Ssam 633105197Ssam/* Get a network device */ 634105197SsamDevice * 635105197SsamtcpDeviceSelect(void) 636105197Ssam{ 637120585Ssam DMenu *menu; 638105197Ssam Device **devs, *rval; 639105197Ssam int cnt; 640120585Ssam 641105197Ssam devs = deviceFind(variable_get(VAR_NETWORK_DEVICE), DEVICE_TYPE_NETWORK); 642105197Ssam cnt = deviceCount(devs); 643105197Ssam rval = NULL; 644105197Ssam 645105197Ssam if (!cnt) { 646105197Ssam msgConfirm("No network devices available!"); 647105197Ssam return NULL; 648105197Ssam } 649105197Ssam else if ((!RunningAsInit) && (variable_check("NETWORK_CONFIGURED=NO") != TRUE)) { 650105197Ssam if (!msgYesNo("Running multi-user, assume that the network is already configured?")) 651105197Ssam return devs[0]; 652105197Ssam } 653105197Ssam if (cnt == 1) { 654105197Ssam if (DITEM_STATUS(tcpOpenDialog(devs[0]) == DITEM_SUCCESS)) 655105197Ssam rval = devs[0]; 656105197Ssam } 657105197Ssam else if (variable_get(VAR_NONINTERACTIVE) && variable_get(VAR_NETWORK_DEVICE)) { 658105197Ssam devs = deviceFind(variable_get(VAR_NETWORK_DEVICE), DEVICE_TYPE_NETWORK); 659105197Ssam cnt = deviceCount(devs); 660105197Ssam if (cnt) { 661105197Ssam if (DITEM_STATUS(tcpOpenDialog(devs[0]) == DITEM_SUCCESS)) 662120585Ssam rval = devs[0]; 663105197Ssam } 664105197Ssam } 665120585Ssam else { 666120585Ssam int status; 667105197Ssam 668105197Ssam menu = deviceCreateMenu(&MenuNetworkDevice, DEVICE_TYPE_NETWORK, netHook, NULL); 669105197Ssam if (!menu) 670105197Ssam msgFatal("Unable to create network device menu! Argh!"); 671120585Ssam status = dmenuOpenSimple(menu, FALSE); 672105197Ssam free(menu); 673105197Ssam if (status) 674105197Ssam rval = NetDev; 675105197Ssam } 676105197Ssam return rval; 677105197Ssam} 678105197Ssam 679105197Ssam/* Do it from a menu that doesn't care about status */ 680105197Ssamint 681105197SsamtcpMenuSelect(dialogMenuItem *self) 682105197Ssam{ 683105197Ssam Device *tmp; 684105197Ssam WINDOW *save; 685105197Ssam 686105197Ssam variable_set("NETWORK_CONFIGURED=NO",0); 687105197Ssam tmp = tcpDeviceSelect(); 688105197Ssam variable_unset("NETWORK_CONFIGURED"); 689105197Ssam save = savescr(); 690105197Ssam if (tmp && tmp->private && !((DevInfo *)tmp->private)->use_dhcp && !msgYesNo("Would you like to bring the %s interface up right now?", tmp->name)) 691105197Ssam if (!DEVICE_INIT(tmp)) 692105197Ssam msgConfirm("Initialization of %s device failed.", tmp->name); 693105197Ssam restorescr(save); 694105197Ssam return DITEM_SUCCESS; 695105197Ssam} 696105197Ssam