tcpip.c revision 8800
1/* 2 * $Id: tcpip.c,v 1.22 1995/05/27 23:39:34 phk Exp $ 3 * 4 * Copyright (c) 1995 5 * Gary J Palmer. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer, 12 * verbatim and that no modifications are made prior to this 13 * point in the file. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by Gary J Palmer 20 * for the FreeBSD Project. 21 * 4. The name of Gary J Palmer or the FreeBSD Project may 22 * not be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY GARY J PALMER ``AS IS'' AND ANY EXPRESS OR 26 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 27 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28 * IN NO EVENT SHALL GARY J PALMER BE LIABLE FOR ANY DIRECT, INDIRECT, 29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 31 * OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 32 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 33 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 * 36 */ 37 38/* 39 * All kinds of hacking also performed by jkh on this code. Don't 40 * blame Gary for every bogosity you see here.. :-) 41 * 42 * -jkh 43 */ 44 45#include <stdio.h> 46#include <stdlib.h> 47#include <unistd.h> 48#include <sys/param.h> 49#include <string.h> 50#include <dialog.h> 51#include "ui_objects.h" 52#include "dir.h" 53#include "dialog.priv.h" 54#include "colors.h" 55#include "rc.h" 56#include "sysinstall.h" 57 58#define HOSTNAME_FIELD_LEN 256 59#define IPADDR_FIELD_LEN 16 60#define EXTRAS_FIELD_LEN 256 61 62/* These are nasty, but they make the layout structure a lot easier ... */ 63 64static char hostname[HOSTNAME_FIELD_LEN], domainname[HOSTNAME_FIELD_LEN], 65 gateway[IPADDR_FIELD_LEN], nameserver[IPADDR_FIELD_LEN]; 66static int okbutton, cancelbutton; 67static char ipaddr[IPADDR_FIELD_LEN], netmask[IPADDR_FIELD_LEN], extras[EXTRAS_FIELD_LEN]; 68 69/* What the screen size is meant to be */ 70#define TCP_DIALOG_Y 0 71#define TCP_DIALOG_X 8 72#define TCP_DIALOG_WIDTH COLS - 16 73#define TCP_DIALOG_HEIGHT LINES - 2 74 75/* This is the structure that Network devices carry around in their private, erm, structures */ 76typedef struct _devPriv { 77 char ipaddr[IPADDR_FIELD_LEN]; 78 char netmask[IPADDR_FIELD_LEN]; 79 char extras[EXTRAS_FIELD_LEN]; 80} DevInfo; 81 82/* The screen layout structure */ 83typedef struct _layout { 84 int y; /* x & Y co-ordinates */ 85 int x; 86 int len; /* The size of the dialog on the screen */ 87 int maxlen; /* How much the user can type in ... */ 88 char *prompt; /* The string for the prompt */ 89 char *help; /* The display for the help line */ 90 void *var; /* The var to set when this changes */ 91 int type; /* The type of the dialog to create */ 92 void *obj; /* The obj pointer returned by libdialog */ 93} Layout; 94 95static Layout layout[] = { 96{ 1, 2, 25, HOSTNAME_FIELD_LEN - 1, 97 "Host name:", "The name of your machine on a network, e.g. foo.bar.com", 98 hostname, STRINGOBJ, NULL }, 99#define LAYOUT_HOSTNAME 0 100{ 1, 35, 20, HOSTNAME_FIELD_LEN - 1, 101 "Domain name:", 102 "The name of the domain that your machine is in, e.g. bar.com", 103 domainname, STRINGOBJ, NULL }, 104#define LAYOUT_DOMAINNAME 1 105{ 5, 2, 18, IPADDR_FIELD_LEN - 1, 106 "Gateway:", 107 "IP address of host forwarding packets to non-local destinations", 108 gateway, STRINGOBJ, NULL }, 109#define LAYOUT_GATEWAY 2 110{ 5, 35, 18, IPADDR_FIELD_LEN - 1, 111 "Name server:", "IP address of your local DNS server", 112 nameserver, STRINGOBJ, NULL }, 113#define LAYOUT_NAMESERVER 3 114{ 10, 10, 18, IPADDR_FIELD_LEN - 1, 115 "IP Address:", 116 "The IP address to be used for this interface", 117 ipaddr, STRINGOBJ, NULL }, 118#define LAYOUT_IPADDR 5 119{ 10, 35, 18, IPADDR_FIELD_LEN - 1, 120 "Netmask:", 121 "The netmask for this interfaace, e.g. 0xffffff00 for a class C network", 122 netmask, STRINGOBJ, NULL }, 123#define LAYOUT_NETMASK 6 124{ 14, 10, 37, HOSTNAME_FIELD_LEN - 1, 125 "Extra options to ifconfig:", 126 "Any interface-specific options to ifconfig you would like to use", 127 extras, STRINGOBJ, NULL }, 128#define LAYOUT_EXTRAS 7 129{ 19, 15, 0, 0, 130 "OK", "Select this if you are happy with these settings", 131 &okbutton, BUTTONOBJ, NULL }, 132#define LAYOUT_OKBUTTON 8 133{ 19, 35, 0, 0, 134 "CANCEL", "Select this if you wish to cancel this screen", 135 &cancelbutton, BUTTONOBJ, NULL }, 136#define LAYOUT_CANCELBUTTON 9 137{ NULL }, 138}; 139 140#define _validByte(b) ((b) >= 0 && (b) < 255) 141 142/* whine */ 143static void 144feepout(char *msg) 145{ 146 beep(); 147 dialog_notify(msg); 148} 149 150/* Very basic IP address integrity check - could be drastically improved */ 151static int 152verifyIP(char *ip) 153{ 154 int a, b, c, d; 155 156 if (ip && sscanf(ip, "%d.%d.%d.%d", &a, &b, &c, &d) == 4 && 157 _validByte(a) && _validByte(b) && _validByte(c) && 158 _validByte(d)) 159 return 1; 160 else 161 return 0; 162} 163 164/* Check for the settings on the screen - the per interface stuff is 165 moved to the main handling code now to do it on the fly - sigh */ 166 167static int 168verifySettings(void) 169{ 170 if (!hostname[0]) 171 feepout("Must specify a host name of some sort!"); 172 else if (gateway[0] && !verifyIP(gateway)) 173 feepout("Invalid gateway IP address specified"); 174 else if (nameserver[0] && !verifyIP(nameserver)) 175 feepout("Invalid name server IP address specified"); 176 else if (netmask[0] && (netmask[0] < '0' && netmask[0] > '3')) 177 feepout("Invalid netmask value"); 178 else if (ipaddr[0] && !verifyIP(ipaddr)) 179 feepout("Invalid IP address"); 180 else 181 return 1; 182 return 0; 183} 184 185/* This is it - how to get TCP setup values */ 186int 187tcpOpenDialog(Device *devp) 188{ 189 WINDOW *ds_win; 190 ComposeObj *obj = NULL; 191 ComposeObj *first, *last; 192 int n=0, quit=FALSE, cancel=FALSE, ret; 193 int max; 194 char *tmp; 195 char help[FILENAME_MAX]; 196 197 /* We need a curses window */ 198 ds_win = newwin(LINES, COLS, 0, 0); 199 if (ds_win == 0) 200 msgFatal("Cannot open TCP/IP dialog window!!"); 201 202 /* Say where our help comes from */ 203 systemHelpFile(TCP_HELPFILE, help); 204 use_helpfile(help); 205 206 /* Setup a nice screen for us to splat stuff onto */ 207 draw_box(ds_win, TCP_DIALOG_Y, TCP_DIALOG_X, TCP_DIALOG_HEIGHT, TCP_DIALOG_WIDTH, dialog_attr, border_attr); 208 wattrset(ds_win, dialog_attr); 209 mvprintw(ds_win, TCP_DIALOG_Y, TCP_DIALOG_X + 20, " Interface %s ", devp->name); 210 211 draw_box(ds_win, TCP_DIALOG_Y + 9, TCP_DIALOG_X + 8, TCP_DIALOG_HEIGHT - 13, TCP_DIALOG_WIDTH - 17, 212 dialog_attr, border_attr); 213 wattrset(ds_win, dialog_attr); 214 mvwaddstr(ds_win, TCP_DIALOG_Y + 9, TCP_DIALOG_X + 16, " Per Interface Configuration "); 215 216 /* Initialise vars from previous device values */ 217 if (devp->private) { 218 DevInfo *di = (DevInfo *)devp->private; 219 220 strcpy(ipaddr, di->ipaddr); 221 strcpy(netmask, di->netmask); 222 strcpy(extras, di->extras); 223 } 224 else 225 ipaddr[0] = netmask[0] = extras[0] = '\0'; 226 227 /* Look up values already recorded with the system, or blank the string variables ready to accept some new data */ 228 tmp = getenv(VAR_HOSTNAME); 229 if (tmp) 230 strcpy(hostname, tmp); 231 else 232 bzero(hostname, sizeof(hostname)); 233 tmp = getenv(VAR_DOMAINNAME); 234 if (tmp) 235 strcpy(domainname, tmp); 236 else 237 bzero(domainname, sizeof(domainname)); 238 tmp = getenv(VAR_GATEWAY); 239 if (tmp) 240 strcpy(gateway, tmp); 241 else 242 bzero(gateway, sizeof(gateway)); 243 tmp = getenv(VAR_NAMESERVER); 244 if (tmp) 245 strcpy(nameserver, tmp); 246 else 247 bzero(nameserver, sizeof(nameserver)); 248 249 /* Loop over the layout list, create the objects, and add them 250 onto the chain of objects that dialog uses for traversal*/ 251 n = 0; 252#define lt layout[n] 253 while (lt.help != NULL) { 254 switch (lt.type) { 255 case STRINGOBJ: 256 lt.obj = NewStringObj(ds_win, lt.prompt, lt.var, 257 lt.y + TCP_DIALOG_Y, lt.x + TCP_DIALOG_X, 258 lt.len, lt.maxlen); 259 break; 260 261 case BUTTONOBJ: 262 lt.obj = NewButtonObj(ds_win, lt.prompt, lt.var, 263 lt.y + TCP_DIALOG_Y, lt.x + TCP_DIALOG_X); 264 break; 265 266 default: 267 msgFatal("Don't support this object yet!"); 268 } 269 AddObj(&obj, lt.type, (void *) lt.obj); 270 n++; 271 } 272 max = n - 1; 273 274 /* Find the last object we can traverse to */ 275 last = obj; 276 while (last->next) 277 last = last->next; 278 279 /* Find the first object in the list */ 280 first = obj; 281 while (first->prev) 282 first = first->prev; 283 284 /* Some more initialisation before we go into the main input loop */ 285 n = 0; 286 cancelbutton = okbutton = 0; 287 288 /* Incoming user data - DUCK! */ 289 while (!quit) { 290 char help_line[80]; 291 int i, len = strlen(lt.help); 292 293 /* Display the help line at the bottom of the screen */ 294 for (i = 0; i < 79; i++) 295 help_line[i] = (i < len) ? lt.help[i] : ' '; 296 help_line[i] = '\0'; 297 use_helpline(help_line); 298 display_helpline(ds_win, LINES - 1, COLS - 1); 299 300 /* Ask for libdialog to do its stuff */ 301 ret = PollObj(&obj); 302 303 /* We are in the Hostname field - calculate the domainname */ 304 if (n == 0) { 305 if ((tmp = index(hostname, '.')) != NULL) { 306 strncpy(domainname, tmp + 1, strlen(tmp + 1)); 307 domainname[strlen(tmp+1)] = '\0'; 308 RefreshStringObj(layout[1].obj); 309 } 310 } 311 312 /* Handle special case stuff that libdialog misses. Sigh */ 313 switch (ret) { 314 /* Bail out */ 315 case SEL_ESC: 316 quit = TRUE, cancel=TRUE; 317 break; 318 319 /* This doesn't work for list dialogs. Oh well. Perhaps 320 should special case the move from the OK button ``up'' 321 to make it go to the interface list, but then it gets 322 awkward for the user to go back and correct screw up's 323 in the per-interface section */ 324 325 case KEY_UP: 326 if (obj->prev !=NULL ) { 327 obj = obj->prev; 328 --n; 329 } else { 330 obj = last; 331 n = max; 332 } 333 break; 334 335 case KEY_DOWN: 336 if (obj->next != NULL) { 337 obj = obj->next; 338 ++n; 339 } else { 340 obj = first; 341 n = 0; 342 } 343 break; 344 345 case SEL_TAB: 346 if (n < max) 347 ++n; 348 else 349 n = 0; 350 break; 351 352 /* The user has pressed enter over a button object */ 353 case SEL_BUTTON: 354 if (cancelbutton) 355 cancel = TRUE, quit = TRUE; 356 else { 357 if (verifySettings()) 358 quit = TRUE; 359 } 360 break; 361 362 /* Generic CR handler */ 363 case SEL_CR: 364 if (n < max) 365 ++n; 366 else 367 n = 0; 368 break; 369 370 case SEL_BACKTAB: 371 if (n) 372 --n; 373 else 374 n = max; 375 break; 376 377 case KEY_F(1): 378 display_helpfile(); 379 380 /* They tried some key combination we don't support - tell them! */ 381 default: 382 beep(); 383 } 384 385 /* BODGE ALERT! */ 386 if (((tmp = index(hostname, '.')) != NULL) && (strlen(domainname)==0)) { 387 strncpy(domainname, tmp + 1, strlen(tmp + 1)); 388 domainname[strlen(tmp+1)] = '\0'; 389 RefreshStringObj(layout[1].obj); 390 } 391 } 392 393 /* Clear this crap off the screen */ 394 dialog_clear(); 395 refresh(); 396 use_helpfile(NULL); 397 398 /* We actually need to inform the rest of sysinstall about this 399 data now - if the user hasn't selected cancel, save the stuff 400 out to the environment via the variable_set layers */ 401 402 if (!cancel) { 403 DevInfo *di; 404 char temp[512], ifn[64]; 405 406 variable_set2(VAR_HOSTNAME, hostname); 407 variable_set2(VAR_DOMAINNAME, domainname); 408 if (gateway[0]) 409 variable_set2(VAR_GATEWAY, gateway); 410 if (nameserver[0]) 411 variable_set2(VAR_NAMESERVER, nameserver); 412 413 if (!devp->private) 414 devp->private = (DevInfo *)malloc(sizeof(DevInfo)); 415 di = devp->private; 416 strcpy(di->ipaddr, ipaddr); 417 strcpy(di->netmask, netmask); 418 strcpy(di->extras, extras); 419 420 sprintf(temp, "inet %s %s netmask %s", ipaddr, extras, netmask); 421 sprintf(ifn, "%s%s", VAR_IFCONFIG, devp->name); 422 variable_set2(ifn, temp); 423 sprintf(ifn, "%s %s", devp->name, getenv(VAR_INTERFACES) ? getenv(VAR_INTERFACES) : ""); 424 variable_set2(VAR_INTERFACES, ifn); 425 if (ipaddr[0]) 426 variable_set2(VAR_IPADDR, ipaddr); 427 return 0; 428 } 429 return 1; 430} 431 432static int 433netHook(char *str) 434{ 435 Device **devs; 436 437 /* Clip garbage off the ends */ 438 string_prune(str); 439 str = string_skipwhite(str); 440 if (!*str) 441 return 0; 442 devs = deviceFind(str, DEVICE_TYPE_NETWORK); 443 if (devs) { 444 tcpOpenDialog(devs[0]); 445 mediaDevice = devs[0]; 446 } 447 return devs ? 1 : 0; 448} 449 450/* Get a network device */ 451int 452tcpDeviceSelect(char *str) 453{ 454 DMenu *menu; 455 456 menu = deviceCreateMenu(&MenuNetworkDevice, DEVICE_TYPE_NETWORK, netHook); 457 if (!menu) 458 msgFatal("Unable to create network device menu! Argh!"); 459 dmenuOpenSimple(menu); 460 free(menu); 461 return 0; 462} 463 464/* Start PPP on the 3rd screen */ 465Boolean 466tcpStartPPP(Device *devp) 467{ 468 int fd; 469 FILE *fp; 470 char *val; 471 char myaddr[16], provider[16]; 472 473 fd = open("/dev/ttyv2", O_RDWR); 474 if (fd == -1) 475 return FALSE; 476 Mkdir("/var/log", NULL); 477 Mkdir("/var/spool/lock", NULL); 478 Mkdir("/etc/ppp", NULL); 479 vsystem("touch /etc/ppp/ppp.linkup; chmod +x /etc/ppp/ppp.linkup"); 480 vsystem("touch /etc/ppp/ppp.secret; chmod +x /etc/ppp/ppp.secret"); 481 fp = fopen("/etc/ppp/ppp.conf", "w"); 482 if (!fp) { 483 msgConfirm("Couldn't open /etc/ppp/ppp.conf file! This isn't going to work"); 484 return FALSE; 485 } 486 fprintf(fp, "default:\n"); 487 fprintf(fp, " set device %s\n", devp->devname); 488 val = msgGetInput("115200", 489"Enter baud rate for your modem - this can be higher than the actual\nmaximum data rate since most modems can talk at one speed to the\ncomputer and at another speed to the remote end.\n\nIf you're not sure what to put here, just select the default."); 490 if (!val) 491 val = "115200"; 492 fprintf(fp, " set speed %s\n", val); 493 if (getenv(VAR_GATEWAY)) 494 strcpy(provider, getenv(VAR_GATEWAY)); 495 else 496 strcpy(provider, "0"); 497 val = msgGetInput(provider, "Enter the IP address of your service provider or 0 if you\ndon't know it and would prefer to negotiate it dynamically."); 498 if (!val) 499 val = "0"; 500 if (devp->private && ((DevInfo *)devp->private)->ipaddr[0]) 501 strcpy(myaddr, ((DevInfo *)devp->private)->ipaddr); 502 else 503 strcpy(myaddr, "0"); 504 fprintf(fp, " set ifaddr %s %s\n", myaddr, val); 505 fclose(fp); 506 if (!fork()) { 507 dup2(fd, 0); 508 dup2(fd, 1); 509 dup2(fd, 2); 510 execl("/stand/ppp", "/stand/ppp", (char *)NULL); 511 exit(1); 512 } 513 msgConfirm("The PPP command is now started on screen 3 (type ALT-F3 to\ninteract with it, ALT-F1 to switch back here). The only command\nyou'll probably want or need to use is the \"term\" command\nwhich starts a terminal emulator you can use to talk to your\nmodem and dial the service provider. Once you're connected,\ncome back to this screen and hit return. DO NOT PRESS RETURN\nHERE UNTIL THE CONNECTION IS FULLY ESTABLISHED!"); 514 return TRUE; 515} 516