revert between 56095 -> 55830 in arch
[AROS.git] / workbench / network / stacks / AROSTCP / bsdsocket / kern / amiga_config.c
blob6afc4c4879bcefe57272e4f07b3389719f591ec5
1 /*
2 * amiga_config.c --- Configuring AmiTCP/IP
4 * Copyright (C) 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>
5 * Helsinki University of Technology, Finland.
6 * All rights reserved.
7 * Copyright (C) 2005 - 2007 The AROS Dev Team
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
21 * MA 02111-1307, USA.
25 #include <conf.h>
27 #include <sys/param.h>
28 #include <sys/systm.h>
29 #include <sys/syslog.h>
30 #include <sys/socket.h>
31 #include <sys/malloc.h>
32 #include <sys/mbuf.h>
34 #include <netdb.h> /* pathnames */
36 #include <kern/amiga_gui.h>
37 #include <kern/amiga_includes.h>
38 #include <kern/amiga_config.h>
39 #include <kern/amiga_netdb.h>
40 #include <utility/tagitem.h>
41 #include <dos/rdargs.h>
43 #include <proto/dos.h>
45 #include "net/netdbpaths.h"
46 #include <net/route.h>
47 #include <netinet/in_systm.h>
48 #include <netinet/in.h>
49 #include <netinet/ip.h>
50 #include <netinet/in_pcb.h>
51 #include <netinet/ip_var.h>
52 #include <netinet/ip_icmp.h>
53 #include <netinet/icmp_var.h>
54 #include <netinet/tcp.h>
55 #include <netinet/tcp_timer.h>
56 #include <netinet/tcp_var.h>
57 #include <netinet/udp.h>
58 #include <netinet/udp_var.h>
60 /* External functions */
61 int ultoa(unsigned long ul,char *buffer);
63 extern struct Task *AROSTCP_Task; /* referenced by sendbreak() */
65 /* Parsing error messages */
66 UBYTE ERR_UNKNOWN[] = "Unknown command";
67 UBYTE ERR_ILLEGAL_VAR[] = "%s: unknown variable %s";
68 UBYTE ERR_ILLEGAL_IND[] = "%s: unknown index %s";
69 UBYTE ERR_SYNTAX[] = "Syntax error";
70 UBYTE ERR_TOO_LONG[] = "Result too long";
71 UBYTE ERR_MEMORY[] = "Memory exhausted";
72 UBYTE ERR_NONETDB[] = "No active net database";
73 UBYTE ERR_VALUE[] = "Illegal value";
74 UBYTE ERR_NOWRITE[] = "%s: Variable %s is not writeable";
76 /* Command-line template */
77 const TEXT cmd_template[] = "WITH/K,NOO=NOCONFIG/S,DEBUG/S";
79 /* Array of parsing functions. Note that the order is same as in the
80 * enum keyword.
82 var_f rexx_parse_funs[] = {
83 getvalue, /* KEY_QUERY */
84 setvalue, /* KEY_SET */
85 readfile, /* KEY_READ */
86 parseroute, /* KEY_ROUTE */
87 do_netdb, /* KEY_ADD */
88 reset_netdb, /* KEY_RESET */
89 sendbreak /* KEY_KILL */
93 * Parse a Rexx command line
95 LONG
96 parseline(struct CSource *csarg, UBYTE **errstrp, struct CSource *res)
98 UBYTE Buffer[KEYWORDLEN];
99 enum keyword keyword;
101 /* Parse the command keyword */
102 LONG item = ReadItem(Buffer, sizeof(Buffer), csarg);
104 if (item == 0)
105 return RETURN_OK;
106 else if (item < 0) {
107 *errstrp = ERR_SYNTAX;
108 return RETURN_WARN;
111 if ((keyword = FindArg((UBYTE*)REXXKEYWORDS, Buffer)) < 0) {
112 *errstrp = ERR_UNKNOWN;
113 return RETURN_WARN;
116 return rexx_parse_funs[keyword](csarg, errstrp, res);
120 * 'Parse' the "KILL" command
122 LONG
123 sendbreak(struct CSource *args, UBYTE **errstrp, struct CSource *res)
125 Signal(AROSTCP_Task, SIGBREAKF_CTRL_C);
126 return RETURN_OK;
129 extern UBYTE *KW_VARS;
130 extern struct cfg_variable variables[];
133 * Parse the "Query" commands
135 LONG
136 getvalue(struct CSource *args, UBYTE **errstrp, struct CSource *res)
138 UBYTE Buffer[KEYWORDLEN];
139 WORD var, index;
140 LONG vlen;
141 UBYTE *value = NULL;
143 Buffer[0] = '\0';
145 while ((var = ReadItem(Buffer, sizeof(Buffer), args)) > 0) {
146 if ((var = FindArg(KW_VARS, Buffer)) < 0 ||
147 (variables[var].flags & VF_READ) != VF_READ) {
148 res->CS_CurChr = 0;
149 csprintf(res, ERR_ILLEGAL_VAR, "getvalue", Buffer);
150 *errstrp = res->CS_Buffer;
151 return RETURN_WARN;
152 } else {
154 if (variables[var].flags & VF_TABLE) {
155 if (ReadItem(Buffer, sizeof(Buffer), args) <= 0 ||
156 (index = FindArg((UBYTE *)variables[var].index, Buffer)) < 0) {
157 res->CS_CurChr = 0;
158 csprintf(res, ERR_ILLEGAL_IND, "getvalue", Buffer);
159 *errstrp = res->CS_Buffer;
160 return RETURN_WARN;
162 } else {
163 index = 0;
166 switch (variables[var].type) {
167 case VAR_FUNC:
168 if (variables[var].value) {
169 if (vlen = (*(var_f)(variables[var].value))(args, errstrp, res))
170 return vlen;
171 } else {
172 *errstrp = ERR_ILLEGAL_VAR;
173 return RETURN_ERROR;
175 value = (char *)1; /* successful flag.. */
176 continue; /* while() */
177 case VAR_LONG:
178 case VAR_FLAG:
179 vlen = ultoa(((LONG*)variables[var].value)[index], Buffer);
180 value = Buffer;
181 break;
182 case VAR_STRP:
183 value = ((UBYTE **)variables[var].value)[index];
184 vlen = strlen(value);
185 break;
186 case VAR_INET:
188 ULONG s_addr =
189 ((struct in_addr *)variables[var].value)[index].s_addr;
190 vlen = sprintf(Buffer, "%ld.%ld.%ld.%ld",
191 (long)(s_addr>>24) & 0xff, (long)(s_addr>>16) & 0xff,
192 (long)(s_addr>>8) & 0xff, (long)s_addr & 0xff);
193 value = Buffer;
195 break;
196 case VAR_ENUM:
198 ULONG i = 0, nth;
199 STRPTR p;
201 nth = ((ULONG*)variables[var].value)[index];
203 * search nth keyword from the template
205 value = (STRPTR)variables[var].notify;
206 while (*value && i < nth)
207 if (*value++ == ',')
208 i++;
209 if (i < nth) { /* value not found */
210 *errstrp = ERR_VALUE;
211 return RETURN_ERROR;
214 * find the length of the answer
216 p = value;
217 while(*p && *p != '=' && *p != ',')
218 p++;
220 vlen = p - value;
222 break;
224 /* prepend by space? */
225 if (res->CS_CurChr)
226 res->CS_Buffer[res->CS_CurChr++] = ' ';
227 if (vlen + res->CS_CurChr > res->CS_Length) {
228 *errstrp = ERR_TOO_LONG;
229 return RETURN_ERROR;
231 bcopy(value, res->CS_Buffer + res->CS_CurChr, (WORD)vlen);
232 res->CS_CurChr += vlen;
235 if (!value || var != ITEM_NOTHING) {
236 *errstrp = ERR_SYNTAX;
237 return RETURN_WARN;
239 res->CS_Buffer[res->CS_CurChr] = '\0';
240 return RETURN_OK;
244 * Parse the "Set" commands
246 * TODO: notifications for VAR_INET;
248 LONG
249 setvalue(struct CSource *args, UBYTE **errstrp, struct CSource *res)
251 UBYTE Buffer[KEYWORDLEN];
252 LONG BufLen = sizeof(Buffer);
253 LONG vlen, item;
254 WORD var, index;
255 UBYTE *value;
256 void *dp = NULL; /* pointer to data item */
258 Buffer[0] = '\0';
260 while ((item = ReadItem(Buffer, BufLen, args)) > 0) {
261 if ((var = FindArg(KW_VARS, Buffer)) < 0 ||
262 (!(variables[var].flags & VF_WRITE) &&
263 (initialized || !(variables[var].flags & VF_CONF)))) {
264 res->CS_CurChr = 0;
265 csprintf(res, (var < 0) ? ERR_ILLEGAL_VAR : ERR_NOWRITE,
266 "setvalue", Buffer);
267 *errstrp = res->CS_Buffer;
268 return RETURN_WARN;
269 } else {
270 if (variables[var].flags & VF_TABLE) {
271 if (ReadItem(Buffer, BufLen, args) <= 0 ||
272 (index = FindArg((UBYTE *)variables[var].index, Buffer)) < 0) {
273 res->CS_CurChr = 0;
274 csprintf(res, ERR_ILLEGAL_IND, "setvalue", Buffer);
275 *errstrp = res->CS_Buffer;
276 return RETURN_WARN;
278 } else {
279 index = 0;
282 if (variables[var].type != VAR_FLAG &&
283 *CURRENT(args) == '=')
284 args->CS_CurChr++;
286 /* If dp is different for a type,
287 * it must be calculated in the case statement
289 dp = (void *)((LONG *)variables[var].value + index);
291 switch (variables[var].type) {
292 case VAR_FUNC:
293 if (variables[var].notify) {
294 if (vlen = (*(var_f)(variables[var].notify))(args, errstrp, res))
295 return vlen;
296 } else {
297 *errstrp = ERR_ILLEGAL_VAR;
298 return RETURN_ERROR;
300 break;
301 case VAR_LONG:
302 if ((vlen = StrToLong(CURRENT(args), &item)) <= 0)
303 goto reterr;
304 if (variables[var].notify)
305 if (!(*variables[var].notify)(dp, item)) {
306 *errstrp = ERR_VALUE;
307 return RETURN_WARN;
309 *(LONG*)dp = item;
310 args->CS_CurChr += vlen;
311 break;
312 case VAR_STRP:
313 if (ReadItem(Buffer, BufLen, args) <= 0)
314 goto reterr;
315 vlen = strlen(Buffer) + 1;
316 value = bsd_malloc(vlen, M_CFGVAR, M_WAITOK);
317 if (!value) {
318 *errstrp = ERR_MEMORY;
319 return RETURN_ERROR;
321 strcpy(value, Buffer);
322 if (variables[var].notify)
323 if (!(*variables[var].notify)(dp, (IPTR) value)) {
324 bsd_free(value, M_CFGVAR);
325 *errstrp = ERR_VALUE;
326 return RETURN_WARN;
328 if (variables[var].flags & VF_FREE) {
329 bsd_free(*(UBYTE **)dp, M_CFGVAR);
331 *(UBYTE **)dp = value;
332 variables[var].flags |= VF_FREE;
333 break;
334 case VAR_INET:
335 /* Currently, nameservice cannot be used */
336 if (ReadItem(Buffer, BufLen, args) <= 0)
337 goto reterr;
338 if (!__inet_aton(Buffer, (struct in_addr *)dp))
339 goto reterr;
340 break;
341 case VAR_ENUM:
342 if (ReadItem(Buffer, BufLen, args) <= 0)
343 goto reterr;
345 * Match the item against the template. The value is the index of
346 * the matching keyword, if one is found.
348 if ((vlen = FindArg((STRPTR)variables[var].notify, Buffer)) < 0)
349 goto reterr;
351 * Set the new value. Note that there is no notify function, since
352 * the notify field was used for the template.
354 *(LONG *)dp = vlen;
355 break;
356 default:
357 goto reterr;
362 if (item != ITEM_NOTHING) {
363 reterr:
364 *errstrp = ERR_SYNTAX;
365 return RETURN_WARN;
368 #define DONE "Done."
369 bcopy(DONE, res->CS_Buffer + res->CS_CurChr, sizeof(DONE));
370 res->CS_CurChr += sizeof(DONE);
371 res->CS_Buffer[res->CS_CurChr] = '\0';
372 return RETURN_OK;
376 * SET WITH a file
378 LONG read_sets(struct CSource *args, UBYTE **errstrp, struct CSource *res)
380 UBYTE * buf = res->CS_Buffer;
382 if (ReadItem(buf, res->CS_Length, args) < 0) {
383 *errstrp = ERR_SYNTAX;
384 return RETURN_WARN;
385 } else {
386 return parsefile(buf, errstrp, res);
391 * Parse a 'WITH' command
393 LONG
394 readfile(struct CSource *args, UBYTE **errstrp, struct CSource *res)
396 *errstrp = "readfile() is currently unimplemented\n";
397 return RETURN_WARN;
400 #define CMDLINETEMP "WITH/K,NOO=NOCONFIG/S,DEBUG/S"
402 #define CL_WITH 0
403 #define CL_NOCFG 1
404 #define CL_DEBUG 2 /* Currently default, does nothing */
405 #define CL_SIZE 3
408 * Read command file
410 LONG
411 parsefile(UBYTE const *name, UBYTE **errstrp, struct CSource *res)
413 LONG retval = RETURN_OK, ioerr = 0;
414 struct CSource arg;
415 int line = 0;
416 BPTR fh;
417 UBYTE *buf;
418 #if defined(__AROS__)
419 D(bug("[AROSTCP](amiga_config.c) parsefile('%s')\n",name));
420 #endif
422 D(Printf("Loading config file: %s\n",name);)
423 buf = AllocMem(CONFIGLINELEN, MEMF_PUBLIC);
425 if (buf) {
426 arg.CS_Buffer = buf;
427 if (fh = Open(name, MODE_OLDFILE)) {
428 while (FGets(fh, buf, CONFIGLINELEN)) {
429 line++;
430 if (*buf == '#')
431 continue;
432 arg.CS_Length = strlen(buf);
433 arg.CS_CurChr = 0;
434 retval = setvalue(&arg, errstrp, res);
436 if (retval == RETURN_OK)
437 continue;
438 if (retval != RETURN_WARN) { /* severe error */
439 error_request("Fatal configuration error in file %s at line %ld, col %ld\n%s\nAROSTCP will quit", (IPTR)name, (IPTR)line, (IPTR)arg.CS_CurChr, (IPTR)*errstrp);
440 break;
443 /* Print the error to the "stdout" */
444 #if defined(__AROS__)
445 D(bug("[AROSTCP](amiga_config.c) parsefile: %s: line %ld, col %ld: %s",
446 name, line, arg.CS_CurChr, *errstrp));
447 #endif
448 error_request("Configuration error in file %s at line %ld, col %ld\n%s", (IPTR)name, (IPTR)line, (IPTR)arg.CS_CurChr, (IPTR)*errstrp);
449 retval = RETURN_OK;
451 /* Check file error */
452 ioerr = IoErr();
454 Close(fh);
455 } else {
456 ioerr = IoErr();
459 if (ioerr) {
460 Fault(ioerr, name, res->CS_Buffer, res->CS_Length);
461 *errstrp = res->CS_Buffer;
462 retval = RETURN_ERROR;
464 if (!fh)
465 error_request("Unable to open configuration file\n%s", (IPTR)*errstrp);
467 FreeMem(buf, CONFIGLINELEN);
468 } else {
469 *errstrp = ERR_MEMORY;
470 retval = RETURN_FAIL;
473 return retval;
477 * Read command line arguments and configuration file
479 BOOL
480 readconfig(void)
482 UBYTE result[REPLYBUFLEN + 1]; /* for error returns */
483 struct CSource res;
484 struct RDArgs *rdargs = NULL;
485 IPTR args[CL_SIZE] = { 0 };
486 UBYTE *errstr;
487 LONG error = 0;
488 #if defined(__AROS__)
489 D(bug("[AROSTCP](amiga_config.c) readconfig()\n"));
490 #endif
492 res.CS_Buffer = result;
493 res.CS_Length = sizeof(result);
494 res.CS_CurChr = 0;
496 /* Parse command line arguments, if any */
497 rdargs = ReadArgs(cmd_template, args, NULL);
499 if (!rdargs) {
500 #if defined(__AROS__)
501 D(bug("[AROSTCP](amiga_config.c) readconfig: Bad Args\n"));
502 #endif
503 Printf("Argument error. Template: %s\n", cmd_template);
504 return FALSE;
507 if (!args[CL_NOCFG])
508 /* Read default configuration file */
509 error = parsefile(config_path, &errstr, &res);
511 if (!error && args[CL_WITH])
512 /* Read given file */
513 error = parsefile((STRPTR)args[CL_WITH], &errstr, &res);
515 FreeArgs(rdargs);
517 if (error)
519 #if defined(__AROS__)
520 D(bug("[AROSTCP](amiga_config.c) readconfig: TCP/IP Configuration: %s\n", errstr));
521 #endif
522 Printf("TCP/IP Configuration: %s\n", errstr);
525 return ((BOOL)!error);
528 #if 0
530 * The order of following keywords is selected to reflect the order of
531 * route message numbers in <net/route.h>, so DO NOT CHANGE THE ORDER.
533 static STRPTR KW_ROUTE_CMDS =
534 "RESET,ADD,DELETE,CHANGE,GET";
536 static STRPTR ROUTE_TEMPLATE =
537 "NET/S,HOST/S,DESTINATION/A,GATEWAY/A,INTERFACE/S,HCNT=HOPCOUNT/K/N";
539 enum route_template
540 { ROUTE_NET, ROUTE_HOST, ROUTE_DESTINATION, ROUTE_GATEWAY, ROUTE_INTERFACE,
541 ROUTE_HOPCOUNT, ROUTE_TEMPLATE_SIZE };
543 #endif /* 0 */
546 * Parse route command
548 LONG
549 parseroute(struct CSource *args, UBYTE **errstrp, struct CSource *res)
551 #if defined(__AROS__)
552 D(bug("[AROSTCP](amiga_config.c) parseroute()\n"));
553 #endif
554 #if 1
555 *errstrp = "ROUTE not implemented.\n";
556 return RETURN_FAIL;
557 #else
558 UBYTE Buffer[KEYWORDLEN];
559 LONG BufLen = sizeof(Buffer);
560 struct RDArgs *rdargs;
561 IPTR argArray[ROUTE_TEMPLATE_SIZE] = { 0 };
562 LONG vlen, item;
563 WORD index;
564 UBYTE *value;
565 void *dp = NULL; /* pointer to data item */
566 int req, flags = 0;
567 struct sockaddr_in destination, gateway, netmask;
568 int error;
570 Buffer[0] = '\0';
572 if ((item = ReadItem(Buffer, BufLen, args)) <= 0
573 || (req = FindArg(KW_ROUTE_CMDS, Buffer)) < 0) {
574 *errstrp = ERR_SYNTAX;
575 return RETURN_FAIL;
578 if (req == 0) { /* RESET, delete all routes */
579 *errstrp = "route reset is currently unimplemented\n";
580 return RETURN_FAIL;
583 if (req == RTM_CHANGE) {
584 *errstrp = "route change is currently unimplemented\n";
585 return RETURN_FAIL;
587 if (req == RTM_GET) {
588 *errstrp = "route get is currently unimplemented\n";
589 return RETURN_FAIL;
593 * Initialize the RDArgs structure for ReadArgs()
595 rdargs = AllocDosObjectTags(DOS_RDARGS, TAG_END);
596 if (rdargs == NULL) {
597 *errstrp = ERR_MEMORY;
598 return RETURN_FAIL;
601 rdargs->RDA_Source = *args;
602 rdargs->RDA_DAList = NULL;
603 rdargs->RDA_Buffer = NULL;
604 rdargs->RDA_BufSiz = 0;
605 rdargs->RDA_ExtHelp = NULL;
606 rdargs->RDA_Flags = 0;
608 if (ReadArgs(ROUTE_TEMPLATE, argArray, rdargs) == NULL
609 || (argArray[ROUTE_HOST] && argArray[ROUTE_NET])) {
610 FreeDosObject(DOS_RDARGS, rdargs);
611 *errstrp = ERR_SYNTAX;
612 return RETURN_FAIL;
616 * Find destination host/network
618 /* INCOMPLETE */
620 if (!argArray[ROUTE_INTERFACE])
621 flags |= RTF_GATEWAY;
622 if (argArray[ROUTE_HOST])
623 flags |= RTF_HOST;
625 #if 0
626 error = rtrequest(req, &destination, &gateway,
627 (flags & RTF_HOST) ? NULL : &netmask,
628 flags, (struct rtentry **)0);
629 #endif
631 FreeArgs(rdargs);
632 FreeDosObject(DOS_RDARGS, rdargs);
634 return RETURN_OK;
635 #endif