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