tcpip.c revision 188631
138061Smsmith/*
238061Smsmith * $FreeBSD: head/usr.sbin/sysinstall/tcpip.c 188631 2009-02-15 03:10:20Z imp $
338061Smsmith *
438061Smsmith * Copyright (c) 1995
538061Smsmith *      Gary J Palmer. All rights reserved.
638061Smsmith * Copyright (c) 1996
738061Smsmith *      Jordan K. Hubbard. All rights reserved.
838061Smsmith *
938061Smsmith * Redistribution and use in source and binary forms, with or without
1038061Smsmith * modification, are permitted provided that the following conditions
1138061Smsmith * are met:
1238061Smsmith * 1. Redistributions of source code must retain the above copyright
1338061Smsmith *    notice, this list of conditions and the following disclaimer,
1438061Smsmith *    verbatim and that no modifications are made prior to this
1538061Smsmith *    point in the file.
1638061Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1738061Smsmith *    notice, this list of conditions and the following disclaimer in the
1838061Smsmith *    documentation and/or other materials provided with the distribution.
1938061Smsmith *
2038061Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
2138061Smsmith * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2238061Smsmith * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2338061Smsmith * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2438061Smsmith * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2538061Smsmith * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
2638061Smsmith * OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2738061Smsmith * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
2838061Smsmith * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29119418Sobrien * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30119418Sobrien *
31119418Sobrien */
3238061Smsmith
3338061Smsmith/*
3438061Smsmith * All kinds of hacking also performed by jkh on this code.  Don't
3538061Smsmith * blame Gary for every bogosity you see here.. :-)
3638061Smsmith *
3738061Smsmith * -jkh
3838061Smsmith */
3938061Smsmith
40108470Sschweikh#include "sysinstall.h"
4138061Smsmith#include <sys/param.h>
4238061Smsmith#include <sys/sysctl.h>
4338061Smsmith#include <sys/socket.h>
4438061Smsmith#include <netinet/in.h>
4538061Smsmith#include <netdb.h>
4638061Smsmith#include <paths.h>
4738061Smsmith
4838061Smsmith/* The help file for the TCP/IP setup screen */
4938061Smsmith#define TCP_HELPFILE		"tcp"
5038061Smsmith
5138061Smsmith/* These are nasty, but they make the layout structure a lot easier ... */
5238061Smsmith
5338061Smsmithstatic char	hostname[HOSTNAME_FIELD_LEN], domainname[HOSTNAME_FIELD_LEN],
5438061Smsmith		gateway[IPADDR_FIELD_LEN], nameserver[INET6_ADDRSTRLEN];
5538061Smsmithstatic int	okbutton, cancelbutton;
5638061Smsmithstatic char	ipaddr[IPADDR_FIELD_LEN], netmask[IPADDR_FIELD_LEN], extras[EXTRAS_FIELD_LEN];
5738061Smsmithstatic char	ipv6addr[INET6_ADDRSTRLEN];
5838061Smsmith
5938061Smsmith/* What the screen size is meant to be */
6038061Smsmith#define TCP_DIALOG_Y		0
6138061Smsmith#define TCP_DIALOG_X		8
6238061Smsmith#define TCP_DIALOG_WIDTH	COLS - 16
6338061Smsmith#define TCP_DIALOG_HEIGHT	LINES - 2
6438061Smsmith
6538061Smsmithstatic Layout layout[] = {
6638061Smsmith#define LAYOUT_HOSTNAME		0
6738061Smsmith    { 1, 2, 25, HOSTNAME_FIELD_LEN - 1,
6838061Smsmith      "Host:", "Your fully-qualified hostname, e.g. foo.bar.com",
6938061Smsmith      hostname, STRINGOBJ, NULL },
7038061Smsmith#define LAYOUT_DOMAINNAME	1
7138061Smsmith    { 1, 35, 20, HOSTNAME_FIELD_LEN - 1,
7238061Smsmith      "Domain:",
7338061Smsmith      "The name of the domain that your machine is in, e.g. bar.com",
7438061Smsmith      domainname, STRINGOBJ, NULL },
7538061Smsmith#define LAYOUT_GATEWAY		2
7638061Smsmith    { 5, 2, 18, IPADDR_FIELD_LEN - 1,
7738061Smsmith      "IPv4 Gateway:",
7838061Smsmith      "IPv4 address of host forwarding packets to non-local destinations",
7938061Smsmith      gateway, STRINGOBJ, NULL },
8038061Smsmith#define LAYOUT_NAMESERVER	3
8138061Smsmith    { 5, 35, 18, INET6_ADDRSTRLEN - 1,
8238061Smsmith      "Name server:", "IPv4 or IPv6 address of your local DNS server",
8355939Snsouch      nameserver, STRINGOBJ, NULL },
8455939Snsouch#define LAYOUT_IPADDR		4
8538061Smsmith    { 10, 10, 18, IPADDR_FIELD_LEN - 1,
8638061Smsmith      "IPv4 Address:",
8755939Snsouch      "The IPv4 address to be used for this interface",
8855939Snsouch      ipaddr, STRINGOBJ, NULL },
8938061Smsmith#define LAYOUT_NETMASK		5
9038061Smsmith    { 10, 35, 18, IPADDR_FIELD_LEN - 1,
9138061Smsmith      "Netmask:",
9238061Smsmith      "The netmask for this interface, e.g. 0xffffff00 for a class C network",
9338061Smsmith      netmask, STRINGOBJ, NULL },
9438061Smsmith#define LAYOUT_EXTRAS		6
9555939Snsouch    { 14, 10, 37, HOSTNAME_FIELD_LEN - 1,
9655939Snsouch      "Extra options to ifconfig (usually empty):",
9755939Snsouch      "Any interface-specific options to ifconfig you would like to add",
9855939Snsouch      extras, STRINGOBJ, NULL },
9938061Smsmith#define LAYOUT_OKBUTTON		7
10038061Smsmith    { 19, 15, 0, 0,
10138061Smsmith      "OK", "Select this if you are happy with these settings",
10238061Smsmith      &okbutton, BUTTONOBJ, NULL },
10338061Smsmith#define LAYOUT_CANCELBUTTON	8
10438061Smsmith    { 19, 35, 0, 0,
10538061Smsmith      "CANCEL", "Select this if you wish to cancel this screen",
10638061Smsmith      &cancelbutton, BUTTONOBJ, NULL },
10738061Smsmith    LAYOUT_END,
10838061Smsmith};
10955939Snsouch
11055939Snsouch#define _validByte(b) ((b) >= 0 && (b) <= 255)
11138061Smsmith
11238061Smsmith/* whine */
11338061Smsmithstatic void
11438061Smsmithfeepout(char *msg)
11538061Smsmith{
11638061Smsmith    beep();
11738061Smsmith    msgConfirm("%s", msg);
11838061Smsmith}
11938061Smsmith
12038061Smsmith/* Verify IP address integrity */
12138061Smsmithstatic int
12238061SmsmithverifyIP(char *ip, unsigned long *mask, unsigned long *out)
12338061Smsmith{
12438061Smsmith    long a, b, c, d;
12538061Smsmith    char *endptr, *endptr_prev;
12638061Smsmith
12738061Smsmith    unsigned long parsedip;
12838061Smsmith    unsigned long max_addr = (255 << 24) | (255 << 16) | (255 << 8) | 255;
12938061Smsmith
13038061Smsmith    if (ip == NULL)
13138061Smsmith	return 0;
13238061Smsmith    a = strtol(ip, &endptr, 10);
13338061Smsmith    if (endptr - ip == 0 || *endptr++ != '.')
13438061Smsmith	return 0;
13538061Smsmith    endptr_prev = endptr;
13638061Smsmith    b = strtol(endptr, &endptr, 10);
13738061Smsmith    if (endptr - endptr_prev == 0 || *endptr++ != '.')
13838061Smsmith	return 0;
13938061Smsmith    endptr_prev = endptr;
14038061Smsmith    c = strtol(endptr, &endptr, 10);
14143433Snsouch    if (endptr - endptr_prev == 0 || *endptr++ != '.')
14243433Snsouch	return 0;
14338061Smsmith    endptr_prev = endptr;
14443433Snsouch    d = strtol(endptr, &endptr, 10);
14543433Snsouch    if (*endptr != '\0' || endptr - endptr_prev == 0)
14638061Smsmith	return 0;
14738061Smsmith    if (!_validByte(a) || !_validByte(b) || !_validByte(c) || !_validByte(d))
14855939Snsouch	return 0;
149147256Sbrooks    parsedip = (a << 24) | (b << 16) | (c << 8) | d;
15038061Smsmith    if (out)
15138061Smsmith	*out = parsedip;
15255939Snsouch    /*
15355939Snsouch     * The ip address must not be network or broadcast address.
15438061Smsmith     */
15538061Smsmith    if (mask && ((parsedip == (parsedip & *mask)) ||
15638061Smsmith	(parsedip == ((parsedip & *mask) + max_addr - *mask))))
15738061Smsmith	return 0;
15838061Smsmith    return 1;
15938061Smsmith}
16038061Smsmith
16138061Smsmithstatic int
16238061SmsmithverifyIP6(char *ip)
16338061Smsmith{
16438061Smsmith    struct addrinfo hints, *res;
16538061Smsmith
16638061Smsmith    memset(&hints, 0, sizeof(hints));
16738061Smsmith    hints.ai_family = AF_INET6;
16838061Smsmith    hints.ai_socktype = SOCK_STREAM;
16938061Smsmith    hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
17038061Smsmith    if (getaddrinfo(ip, NULL, &hints, &res) == 0) {
17138061Smsmith	freeaddrinfo(res);
17255939Snsouch	return 1;
17338061Smsmith    }
17455939Snsouch    return 0;
17555939Snsouch}
17655939Snsouch
17755939Snsouch/* Verify IPv4 netmask as being well-formed as
17855939Snsouch   a 0x or AAA.BBB.CCC.DDD mask */
17955939Snsouchstatic int
18038061SmsmithverifyNetmask(const char *netmask, unsigned long *out)
18155939Snsouch{
18255939Snsouch    unsigned long mask;
18356455Speter    long tmp;
18456455Speter    char *endptr;
18556455Speter
186127189Sguido    if (netmask[0] == '0' && (netmask[1] == 'x' || netmask[1] == 'X')) {
18755939Snsouch        /* Parse out hex mask */
188127189Sguido        mask = strtoul(netmask, &endptr, 0);
189127189Sguido        if (*endptr != '\0')
190127189Sguido            return 0;
19156455Speter    } else {
19238061Smsmith        /* Parse out quad decimal mask */
19338061Smsmith        tmp = strtoul(netmask, &endptr, 10);
19438061Smsmith        if (!_validByte(tmp) || *endptr++ != '.')
19555939Snsouch            return 0;
19655939Snsouch	mask = tmp;
19738061Smsmith        tmp = strtoul(endptr, &endptr, 10);
19855939Snsouch        if (!_validByte(tmp) || *endptr++ != '.')
19955939Snsouch            return 0;
20056618Sdfr	mask = (mask << 8) + tmp;
20157177Speter        tmp = strtoul(endptr, &endptr, 10);
20238061Smsmith        if (!_validByte(tmp) || *endptr++ != '.')
20355939Snsouch            return 0;
20455939Snsouch	mask = (mask << 8) + tmp;
20555939Snsouch        tmp = strtoul(endptr, &endptr, 10);
20655939Snsouch        if (!_validByte(tmp) || *endptr++ != '\0')
20755939Snsouch            return 0;
20838061Smsmith	mask = (mask << 8) + tmp;
20955939Snsouch    }
21055939Snsouch    /* Verify that we have a continous netmask */
21155939Snsouch    if ((((-mask & mask) - 1) | mask) != 0xffffffff)
21243989Snsouch        return 0;
21338061Smsmith    if (out)
21455939Snsouch        *out = mask;
21555939Snsouch    return 1;
21655939Snsouch}
21755939Snsouch
21855939Snsouchstatic int
21955939SnsouchverifyGW(char *gw, unsigned long *ip, unsigned long *mask)
22038061Smsmith{
22138061Smsmith    unsigned long parsedgw;
22238061Smsmith
22338061Smsmith    if (!verifyIP(gw, mask, &parsedgw))
22438061Smsmith	return 0;
22538061Smsmith    /* Gateway needs to be within the set of IPs reachable through the
22655939Snsouch       interface */
22738061Smsmith    if (ip && mask && ((parsedgw & *mask) != (*ip & *mask)))
22855939Snsouch	return 0;
22938061Smsmith    return 1;
23038061Smsmith}
23138061Smsmith
23255939Snsouch/* Check for the settings on the screen - the per-interface stuff is
23338061Smsmith   moved to the main handling code now to do it on the fly - sigh */
23455939Snsouchstatic int
235147256SbrooksverifySettings(void)
23638061Smsmith{
237147256Sbrooks    unsigned long parsedip;
238147256Sbrooks    unsigned long parsednetmask;
239147256Sbrooks
240147256Sbrooks    if (!hostname[0])
241147256Sbrooks	feepout("Must specify a host name of some sort!");
24255939Snsouch    else if (netmask[0] && !verifyNetmask(netmask, &parsednetmask))
243121816Sbrooks	feepout("Invalid netmask value");
24438061Smsmith    else if (nameserver[0] && !verifyIP(nameserver, NULL, NULL) &&
245133695Srwatson		    !verifyIP6(nameserver))
246133695Srwatson	feepout("Invalid name server IP address specified");
24738061Smsmith    else if (ipaddr[0] && !verifyIP(ipaddr, &parsednetmask, &parsedip))
24838061Smsmith	feepout("Invalid IPv4 address");
24938061Smsmith    else if (gateway[0] && strcmp(gateway, "NO") &&
25038061Smsmith	     !verifyGW(gateway, ipaddr[0] ? &parsedip : NULL,
25138061Smsmith		     netmask[0] ? &parsednetmask : NULL))
25238061Smsmith	feepout("Invalid gateway IPv4 address specified");
25338061Smsmith    else
25443773Sdes	return 1;
25538061Smsmith    return 0;
25655939Snsouch}
25738061Smsmith
25838061Smsmithstatic void
25938061SmsmithdhcpGetInfo(Device *devp)
26038061Smsmith{
26138061Smsmith    char leasefile[PATH_MAX];
26238061Smsmith
26338061Smsmith    snprintf(leasefile, sizeof(leasefile), "%sdhclient.leases.%s",
26438061Smsmith	_PATH_VARDB, devp->name);
26538061Smsmith    /* If it fails, do it the old-fashioned way */
26638061Smsmith    if (dhcpParseLeases(leasefile, hostname, domainname,
26738061Smsmith			 nameserver, ipaddr, gateway, netmask) == -1) {
26838061Smsmith	FILE *ifp;
26938061Smsmith	char *cp, cmd[256], data[2048];
27038061Smsmith	int i, j;
27138061Smsmith
27238061Smsmith	/* Bah, now we have to kludge getting the information from ifconfig */
27338061Smsmith	snprintf(cmd, sizeof cmd, "ifconfig %s", devp->name);
27438061Smsmith	ifp = popen(cmd, "r");
27538061Smsmith	if (ifp) {
27638061Smsmith	    j = fread(data, 1, sizeof(data), ifp);
27738061Smsmith	    fclose(ifp);
27838061Smsmith	    if (j < 0)	/* paranoia */
27938061Smsmith		j = 0;
28038061Smsmith	    data[j] = '\0';
28138061Smsmith	    if (isDebug())
28238061Smsmith		msgDebug("DHCP configured interface returns %s\n", data);
28338061Smsmith	    /* XXX This is gross as it assumes a certain ordering to
28438061Smsmith	       ifconfig's output! XXX */
28538061Smsmith	    if ((cp = strstr(data, "inet ")) != NULL) {
28638061Smsmith		i = 0;
28738061Smsmith		cp += 5;	/* move over keyword */
28838061Smsmith		while (*cp != ' ')
28938061Smsmith		    ipaddr[i++] = *(cp++);
29038061Smsmith		ipaddr[i] = '\0';
29138061Smsmith		if (!strncmp(++cp, "netmask", 7)) {
29238061Smsmith		    i = 0;
29338061Smsmith		    cp += 8;
29438061Smsmith		    while (*cp != ' ')
29538061Smsmith			netmask[i++] = *(cp++);
29638061Smsmith		    netmask[i] = '\0';
29738061Smsmith		}
29838061Smsmith	    }
29938061Smsmith	}
30038061Smsmith    }
30138061Smsmith
30238061Smsmith    /* If we didn't get a name server value, hunt for it in resolv.conf */
30338061Smsmith    if (!nameserver[0] && file_readable("/etc/resolv.conf"))
304121816Sbrooks	configEnvironmentResolv("/etc/resolv.conf");
30555939Snsouch    if (hostname[0])
30655939Snsouch	variable_set2(VAR_HOSTNAME, hostname, 0);
30738061Smsmith}
30838061Smsmith
30938061Smsmithstatic void
31055939SnsouchrtsolGetInfo(Device *devp)
31138061Smsmith{
31238061Smsmith    FILE *ifp;
31338061Smsmith    char *cp, cmd[256], data[2048];
31438061Smsmith    int i;
31538061Smsmith
31638061Smsmith    snprintf(cmd, sizeof cmd, "ifconfig %s", devp->name);
31738061Smsmith    if ((ifp = popen(cmd, "r")) == NULL)
31838061Smsmith	return;
31938061Smsmith    while (fgets(data, sizeof(data), ifp) != NULL) {
32038061Smsmith	if (isDebug())
32138061Smsmith	    msgDebug("RTSOL configured interface returns %s\n", data);
32238061Smsmith	if ((cp = strstr(data, "inet6 ")) != NULL) {
32338061Smsmith	    cp += 6;	/* move over keyword */
32438061Smsmith	    if (strncmp(cp, "fe80:", 5)) {
32538061Smsmith		i = 0;
32655939Snsouch		while (*cp != ' ')
32738061Smsmith		    ipv6addr[i++] = *(cp++);
32838061Smsmith		ipv6addr[i] = '\0';
32938061Smsmith	    }
33055939Snsouch	}
33138061Smsmith    }
33238061Smsmith    fclose(ifp);
33338061Smsmith}
33438061Smsmith
33542443Snsouch/* This is it - how to get TCP setup values */
33638061Smsmithint
33738061SmsmithtcpOpenDialog(Device *devp)
33855939Snsouch{
33938061Smsmith    WINDOW              *ds_win, *save = NULL;
34038061Smsmith    ComposeObj          *obj = NULL;
34142443Snsouch    int                 n = 0, filled = 0, cancel = FALSE;
34242443Snsouch    int			max, ret = DITEM_SUCCESS;
34355939Snsouch    int			use_dhcp = FALSE;
34442443Snsouch    int			use_rtsol = FALSE;
34538061Smsmith    char                *tmp;
34655939Snsouch    char		title[80];
34738061Smsmith
34838061Smsmith    save = savescr();
34938061Smsmith    /* Initialise vars from previous device values */
350147256Sbrooks    if (devp->private) {
351111119Simp	DevInfo *di = (DevInfo *)devp->private;
35238061Smsmith
35355939Snsouch	SAFE_STRCPY(ipaddr, di->ipaddr);
35438061Smsmith	SAFE_STRCPY(netmask, di->netmask);
35538061Smsmith	SAFE_STRCPY(extras, di->extras);
35638061Smsmith	use_dhcp = di->use_dhcp;
35755939Snsouch	use_rtsol = di->use_rtsol;
35855939Snsouch    }
35955939Snsouch    else { /* See if there are any defaults */
36055939Snsouch	char *cp;
36155939Snsouch	char *old_interactive = NULL;
36255939Snsouch
36355939Snsouch	/*
36455939Snsouch	 * This is a hack so that the dialogs below are interactive in a
36538061Smsmith	 * script if we have requested interactive behavior.
36638061Smsmith	 */
36738061Smsmith	if (variable_get(VAR_NONINTERACTIVE) &&
36838061Smsmith	  variable_get(VAR_NETINTERACTIVE)) {
36938061Smsmith	    old_interactive = strdup(VAR_NONINTERACTIVE);
37038061Smsmith	    variable_unset(VAR_NONINTERACTIVE);
37138061Smsmith	}
37238061Smsmith
37338061Smsmith
37438061Smsmith	/*
37538061Smsmith	 * Try a RTSOL scan if such behavior is desired.
37638061Smsmith	 * If the variable was configured and is YES, do it.
37738061Smsmith	 * If it was configured to anything else, treat it as NO.
378147256Sbrooks	 * Otherwise, ask the question interactively.
37938061Smsmith	 */
38038061Smsmith	if (!variable_get(VAR_NO_INET6) &&
38138061Smsmith	    (!variable_cmp(VAR_TRY_RTSOL, "YES") ||
382147256Sbrooks	    (variable_get(VAR_TRY_RTSOL)==0 && !msgNoYes("Do you want to try IPv6 configuration of the interface?")))) {
38338061Smsmith	    int i;
38438061Smsmith	    size_t len;
38538061Smsmith
38638061Smsmith	    i = 0;
38738061Smsmith	    sysctlbyname("net.inet6.ip6.forwarding", NULL, 0, &i, sizeof(i));
38838061Smsmith	    i = 1;
38938061Smsmith	    sysctlbyname("net.inet6.ip6.accept_rtadv", NULL, 0, &i, sizeof(i));
39038061Smsmith	    vsystem("ifconfig %s up", devp->name);
39138061Smsmith	    len = sizeof(i);
39238061Smsmith	    sysctlbyname("net.inet6.ip6.dad_count", &i, &len, NULL, 0);
39338061Smsmith	    sleep(i + 1);
39438061Smsmith	    Mkdir("/var/run");
39538061Smsmith	    msgNotify("Scanning for RA servers...");
39638061Smsmith	    if (0 == vsystem("rtsol %s", devp->name)) {
39738061Smsmith		len = sizeof(i);
39838061Smsmith		sysctlbyname("net.inet6.ip6.dad_count", &i, &len, NULL, 0);
39938061Smsmith		sleep(i + 1);
40040626Smsmith		rtsolGetInfo(devp);
40140626Smsmith		use_rtsol = TRUE;
40240626Smsmith	    } else
40340626Smsmith		use_rtsol = FALSE;
40440626Smsmith	}
40540626Smsmith
40640626Smsmith
40738061Smsmith	/*
40838373Sbde	 * First try a DHCP scan if such behavior is desired.
40938061Smsmith	 * If the variable was configured and is YES, do it.
41038061Smsmith	 * If it was configured to anything else, treat it as NO.
41138061Smsmith	 * Otherwise, ask the question interactively.
41238061Smsmith	 */
41338061Smsmith	if (!variable_cmp(VAR_TRY_DHCP, "YES") ||
41438061Smsmith	    (variable_get(VAR_TRY_DHCP)==0 && !msgNoYes("Do you want to try DHCP configuration of the interface?"))) {
41555939Snsouch	    Mkdir("/var/db");
41638061Smsmith	    Mkdir("/var/run");
41755939Snsouch	    Mkdir("/tmp");
41855939Snsouch	    msgNotify("Scanning for DHCP servers...");
41938061Smsmith	    /* XXX clear any existing lease */
42038061Smsmith	    /* XXX limit protocol to N tries */
42138061Smsmith	    if (0 == vsystem("dhclient %s", devp->name)) {
42255939Snsouch		dhcpGetInfo(devp);
42355939Snsouch		use_dhcp = TRUE;
42438061Smsmith	    }
42538061Smsmith	    else
42638061Smsmith		use_dhcp = FALSE;
42738061Smsmith	}
42838061Smsmith
42938061Smsmith	/* Restore old VAR_NONINTERACTIVE if needed. */
43038061Smsmith	if (old_interactive != NULL) {
43155939Snsouch	    variable_set2(VAR_NONINTERACTIVE, old_interactive, 0);
43238061Smsmith	    free(old_interactive);
43342443Snsouch	}
43438061Smsmith
43555939Snsouch	/* Special hack so it doesn't show up oddly in the tcpip setup menu */
43638061Smsmith	if (!strcmp(gateway, "NO"))
43738061Smsmith	    gateway[0] = '\0';
43838061Smsmith
43955939Snsouch	/* Get old IP address from variable space, if available */
44055939Snsouch	if (!ipaddr[0]) {
44138061Smsmith	    if ((cp = variable_get(VAR_IPADDR)) != NULL)
44255939Snsouch		SAFE_STRCPY(ipaddr, cp);
44338061Smsmith	    else if ((cp = variable_get(string_concat3(devp->name, "_", VAR_IPADDR))) != NULL)
44438061Smsmith		SAFE_STRCPY(ipaddr, cp);
44538061Smsmith	}
44655939Snsouch
44755939Snsouch	/* Get old netmask from variable space, if available */
44838061Smsmith	if (!netmask[0]) {
44938061Smsmith	    if ((cp = variable_get(VAR_NETMASK)) != NULL)
45038061Smsmith		SAFE_STRCPY(netmask, cp);
45138061Smsmith	    else if ((cp = variable_get(string_concat3(devp->name, "_", VAR_NETMASK))) != NULL)
45238061Smsmith		SAFE_STRCPY(netmask, cp);
45343773Sdes	}
45443773Sdes
45543773Sdes	/* Get old extras string from variable space, if available */
456123922Ssam	if (!extras[0]) {
45743773Sdes	    if ((cp = variable_get(VAR_EXTRAS)) != NULL)
45843773Sdes		SAFE_STRCPY(extras, cp);
45943773Sdes	    else if ((cp = variable_get(string_concat3(devp->name, "_", VAR_EXTRAS))) != NULL)
46055939Snsouch		SAFE_STRCPY(extras, cp);
46138061Smsmith	}
46255939Snsouch    }
46355939Snsouch
46455939Snsouch    /* Look up values already recorded with the system, or blank the string variables ready to accept some new data */
46538061Smsmith    if (!hostname[0]) {
46638061Smsmith	tmp = variable_get(VAR_HOSTNAME);
46738061Smsmith	if (tmp)
46838061Smsmith	    SAFE_STRCPY(hostname, tmp);
46938061Smsmith    }
47038061Smsmith    if (!domainname[0]) {
47138061Smsmith	tmp = variable_get(VAR_DOMAINNAME);
472147256Sbrooks	if (tmp)
47338061Smsmith	    SAFE_STRCPY(domainname, tmp);
47438061Smsmith    }
47555939Snsouch    if (!gateway[0]) {
47638061Smsmith	tmp = variable_get(VAR_GATEWAY);
47738061Smsmith	if (tmp && strcmp(tmp, "NO"))
47855939Snsouch	    SAFE_STRCPY(gateway, tmp);
47938061Smsmith    }
48038061Smsmith    if (!nameserver[0]) {
48138061Smsmith	tmp = variable_get(VAR_NAMESERVER);
48255939Snsouch	if (tmp)
48338061Smsmith	    SAFE_STRCPY(nameserver, tmp);
48438061Smsmith    }
48538061Smsmith
486147256Sbrooks    /* If non-interactive, jump straight over the dialog crap and into config section */
48738061Smsmith    if (variable_get(VAR_NONINTERACTIVE) &&
48838061Smsmith	!variable_get(VAR_NETINTERACTIVE)) {
48938061Smsmith	if (!hostname[0])
49038061Smsmith	    msgConfirm("WARNING: hostname variable not set and is a non-optional\n"
49138061Smsmith		       "parameter.  Please add this to your installation script\n"
49255939Snsouch		       "or set the netInteractive variable (see sysinstall man page)");
49338061Smsmith	else
49438061Smsmith	    goto netconfig;
49538061Smsmith    }
49638061Smsmith
49738061Smsmith    /* Now do all the screen I/O */
49838061Smsmith    dialog_clear_norefresh();
49955939Snsouch
50038061Smsmith    /* Modify the help line for PLIP config */
50138061Smsmith    if (!strncmp(devp->name, "plip", 4))
50238061Smsmith	layout[LAYOUT_EXTRAS].help =
50338061Smsmith         "For PLIP configuration, you must enter the peer's IP address here.";
50438061Smsmith
50538061Smsmith    /* We need a curses window */
50638061Smsmith    tmp = " Network Configuration ";
50738061Smsmith    if (ipv6addr[0])
50838061Smsmith	tmp = string_concat(tmp, "(IPv6 ready) ");
50938061Smsmith    if (!(ds_win = openLayoutDialog(TCP_HELPFILE, tmp,
51038061Smsmith				    TCP_DIALOG_X, TCP_DIALOG_Y, TCP_DIALOG_WIDTH, TCP_DIALOG_HEIGHT))) {
511147256Sbrooks	beep();
512147256Sbrooks	msgConfirm("Cannot open TCP/IP dialog window!!");
513147256Sbrooks	restorescr(save);
51438061Smsmith	return DITEM_FAILURE;
515147256Sbrooks    }
516147256Sbrooks
517134391Sandre    /* Draw interface configuration box */
51838061Smsmith    draw_box(ds_win, TCP_DIALOG_Y + 9, TCP_DIALOG_X + 8, TCP_DIALOG_HEIGHT - 13, TCP_DIALOG_WIDTH - 17,
51938061Smsmith	     dialog_attr, border_attr);
52038061Smsmith    wattrset(ds_win, dialog_attr);
52155939Snsouch    sprintf(title, " Configuration for Interface %s ", devp->name);
522147256Sbrooks    mvwaddstr(ds_win, TCP_DIALOG_Y + 9, TCP_DIALOG_X + 14, title);
52338061Smsmith
52438061Smsmith    /* Some more initialisation before we go into the main input loop */
52538061Smsmith    obj = initLayoutDialog(ds_win, layout, TCP_DIALOG_X, TCP_DIALOG_Y, &max);
52655939Snsouch
52755939Snsouchreenter:
52838061Smsmith    cancelbutton = okbutton = 0;
52938061Smsmith    while (layoutDialogLoop(ds_win, layout, &obj, &n, max, &cancelbutton, &cancel)) {
53055939Snsouch	/* Prevent this from being irritating if user really means NO */
53138061Smsmith	if (filled < 3) {
53238061Smsmith	    /* Insert a default value for the netmask, 0xffffff00 is
53355939Snsouch	     * the most appropriate one (entire class C, or subnetted
53455939Snsouch	     * class A/B network).
53538061Smsmith	     */
53638061Smsmith	    if (!netmask[0]) {
53738061Smsmith		strcpy(netmask, "255.255.255.0");
53838061Smsmith		RefreshStringObj(layout[LAYOUT_NETMASK].obj);
53955939Snsouch		++filled;
54038061Smsmith	    }
54155939Snsouch	    if (!index(hostname, '.') && domainname[0]) {
54238061Smsmith		strcat(hostname, ".");
54338061Smsmith		strcat(hostname, domainname);
54438061Smsmith		RefreshStringObj(layout[LAYOUT_HOSTNAME].obj);
54538061Smsmith		++filled;
54638061Smsmith	    }
54738061Smsmith	    else if (((tmp = index(hostname, '.')) != NULL) && !domainname[0]) {
54838061Smsmith		SAFE_STRCPY(domainname, tmp + 1);
54938061Smsmith		RefreshStringObj(layout[LAYOUT_DOMAINNAME].obj);
55038061Smsmith		++filled;
55138061Smsmith	    }
55238061Smsmith	}
55338061Smsmith    }
55438061Smsmith    if (!cancel && !verifySettings())
55538061Smsmith	goto reenter;
556147256Sbrooks
557147256Sbrooks    /* Clear this crap off the screen */
558147256Sbrooks    delwin(ds_win);
55938061Smsmith    dialog_clear_norefresh();
560147256Sbrooks    use_helpfile(NULL);
561147256Sbrooks
562134391Sandre    /* We actually need to inform the rest of sysinstall about this
56338061Smsmith       data now if the user hasn't selected cancel.  Save the stuff
56438061Smsmith       out to the environment via the variable_set() mechanism */
56538061Smsmith
56638061Smsmithnetconfig:
56738061Smsmith    if (!cancel) {
56855939Snsouch	DevInfo *di;
56938061Smsmith	char temp[512], ifn[255];
570147256Sbrooks	int ipv4_enable = FALSE;
57138061Smsmith
57238061Smsmith	if (hostname[0]) {
57338061Smsmith	    variable_set2(VAR_HOSTNAME, hostname, 1);
57438061Smsmith	    sethostname(hostname, strlen(hostname));
57538061Smsmith	}
57638061Smsmith	if (domainname[0])
57738061Smsmith	    variable_set2(VAR_DOMAINNAME, domainname, 0);
57855939Snsouch	if (gateway[0])
57955939Snsouch	    variable_set2(VAR_GATEWAY, gateway, use_dhcp ? 0 : 1);
580147256Sbrooks	if (nameserver[0])
58138061Smsmith	    variable_set2(VAR_NAMESERVER, nameserver, 0);
58238061Smsmith	if (ipaddr[0])
58338061Smsmith	    variable_set2(VAR_IPADDR, ipaddr, 0);
58438061Smsmith	if (ipv6addr[0])
58538061Smsmith	    variable_set2(VAR_IPV6ADDR, ipv6addr, 0);
58638061Smsmith
58738061Smsmith	if (!devp->private)
58838061Smsmith	    devp->private = (DevInfo *)safe_malloc(sizeof(DevInfo));
58938061Smsmith	di = devp->private;
59055939Snsouch	SAFE_STRCPY(di->ipaddr, ipaddr);
59138061Smsmith	SAFE_STRCPY(di->netmask, netmask);
59255939Snsouch	SAFE_STRCPY(di->extras, extras);
59355939Snsouch	di->use_dhcp = use_dhcp;
59438061Smsmith	di->use_rtsol = use_rtsol;
59538061Smsmith
59655939Snsouch	if (use_dhcp || ipaddr[0])
59755939Snsouch	    ipv4_enable = TRUE;
59838061Smsmith	if (ipv4_enable) {
59938061Smsmith	    sprintf(ifn, "%s%s", VAR_IFCONFIG, devp->name);
60038061Smsmith	    if (use_dhcp) {
60138061Smsmith		if (strlen(extras) > 0)
60238061Smsmith		    sprintf(temp, "DHCP %s", extras);
60338061Smsmith		else
60438061Smsmith		    sprintf(temp, "DHCP");
60538061Smsmith	    } else
60638061Smsmith		sprintf(temp, "inet %s %s netmask %s",
607121816Sbrooks			ipaddr, extras, netmask);
60855939Snsouch	    variable_set2(ifn, temp, 1);
60938061Smsmith	}
61038061Smsmith	if (use_rtsol)
61138061Smsmith	    variable_set2(VAR_IPV6_ENABLE, "YES", 1);
61238061Smsmith	if (!use_dhcp)
61338061Smsmith	    configResolv(NULL);	/* XXX this will do it on the MFS copy XXX */
61443773Sdes	ret = DITEM_SUCCESS;
61538061Smsmith    }
61638061Smsmith    else
61738061Smsmith	ret = DITEM_FAILURE;
61838061Smsmith    restorescr(save);
61938061Smsmith    return ret;
62038061Smsmith}
62138061Smsmith
62238061Smsmithstatic Device *NetDev;
62338061Smsmith
62438061Smsmithstatic int
62555939SnsouchnetHook(dialogMenuItem *self)
62638061Smsmith{
62738061Smsmith    Device **devs;
62838061Smsmith
62955939Snsouch    devs = deviceFindDescr(self->prompt, self->title, DEVICE_TYPE_NETWORK);
63038061Smsmith    if (devs) {
63155939Snsouch	if (DITEM_STATUS(tcpOpenDialog(devs[0])) != DITEM_FAILURE)
63238061Smsmith	    NetDev = devs[0];
63338061Smsmith	else
63438061Smsmith	    NetDev = NULL;
63538061Smsmith    }
63655939Snsouch    return devs ? DITEM_LEAVE_MENU : DITEM_FAILURE;
63755939Snsouch}
63838061Smsmith
63938061Smsmith/* Get a network device */
64038061SmsmithDevice *
64138061SmsmithtcpDeviceSelect(void)
64238061Smsmith{
64338061Smsmith    DMenu *menu;
64438061Smsmith    Device **devs, *rval;
64538061Smsmith    int cnt;
64638061Smsmith
64738061Smsmith    devs = deviceFind(variable_get(VAR_NETWORK_DEVICE), DEVICE_TYPE_NETWORK);
64838061Smsmith    cnt = deviceCount(devs);
64938061Smsmith    rval = NULL;
65055939Snsouch
65138061Smsmith    if (!cnt) {
65255939Snsouch	msgConfirm("No network devices available!");
65338061Smsmith	return NULL;
65438061Smsmith    }
65538061Smsmith    else if ((!RunningAsInit) && (variable_check("NETWORK_CONFIGURED=NO") != TRUE)) {
65638061Smsmith	if (!msgYesNo("Running multi-user, assume that the network is already configured?"))
65755939Snsouch	    return devs[0];
65838061Smsmith    }
65938061Smsmith    if (cnt == 1) {
66038061Smsmith	if (DITEM_STATUS(tcpOpenDialog(devs[0]) == DITEM_SUCCESS))
66138061Smsmith	    rval = devs[0];
66255939Snsouch    }
66338061Smsmith    else if (variable_get(VAR_NONINTERACTIVE) && variable_get(VAR_NETWORK_DEVICE)) {
66455939Snsouch	devs = deviceFind(variable_get(VAR_NETWORK_DEVICE), DEVICE_TYPE_NETWORK);
66538061Smsmith	cnt = deviceCount(devs);
66638061Smsmith	if (cnt) {
66738061Smsmith	    if (DITEM_STATUS(tcpOpenDialog(devs[0]) == DITEM_SUCCESS))
66838061Smsmith		rval = devs[0];
66938061Smsmith	}
67038061Smsmith    }
67143773Sdes    else {
67243773Sdes	int status;
67338061Smsmith
67455939Snsouch	menu = deviceCreateMenu(&MenuNetworkDevice, DEVICE_TYPE_NETWORK, netHook, NULL);
67538061Smsmith	if (!menu)
67638061Smsmith	    msgFatal("Unable to create network device menu!  Argh!");
67738061Smsmith	status = dmenuOpenSimple(menu, FALSE);
67838061Smsmith	free(menu);
67938061Smsmith	if (status)
68055939Snsouch	    rval = NetDev;
68138061Smsmith    }
68238061Smsmith    return rval;
68338061Smsmith}
68455939Snsouch
68538061Smsmith/* Do it from a menu that doesn't care about status */
68638061Smsmithint
68738061SmsmithtcpMenuSelect(dialogMenuItem *self)
68838061Smsmith{
68938061Smsmith    Device *tmp;
69038061Smsmith    WINDOW *save;
69138061Smsmith
69238061Smsmith    variable_set("NETWORK_CONFIGURED=NO",0);
69338061Smsmith    tmp = tcpDeviceSelect();
69438061Smsmith    variable_unset("NETWORK_CONFIGURED");
69543773Sdes    save = savescr();
69643773Sdes    if (tmp && tmp->private && !((DevInfo *)tmp->private)->use_dhcp && !msgYesNo("Would you like to bring the %s interface up right now?", tmp->name))
69738061Smsmith	if (!DEVICE_INIT(tmp))
69838061Smsmith	    msgConfirm("Initialization of %s device failed.", tmp->name);
69938061Smsmith    restorescr(save);
70038061Smsmith    return DITEM_SUCCESS;
70155939Snsouch}
70238061Smsmith