18549Sjkh/* 250479Speter * $FreeBSD$ 38549Sjkh * 48549Sjkh * Copyright (c) 1995 58549Sjkh * Gary J Palmer. All rights reserved. 617985Sjkh * Copyright (c) 1996 717985Sjkh * Jordan K. Hubbard. All rights reserved. 88549Sjkh * 98549Sjkh * Redistribution and use in source and binary forms, with or without 108549Sjkh * modification, are permitted provided that the following conditions 118549Sjkh * are met: 128549Sjkh * 1. Redistributions of source code must retain the above copyright 138881Srgrimes * notice, this list of conditions and the following disclaimer, 148881Srgrimes * verbatim and that no modifications are made prior to this 158549Sjkh * point in the file. 168549Sjkh * 2. Redistributions in binary form must reproduce the above copyright 178549Sjkh * notice, this list of conditions and the following disclaimer in the 188549Sjkh * documentation and/or other materials provided with the distribution. 198549Sjkh * 2017985Sjkh * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 218677Sjkh * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 228677Sjkh * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2317985Sjkh * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 248677Sjkh * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 258677Sjkh * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 268677Sjkh * OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 278677Sjkh * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 288677Sjkh * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 298677Sjkh * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 308549Sjkh * 318549Sjkh */ 328549Sjkh 338756Sjkh/* 348756Sjkh * All kinds of hacking also performed by jkh on this code. Don't 358756Sjkh * blame Gary for every bogosity you see here.. :-) 368756Sjkh * 378756Sjkh * -jkh 388756Sjkh */ 398756Sjkh 4021243Sjkh#include "sysinstall.h" 418549Sjkh#include <sys/param.h> 4263118Sume#include <sys/sysctl.h> 43198317Srink#include <sys/types.h> 4463118Sume#include <sys/socket.h> 45198317Srink#include <sys/sockio.h> 46198317Srink 4763118Sume#include <netinet/in.h> 48198317Srink#include <net/if.h> 49198317Srink#include <net/if_media.h> 50198317Srink 5150780Sjkh#include <netdb.h> 52147902Sscottl#include <paths.h> 53198317Srink#include <ifaddrs.h> 548549Sjkh 5514321Sjkh/* The help file for the TCP/IP setup screen */ 5614321Sjkh#define TCP_HELPFILE "tcp" 5714321Sjkh 588574Sgpalmer/* These are nasty, but they make the layout structure a lot easier ... */ 598574Sgpalmer 6012661Speterstatic char hostname[HOSTNAME_FIELD_LEN], domainname[HOSTNAME_FIELD_LEN], 6163118Sume gateway[IPADDR_FIELD_LEN], nameserver[INET6_ADDRSTRLEN]; 6212661Speterstatic int okbutton, cancelbutton; 6312661Speterstatic char ipaddr[IPADDR_FIELD_LEN], netmask[IPADDR_FIELD_LEN], extras[EXTRAS_FIELD_LEN]; 6463118Sumestatic char ipv6addr[INET6_ADDRSTRLEN]; 658549Sjkh 668574Sgpalmer/* What the screen size is meant to be */ 678549Sjkh#define TCP_DIALOG_Y 0 688549Sjkh#define TCP_DIALOG_X 8 698549Sjkh#define TCP_DIALOG_WIDTH COLS - 16 708549Sjkh#define TCP_DIALOG_HEIGHT LINES - 2 718549Sjkh 728549Sjkhstatic Layout layout[] = { 7320484Sjkh#define LAYOUT_HOSTNAME 0 7421243Sjkh { 1, 2, 25, HOSTNAME_FIELD_LEN - 1, 75213763Sbrucec "Host:", "Your fully-qualified hostname, e.g. foo.example.com", 768549Sjkh hostname, STRINGOBJ, NULL }, 7720484Sjkh#define LAYOUT_DOMAINNAME 1 7821243Sjkh { 1, 35, 20, HOSTNAME_FIELD_LEN - 1, 7917985Sjkh "Domain:", 80213763Sbrucec "The name of the domain that your machine is in, e.g. example.com", 818549Sjkh domainname, STRINGOBJ, NULL }, 8220484Sjkh#define LAYOUT_GATEWAY 2 8321243Sjkh { 5, 2, 18, IPADDR_FIELD_LEN - 1, 8463118Sume "IPv4 Gateway:", 8563118Sume "IPv4 address of host forwarding packets to non-local destinations", 868549Sjkh gateway, STRINGOBJ, NULL }, 8720484Sjkh#define LAYOUT_NAMESERVER 3 8863118Sume { 5, 35, 18, INET6_ADDRSTRLEN - 1, 8963118Sume "Name server:", "IPv4 or IPv6 address of your local DNS server", 908556Sjkh nameserver, STRINGOBJ, NULL }, 9120484Sjkh#define LAYOUT_IPADDR 4 9221243Sjkh { 10, 10, 18, IPADDR_FIELD_LEN - 1, 9363118Sume "IPv4 Address:", 9463118Sume "The IPv4 address to be used for this interface", 958549Sjkh ipaddr, STRINGOBJ, NULL }, 9620484Sjkh#define LAYOUT_NETMASK 5 9721243Sjkh { 10, 35, 18, IPADDR_FIELD_LEN - 1, 988549Sjkh "Netmask:", 9912661Speter "The netmask for this interface, e.g. 0xffffff00 for a class C network", 1008549Sjkh netmask, STRINGOBJ, NULL }, 10120484Sjkh#define LAYOUT_EXTRAS 6 10221243Sjkh { 14, 10, 37, HOSTNAME_FIELD_LEN - 1, 103125027Seivind "Extra options to ifconfig (usually empty):", 10417985Sjkh "Any interface-specific options to ifconfig you would like to add", 1058549Sjkh extras, STRINGOBJ, NULL }, 10620484Sjkh#define LAYOUT_OKBUTTON 7 10721243Sjkh { 19, 15, 0, 0, 1088549Sjkh "OK", "Select this if you are happy with these settings", 1098549Sjkh &okbutton, BUTTONOBJ, NULL }, 11020484Sjkh#define LAYOUT_CANCELBUTTON 8 11121243Sjkh { 19, 35, 0, 0, 1128549Sjkh "CANCEL", "Select this if you wish to cancel this screen", 1138549Sjkh &cancelbutton, BUTTONOBJ, NULL }, 114156123Sjhb LAYOUT_END, 1158549Sjkh}; 1168549Sjkh 11710882Speter#define _validByte(b) ((b) >= 0 && (b) <= 255) 1188549Sjkh 1198756Sjkh/* whine */ 1208549Sjkhstatic void 1218549Sjkhfeepout(char *msg) 1228549Sjkh{ 1238549Sjkh beep(); 12479304Skris msgConfirm("%s", msg); 1258549Sjkh} 1268549Sjkh 12770023Seivind/* Verify IP address integrity */ 1288549Sjkhstatic int 12979605SjesperverifyIP(char *ip, unsigned long *mask, unsigned long *out) 1308549Sjkh{ 13170023Seivind long a, b, c, d; 132169652Sdelphij char *endptr, *endptr_prev; 1338549Sjkh 13479605Sjesper unsigned long parsedip; 13579605Sjesper unsigned long max_addr = (255 << 24) | (255 << 16) | (255 << 8) | 255; 13679605Sjesper 13770023Seivind if (ip == NULL) 1388549Sjkh return 0; 13970023Seivind a = strtol(ip, &endptr, 10); 140169652Sdelphij if (endptr - ip == 0 || *endptr++ != '.') 14170023Seivind return 0; 142169652Sdelphij endptr_prev = endptr; 14370023Seivind b = strtol(endptr, &endptr, 10); 144169652Sdelphij if (endptr - endptr_prev == 0 || *endptr++ != '.') 14570023Seivind return 0; 146169652Sdelphij endptr_prev = endptr; 14770023Seivind c = strtol(endptr, &endptr, 10); 148169652Sdelphij if (endptr - endptr_prev == 0 || *endptr++ != '.') 14970023Seivind return 0; 150169652Sdelphij endptr_prev = endptr; 15170023Seivind d = strtol(endptr, &endptr, 10); 152169652Sdelphij if (*endptr != '\0' || endptr - endptr_prev == 0) 15370023Seivind return 0; 15479605Sjesper if (!_validByte(a) || !_validByte(b) || !_validByte(c) || !_validByte(d)) 15570023Seivind return 0; 15679605Sjesper parsedip = (a << 24) | (b << 16) | (c << 8) | d; 15770023Seivind if (out) 15879605Sjesper *out = parsedip; 15979605Sjesper /* 16079605Sjesper * The ip address must not be network or broadcast address. 16179605Sjesper */ 16279605Sjesper if (mask && ((parsedip == (parsedip & *mask)) || 16379605Sjesper (parsedip == ((parsedip & *mask) + max_addr - *mask)))) 16479605Sjesper return 0; 16570023Seivind return 1; 1668549Sjkh} 1678549Sjkh 16863118Sumestatic int 16963118SumeverifyIP6(char *ip) 17063118Sume{ 17163118Sume struct addrinfo hints, *res; 17263118Sume 17363118Sume memset(&hints, 0, sizeof(hints)); 17463118Sume hints.ai_family = AF_INET6; 17563118Sume hints.ai_socktype = SOCK_STREAM; 17663118Sume hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; 17763118Sume if (getaddrinfo(ip, NULL, &hints, &res) == 0) { 17863118Sume freeaddrinfo(res); 17963118Sume return 1; 18063118Sume } 18163118Sume return 0; 18263118Sume} 18363118Sume 18470023Seivind/* Verify IPv4 netmask as being well-formed as 18570023Seivind a 0x or AAA.BBB.CCC.DDD mask */ 18670023Seivindstatic int 18770023SeivindverifyNetmask(const char *netmask, unsigned long *out) 18870023Seivind{ 18970023Seivind unsigned long mask; 190156123Sjhb long tmp; 19170023Seivind char *endptr; 19270023Seivind 19370023Seivind if (netmask[0] == '0' && (netmask[1] == 'x' || netmask[1] == 'X')) { 19470023Seivind /* Parse out hex mask */ 19570023Seivind mask = strtoul(netmask, &endptr, 0); 19670023Seivind if (*endptr != '\0') 19770023Seivind return 0; 19870023Seivind } else { 19970023Seivind /* Parse out quad decimal mask */ 200156123Sjhb tmp = strtoul(netmask, &endptr, 10); 201156123Sjhb if (!_validByte(tmp) || *endptr++ != '.') 20270023Seivind return 0; 203156123Sjhb mask = tmp; 20470023Seivind tmp = strtoul(endptr, &endptr, 10); 20570023Seivind if (!_validByte(tmp) || *endptr++ != '.') 20670023Seivind return 0; 20770023Seivind mask = (mask << 8) + tmp; 20870023Seivind tmp = strtoul(endptr, &endptr, 10); 20970023Seivind if (!_validByte(tmp) || *endptr++ != '.') 21070023Seivind return 0; 21170023Seivind mask = (mask << 8) + tmp; 21270023Seivind tmp = strtoul(endptr, &endptr, 10); 21370023Seivind if (!_validByte(tmp) || *endptr++ != '\0') 21470023Seivind return 0; 21570023Seivind mask = (mask << 8) + tmp; 21670023Seivind } 21770023Seivind /* Verify that we have a continous netmask */ 21870023Seivind if ((((-mask & mask) - 1) | mask) != 0xffffffff) 21970023Seivind return 0; 22070023Seivind if (out) 22170023Seivind *out = mask; 22270023Seivind return 1; 22370023Seivind} 22470023Seivind 22570023Seivindstatic int 22670023SeivindverifyGW(char *gw, unsigned long *ip, unsigned long *mask) 22770023Seivind{ 22870023Seivind unsigned long parsedgw; 22970023Seivind 23079605Sjesper if (!verifyIP(gw, mask, &parsedgw)) 23170023Seivind return 0; 23270023Seivind /* Gateway needs to be within the set of IPs reachable through the 23370023Seivind interface */ 23470023Seivind if (ip && mask && ((parsedgw & *mask) != (*ip & *mask))) 23570023Seivind return 0; 23670023Seivind return 1; 23770023Seivind} 23870023Seivind 23921243Sjkh/* Check for the settings on the screen - the per-interface stuff is 2408574Sgpalmer moved to the main handling code now to do it on the fly - sigh */ 2418549Sjkhstatic int 2428549SjkhverifySettings(void) 2438549Sjkh{ 24470023Seivind unsigned long parsedip; 24570023Seivind unsigned long parsednetmask; 24670023Seivind 2478549Sjkh if (!hostname[0]) 2488549Sjkh feepout("Must specify a host name of some sort!"); 24979605Sjesper else if (netmask[0] && !verifyNetmask(netmask, &parsednetmask)) 25079605Sjesper feepout("Invalid netmask value"); 25179605Sjesper else if (nameserver[0] && !verifyIP(nameserver, NULL, NULL) && 25270023Seivind !verifyIP6(nameserver)) 2538549Sjkh feepout("Invalid name server IP address specified"); 25479605Sjesper else if (ipaddr[0] && !verifyIP(ipaddr, &parsednetmask, &parsedip)) 25570023Seivind feepout("Invalid IPv4 address"); 25670023Seivind else if (gateway[0] && strcmp(gateway, "NO") && 25770023Seivind !verifyGW(gateway, ipaddr[0] ? &parsedip : NULL, 25870023Seivind netmask[0] ? &parsednetmask : NULL)) 25970023Seivind feepout("Invalid gateway IPv4 address specified"); 2608549Sjkh else 2618549Sjkh return 1; 2628549Sjkh return 0; 2638549Sjkh} 2648549Sjkh 26550780Sjkhstatic void 26650780SjkhdhcpGetInfo(Device *devp) 26750780Sjkh{ 268147902Sscottl char leasefile[PATH_MAX]; 269147902Sscottl 270147902Sscottl snprintf(leasefile, sizeof(leasefile), "%sdhclient.leases.%s", 271147902Sscottl _PATH_VARDB, devp->name); 27250780Sjkh /* If it fails, do it the old-fashioned way */ 273147902Sscottl if (dhcpParseLeases(leasefile, hostname, domainname, 27450780Sjkh nameserver, ipaddr, gateway, netmask) == -1) { 27550780Sjkh FILE *ifp; 27650780Sjkh char *cp, cmd[256], data[2048]; 27750780Sjkh int i, j; 27850780Sjkh 27950780Sjkh /* Bah, now we have to kludge getting the information from ifconfig */ 28050780Sjkh snprintf(cmd, sizeof cmd, "ifconfig %s", devp->name); 28150780Sjkh ifp = popen(cmd, "r"); 28250780Sjkh if (ifp) { 28350780Sjkh j = fread(data, 1, sizeof(data), ifp); 28450780Sjkh fclose(ifp); 28550780Sjkh if (j < 0) /* paranoia */ 28650780Sjkh j = 0; 28750780Sjkh data[j] = '\0'; 28850780Sjkh if (isDebug()) 28950780Sjkh msgDebug("DHCP configured interface returns %s\n", data); 29050780Sjkh /* XXX This is gross as it assumes a certain ordering to 29150780Sjkh ifconfig's output! XXX */ 29263118Sume if ((cp = strstr(data, "inet ")) != NULL) { 29350780Sjkh i = 0; 29450780Sjkh cp += 5; /* move over keyword */ 29550780Sjkh while (*cp != ' ') 29650780Sjkh ipaddr[i++] = *(cp++); 29750780Sjkh ipaddr[i] = '\0'; 29850780Sjkh if (!strncmp(++cp, "netmask", 7)) { 29950780Sjkh i = 0; 30050780Sjkh cp += 8; 30150780Sjkh while (*cp != ' ') 30250780Sjkh netmask[i++] = *(cp++); 30350780Sjkh netmask[i] = '\0'; 30450780Sjkh } 30550780Sjkh } 30650780Sjkh } 30750780Sjkh } 30850780Sjkh 30950780Sjkh /* If we didn't get a name server value, hunt for it in resolv.conf */ 31050780Sjkh if (!nameserver[0] && file_readable("/etc/resolv.conf")) 31150780Sjkh configEnvironmentResolv("/etc/resolv.conf"); 31250780Sjkh if (hostname[0]) 31350780Sjkh variable_set2(VAR_HOSTNAME, hostname, 0); 31450780Sjkh} 31550780Sjkh 31663118Sumestatic void 31763118SumertsolGetInfo(Device *devp) 31863118Sume{ 31963118Sume FILE *ifp; 32063118Sume char *cp, cmd[256], data[2048]; 32163118Sume int i; 32263118Sume 32363118Sume snprintf(cmd, sizeof cmd, "ifconfig %s", devp->name); 32463118Sume if ((ifp = popen(cmd, "r")) == NULL) 32563118Sume return; 32663118Sume while (fgets(data, sizeof(data), ifp) != NULL) { 32763118Sume if (isDebug()) 328106279Skuriyama msgDebug("RTSOL configured interface returns %s\n", data); 32963118Sume if ((cp = strstr(data, "inet6 ")) != NULL) { 33063118Sume cp += 6; /* move over keyword */ 33163118Sume if (strncmp(cp, "fe80:", 5)) { 33263118Sume i = 0; 33363118Sume while (*cp != ' ') 33463118Sume ipv6addr[i++] = *(cp++); 33563118Sume ipv6addr[i] = '\0'; 33663118Sume } 33763118Sume } 33863118Sume } 33963118Sume fclose(ifp); 34063118Sume} 34163118Sume 3428549Sjkh/* This is it - how to get TCP setup values */ 3438556Sjkhint 3448756SjkhtcpOpenDialog(Device *devp) 3458549Sjkh{ 34626514Sjkh WINDOW *ds_win, *save = NULL; 3478549Sjkh ComposeObj *obj = NULL; 34846617Sjkh int n = 0, filled = 0, cancel = FALSE; 34926576Sjkh int max, ret = DITEM_SUCCESS; 35050780Sjkh int use_dhcp = FALSE; 35163118Sume int use_rtsol = FALSE; 3528549Sjkh char *tmp; 3538803Sjkh char title[80]; 3548549Sjkh 35554722Sjkh save = savescr(); 3568756Sjkh /* Initialise vars from previous device values */ 3578756Sjkh if (devp->private) { 3588756Sjkh DevInfo *di = (DevInfo *)devp->private; 3598881Srgrimes 36020247Sjkh SAFE_STRCPY(ipaddr, di->ipaddr); 36120247Sjkh SAFE_STRCPY(netmask, di->netmask); 36220247Sjkh SAFE_STRCPY(extras, di->extras); 36350780Sjkh use_dhcp = di->use_dhcp; 36463118Sume use_rtsol = di->use_rtsol; 3658756Sjkh } 36612661Speter else { /* See if there are any defaults */ 36712661Speter char *cp; 36897668Sjhb char *old_interactive = NULL; 3698756Sjkh 37083486Sjkh /* 37197668Sjhb * This is a hack so that the dialogs below are interactive in a 37297668Sjhb * script if we have requested interactive behavior. 37397668Sjhb */ 37497668Sjhb if (variable_get(VAR_NONINTERACTIVE) && 37597668Sjhb variable_get(VAR_NETINTERACTIVE)) { 37697668Sjhb old_interactive = strdup(VAR_NONINTERACTIVE); 37797668Sjhb variable_unset(VAR_NONINTERACTIVE); 37897668Sjhb } 37997668Sjhb 38097668Sjhb 38197668Sjhb /* 38283486Sjkh * Try a RTSOL scan if such behavior is desired. 38383486Sjkh * If the variable was configured and is YES, do it. 38483486Sjkh * If it was configured to anything else, treat it as NO. 38583486Sjkh * Otherwise, ask the question interactively. 38683486Sjkh */ 387111644Ssobomax if (!variable_get(VAR_NO_INET6) && 388111644Ssobomax (!variable_cmp(VAR_TRY_RTSOL, "YES") || 389111644Ssobomax (variable_get(VAR_TRY_RTSOL)==0 && !msgNoYes("Do you want to try IPv6 configuration of the interface?")))) { 39063118Sume int i; 39183843Smurray size_t len; 39263118Sume 39363118Sume i = 0; 39463118Sume sysctlbyname("net.inet6.ip6.forwarding", NULL, 0, &i, sizeof(i)); 39563118Sume i = 1; 39663118Sume sysctlbyname("net.inet6.ip6.accept_rtadv", NULL, 0, &i, sizeof(i)); 39763118Sume vsystem("ifconfig %s up", devp->name); 39869576Sume len = sizeof(i); 39969576Sume sysctlbyname("net.inet6.ip6.dad_count", &i, &len, NULL, 0); 40069576Sume sleep(i + 1); 40163118Sume Mkdir("/var/run"); 40263118Sume msgNotify("Scanning for RA servers..."); 40363118Sume if (0 == vsystem("rtsol %s", devp->name)) { 40469576Sume len = sizeof(i); 40569576Sume sysctlbyname("net.inet6.ip6.dad_count", &i, &len, NULL, 0); 40669576Sume sleep(i + 1); 40763118Sume rtsolGetInfo(devp); 40863118Sume use_rtsol = TRUE; 40963118Sume } else 41063118Sume use_rtsol = FALSE; 41163118Sume } 41263118Sume 41383486Sjkh 41483486Sjkh /* 41583486Sjkh * First try a DHCP scan if such behavior is desired. 41683486Sjkh * If the variable was configured and is YES, do it. 41783486Sjkh * If it was configured to anything else, treat it as NO. 41883486Sjkh * Otherwise, ask the question interactively. 41983486Sjkh */ 42065167Smurray if (!variable_cmp(VAR_TRY_DHCP, "YES") || 42183486Sjkh (variable_get(VAR_TRY_DHCP)==0 && !msgNoYes("Do you want to try DHCP configuration of the interface?"))) { 42250780Sjkh Mkdir("/var/db"); 42350780Sjkh Mkdir("/var/run"); 42450780Sjkh Mkdir("/tmp"); 42550780Sjkh msgNotify("Scanning for DHCP servers..."); 426147902Sscottl /* XXX clear any existing lease */ 427147902Sscottl /* XXX limit protocol to N tries */ 428147902Sscottl if (0 == vsystem("dhclient %s", devp->name)) { 42951019Sjkh dhcpGetInfo(devp); 43051019Sjkh use_dhcp = TRUE; 43150780Sjkh } 43251019Sjkh else 43351019Sjkh use_dhcp = FALSE; 43450780Sjkh } 43550780Sjkh 43697668Sjhb /* Restore old VAR_NONINTERACTIVE if needed. */ 43797668Sjhb if (old_interactive != NULL) { 43897668Sjhb variable_set2(VAR_NONINTERACTIVE, old_interactive, 0); 43997668Sjhb free(old_interactive); 44097668Sjhb } 44197668Sjhb 44251019Sjkh /* Special hack so it doesn't show up oddly in the tcpip setup menu */ 44351019Sjkh if (!strcmp(gateway, "NO")) 44451019Sjkh gateway[0] = '\0'; 44551019Sjkh 44650780Sjkh /* Get old IP address from variable space, if available */ 44712661Speter if (!ipaddr[0]) { 44812661Speter if ((cp = variable_get(VAR_IPADDR)) != NULL) 44920247Sjkh SAFE_STRCPY(ipaddr, cp); 45012661Speter else if ((cp = variable_get(string_concat3(devp->name, "_", VAR_IPADDR))) != NULL) 45120247Sjkh SAFE_STRCPY(ipaddr, cp); 45212661Speter } 45350780Sjkh 45450780Sjkh /* Get old netmask from variable space, if available */ 45512661Speter if (!netmask[0]) { 45612661Speter if ((cp = variable_get(VAR_NETMASK)) != NULL) 45720247Sjkh SAFE_STRCPY(netmask, cp); 45812661Speter else if ((cp = variable_get(string_concat3(devp->name, "_", VAR_NETMASK))) != NULL) 45920247Sjkh SAFE_STRCPY(netmask, cp); 46012661Speter } 46150780Sjkh 46250780Sjkh /* Get old extras string from variable space, if available */ 46312661Speter if (!extras[0]) { 46412661Speter if ((cp = variable_get(VAR_EXTRAS)) != NULL) 46520247Sjkh SAFE_STRCPY(extras, cp); 46612661Speter else if ((cp = variable_get(string_concat3(devp->name, "_", VAR_EXTRAS))) != NULL) 46720247Sjkh SAFE_STRCPY(extras, cp); 46812661Speter } 46912661Speter } 47021243Sjkh 4718756Sjkh /* Look up values already recorded with the system, or blank the string variables ready to accept some new data */ 47250780Sjkh if (!hostname[0]) { 47350780Sjkh tmp = variable_get(VAR_HOSTNAME); 47450780Sjkh if (tmp) 47550780Sjkh SAFE_STRCPY(hostname, tmp); 47650780Sjkh } 47750780Sjkh if (!domainname[0]) { 47850780Sjkh tmp = variable_get(VAR_DOMAINNAME); 47950780Sjkh if (tmp) 48050780Sjkh SAFE_STRCPY(domainname, tmp); 48150780Sjkh } 48250780Sjkh if (!gateway[0]) { 48350780Sjkh tmp = variable_get(VAR_GATEWAY); 48451019Sjkh if (tmp && strcmp(tmp, "NO")) 48550780Sjkh SAFE_STRCPY(gateway, tmp); 48650780Sjkh } 48750780Sjkh if (!nameserver[0]) { 48850780Sjkh tmp = variable_get(VAR_NAMESERVER); 48950780Sjkh if (tmp) 49050780Sjkh SAFE_STRCPY(nameserver, tmp); 49150780Sjkh } 4928549Sjkh 49326514Sjkh /* If non-interactive, jump straight over the dialog crap and into config section */ 49429539Spst if (variable_get(VAR_NONINTERACTIVE) && 49529539Spst !variable_get(VAR_NETINTERACTIVE)) { 49629537Sjkh if (!hostname[0]) 49729537Sjkh msgConfirm("WARNING: hostname variable not set and is a non-optional\n" 49829537Sjkh "parameter. Please add this to your installation script\n" 49929537Sjkh "or set the netInteractive variable (see sysinstall man page)"); 50029537Sjkh else 50129537Sjkh goto netconfig; 50229537Sjkh } 50326514Sjkh 50426514Sjkh /* Now do all the screen I/O */ 50526514Sjkh dialog_clear_norefresh(); 50626514Sjkh 50787609Smurray /* Modify the help line for PLIP config */ 508155613Sceri if (!strncmp(devp->name, "plip", 4)) 50987609Smurray layout[LAYOUT_EXTRAS].help = 51087609Smurray "For PLIP configuration, you must enter the peer's IP address here."; 51187609Smurray 51226514Sjkh /* We need a curses window */ 51363118Sume tmp = " Network Configuration "; 51463118Sume if (ipv6addr[0]) 51563118Sume tmp = string_concat(tmp, "(IPv6 ready) "); 51663118Sume if (!(ds_win = openLayoutDialog(TCP_HELPFILE, tmp, 51726514Sjkh TCP_DIALOG_X, TCP_DIALOG_Y, TCP_DIALOG_WIDTH, TCP_DIALOG_HEIGHT))) { 51826514Sjkh beep(); 51926514Sjkh msgConfirm("Cannot open TCP/IP dialog window!!"); 52026514Sjkh restorescr(save); 52126514Sjkh return DITEM_FAILURE; 52226514Sjkh } 52326514Sjkh 52426514Sjkh /* Draw interface configuration box */ 52526514Sjkh draw_box(ds_win, TCP_DIALOG_Y + 9, TCP_DIALOG_X + 8, TCP_DIALOG_HEIGHT - 13, TCP_DIALOG_WIDTH - 17, 52626514Sjkh dialog_attr, border_attr); 52726514Sjkh wattrset(ds_win, dialog_attr); 52826514Sjkh sprintf(title, " Configuration for Interface %s ", devp->name); 52926514Sjkh mvwaddstr(ds_win, TCP_DIALOG_Y + 9, TCP_DIALOG_X + 14, title); 53026514Sjkh 53121243Sjkh /* Some more initialisation before we go into the main input loop */ 53221243Sjkh obj = initLayoutDialog(ds_win, layout, TCP_DIALOG_X, TCP_DIALOG_Y, &max); 5338549Sjkh 53421243Sjkhreenter: 5358556Sjkh cancelbutton = okbutton = 0; 53621243Sjkh while (layoutDialogLoop(ds_win, layout, &obj, &n, max, &cancelbutton, &cancel)) { 53746617Sjkh /* Prevent this from being irritating if user really means NO */ 53846639Sjkh if (filled < 3) { 53946617Sjkh /* Insert a default value for the netmask, 0xffffff00 is 54046639Sjkh * the most appropriate one (entire class C, or subnetted 54146639Sjkh * class A/B network). 54246639Sjkh */ 54350780Sjkh if (!netmask[0]) { 54446617Sjkh strcpy(netmask, "255.255.255.0"); 54546617Sjkh RefreshStringObj(layout[LAYOUT_NETMASK].obj); 54646639Sjkh ++filled; 54746617Sjkh } 54846617Sjkh if (!index(hostname, '.') && domainname[0]) { 54946617Sjkh strcat(hostname, "."); 55046617Sjkh strcat(hostname, domainname); 55146617Sjkh RefreshStringObj(layout[LAYOUT_HOSTNAME].obj); 55246639Sjkh ++filled; 55346617Sjkh } 55446617Sjkh else if (((tmp = index(hostname, '.')) != NULL) && !domainname[0]) { 55546639Sjkh SAFE_STRCPY(domainname, tmp + 1); 55646639Sjkh RefreshStringObj(layout[LAYOUT_DOMAINNAME].obj); 55746639Sjkh ++filled; 55846617Sjkh } 55921243Sjkh } 5608549Sjkh } 56122721Sjkh if (!cancel && !verifySettings()) 56221243Sjkh goto reenter; 5638556Sjkh 5648574Sgpalmer /* Clear this crap off the screen */ 56523588Sjkh delwin(ds_win); 56617404Sjkh dialog_clear_norefresh(); 5678576Sjkh use_helpfile(NULL); 5688881Srgrimes 5698574Sgpalmer /* We actually need to inform the rest of sysinstall about this 57021243Sjkh data now if the user hasn't selected cancel. Save the stuff 57121243Sjkh out to the environment via the variable_set() mechanism */ 5728556Sjkh 57326514Sjkhnetconfig: 5748549Sjkh if (!cancel) { 5758756Sjkh DevInfo *di; 57612661Speter char temp[512], ifn[255]; 57763118Sume int ipv4_enable = FALSE; 5788756Sjkh 57950780Sjkh if (hostname[0]) { 58056713Sjkh variable_set2(VAR_HOSTNAME, hostname, 1); 58150780Sjkh sethostname(hostname, strlen(hostname)); 58250780Sjkh } 5839202Srgrimes if (domainname[0]) 58443685Sjkh variable_set2(VAR_DOMAINNAME, domainname, 0); 5858556Sjkh if (gateway[0]) 58657365Sjkh variable_set2(VAR_GATEWAY, gateway, use_dhcp ? 0 : 1); 5878556Sjkh if (nameserver[0]) 58843685Sjkh variable_set2(VAR_NAMESERVER, nameserver, 0); 58950780Sjkh if (ipaddr[0]) 59050780Sjkh variable_set2(VAR_IPADDR, ipaddr, 0); 59163118Sume if (ipv6addr[0]) 59263118Sume variable_set2(VAR_IPV6ADDR, ipv6addr, 0); 5938574Sgpalmer 5948756Sjkh if (!devp->private) 59516330Sjkh devp->private = (DevInfo *)safe_malloc(sizeof(DevInfo)); 5968756Sjkh di = devp->private; 59720247Sjkh SAFE_STRCPY(di->ipaddr, ipaddr); 59820247Sjkh SAFE_STRCPY(di->netmask, netmask); 59920247Sjkh SAFE_STRCPY(di->extras, extras); 60050780Sjkh di->use_dhcp = use_dhcp; 60163118Sume di->use_rtsol = use_rtsol; 6028756Sjkh 60363118Sume if (use_dhcp || ipaddr[0]) 60463118Sume ipv4_enable = TRUE; 60563118Sume if (ipv4_enable) { 60663118Sume sprintf(ifn, "%s%s", VAR_IFCONFIG, devp->name); 607155380Sdelphij if (use_dhcp) { 608155380Sdelphij if (strlen(extras) > 0) 609155380Sdelphij sprintf(temp, "DHCP %s", extras); 610155380Sdelphij else 611155380Sdelphij sprintf(temp, "DHCP"); 612155380Sdelphij } else 61363118Sume sprintf(temp, "inet %s %s netmask %s", 61463118Sume ipaddr, extras, netmask); 61563118Sume variable_set2(ifn, temp, 1); 61663118Sume } 61763118Sume if (use_rtsol) 61863118Sume variable_set2(VAR_IPV6_ENABLE, "YES", 1); 61950780Sjkh if (!use_dhcp) 62050780Sjkh configResolv(NULL); /* XXX this will do it on the MFS copy XXX */ 62121243Sjkh ret = DITEM_SUCCESS; 6228556Sjkh } 62321243Sjkh else 62421243Sjkh ret = DITEM_FAILURE; 62515355Sjkh restorescr(save); 62621243Sjkh return ret; 6278549Sjkh} 6288677Sjkh 62922842Sjkhstatic Device *NetDev; 63022842Sjkh 6318677Sjkhstatic int 63215242SjkhnetHook(dialogMenuItem *self) 6338677Sjkh{ 6348677Sjkh Device **devs; 6358677Sjkh 63621730Sjkh devs = deviceFindDescr(self->prompt, self->title, DEVICE_TYPE_NETWORK); 6378756Sjkh if (devs) { 63817007Sjkh if (DITEM_STATUS(tcpOpenDialog(devs[0])) != DITEM_FAILURE) 63922842Sjkh NetDev = devs[0]; 64017007Sjkh else 64122842Sjkh NetDev = NULL; 6428756Sjkh } 64315242Sjkh return devs ? DITEM_LEAVE_MENU : DITEM_FAILURE; 6448677Sjkh} 6458677Sjkh 646198317Srinkstatic char * 647198317SrinktcpDeviceScan(void) 648198317Srink{ 649198317Srink int s; 650198317Srink struct ifmediareq ifmr; 651198317Srink struct ifaddrs *ifap, *ifa; 652198317Srink char *network_dev; 653198317Srink 654198317Srink if ((s = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0) 655198317Srink return (NULL); 656198317Srink 657198317Srink if (getifaddrs(&ifap) < 0) 658198317Srink return (NULL); 659198317Srink 660198317Srink for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { 661198317Srink memset(&ifmr, 0, sizeof(ifmr)); 662198317Srink strlcpy(ifmr.ifm_name, ifa->ifa_name, sizeof(ifmr.ifm_name)); 663198317Srink 664198317Srink if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) 665198317Srink continue; /* some devices don't support this */ 666198317Srink 667198317Srink if ((ifmr.ifm_status & IFM_AVALID) == 0) 668198317Srink continue; /* not active */ 669198317Srink 670198317Srink if (IFM_TYPE(ifmr.ifm_active) != IFM_ETHER) 671198317Srink continue; /* not an ethernet device */ 672198317Srink 673198317Srink if (ifmr.ifm_status & IFM_ACTIVE) { 674198317Srink network_dev = strdup(ifa->ifa_name); 675198317Srink freeifaddrs(ifap); 676198317Srink 677198317Srink if (!variable_get(VAR_NONINTERACTIVE)) 678198317Srink msgConfirm("Using interface %s", network_dev); 679198317Srink 680198317Srink msgDebug("tcpDeviceScan found %s", network_dev); 681198317Srink return (network_dev); 682198317Srink } 683198317Srink } 684198317Srink 685206995Srandi close(s); 686206995Srandi 687198317Srink freeifaddrs(ifap); 688198317Srink 689198317Srink return (NULL); 690198317Srink} 691198317Srink 6928677Sjkh/* Get a network device */ 69322842SjkhDevice * 6949202SrgrimestcpDeviceSelect(void) 6958677Sjkh{ 6968677Sjkh DMenu *menu; 69722842Sjkh Device **devs, *rval; 698192130Scperciva char *dev, *network_dev; 6999202Srgrimes int cnt; 7008677Sjkh 701192130Scperciva rval = NULL; 702192130Scperciva 703198317Srink if (variable_get(VAR_NETWORK_DEVICE)) { 704192130Scperciva network_dev = variable_get(VAR_NETWORK_DEVICE); 705192130Scperciva 706198317Srink /* 707198317Srink * netDev can be set to several types of values. 708198317Srink * If netDev is set to ANY, scan all network devices 709198317Srink * looking for a valid link, and go with the first 710198317Srink * device found. netDev can also be specified as a 711198317Srink * comma delimited list, with each network device 712198317Srink * tried in order. netDev can also be set to a single 713198317Srink * network device. 714198317Srink */ 715198317Srink if (!strcmp(network_dev, "ANY")) 716198317Srink network_dev = strdup(tcpDeviceScan()); 717198317Srink 718192130Scperciva while ((dev = strsep(&network_dev, ",")) != NULL) { 719192130Scperciva devs = deviceFind(dev, DEVICE_TYPE_NETWORK); 720192130Scperciva cnt = deviceCount(devs); 721198317Srink 722192130Scperciva if (cnt) { 723198317Srink if (DITEM_STATUS(tcpOpenDialog(devs[0])) == DITEM_SUCCESS) 724198317Srink return (devs[0]); 725192130Scperciva } 726192130Scperciva } 727192130Scperciva 728198317Srink if (!variable_get(VAR_NONINTERACTIVE)) 729198317Srink msgConfirm("No network devices available!"); 73026514Sjkh 731198317Srink return (NULL); 73229222Sjkh } 733198317Srink 734209004Srandi devs = deviceFind(NULL, DEVICE_TYPE_NETWORK); 735209004Srandi cnt = deviceCount(devs); 736209004Srandi 737198317Srink if ((!RunningAsInit) && (variable_check("NETWORK_CONFIGURED=NO") != TRUE)) { 73829222Sjkh if (!msgYesNo("Running multi-user, assume that the network is already configured?")) 73929222Sjkh return devs[0]; 74029222Sjkh } 74129222Sjkh if (cnt == 1) { 74226514Sjkh if (DITEM_STATUS(tcpOpenDialog(devs[0]) == DITEM_SUCCESS)) 74326514Sjkh rval = devs[0]; 7449202Srgrimes } 7459202Srgrimes else { 74622856Sjkh int status; 74722856Sjkh 74815242Sjkh menu = deviceCreateMenu(&MenuNetworkDevice, DEVICE_TYPE_NETWORK, netHook, NULL); 7499202Srgrimes if (!menu) 7509202Srgrimes msgFatal("Unable to create network device menu! Argh!"); 75116887Sjkh status = dmenuOpenSimple(menu, FALSE); 7529202Srgrimes free(menu); 75326514Sjkh if (status) 75422856Sjkh rval = NetDev; 7559202Srgrimes } 75622842Sjkh return rval; 7579202Srgrimes} 7589202Srgrimes 7599202Srgrimes/* Do it from a menu that doesn't care about status */ 7609202Srgrimesint 76115091SjkhtcpMenuSelect(dialogMenuItem *self) 7629202Srgrimes{ 76322842Sjkh Device *tmp; 76463832Sjkh WINDOW *save; 76522842Sjkh 76659057Smurray variable_set("NETWORK_CONFIGURED=NO",0); 76722842Sjkh tmp = tcpDeviceSelect(); 76859057Smurray variable_unset("NETWORK_CONFIGURED"); 76963832Sjkh save = savescr(); 77053019Sjkh if (tmp && tmp->private && !((DevInfo *)tmp->private)->use_dhcp && !msgYesNo("Would you like to bring the %s interface up right now?", tmp->name)) 77179065Sdd if (!DEVICE_INIT(tmp)) 77222842Sjkh msgConfirm("Initialization of %s device failed.", tmp->name); 77363832Sjkh restorescr(save); 77454587Sjkh return DITEM_SUCCESS; 7758677Sjkh} 776