2 * amiga_config.c --- Configuring AmiTCP/IP
4 * Copyright (C) 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>
5 * Helsinki University of Technology, Finland.
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,
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>
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
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
96 parseline(struct CSource
*csarg
, UBYTE
**errstrp
, struct CSource
*res
)
98 UBYTE Buffer
[KEYWORDLEN
];
101 /* Parse the command keyword */
102 LONG item
= ReadItem(Buffer
, sizeof(Buffer
), csarg
);
107 *errstrp
= ERR_SYNTAX
;
111 if ((keyword
= FindArg((UBYTE
*)REXXKEYWORDS
, Buffer
)) < 0) {
112 *errstrp
= ERR_UNKNOWN
;
116 return rexx_parse_funs
[keyword
](csarg
, errstrp
, res
);
120 * 'Parse' the "KILL" command
123 sendbreak(struct CSource
*args
, UBYTE
**errstrp
, struct CSource
*res
)
125 Signal(AROSTCP_Task
, SIGBREAKF_CTRL_C
);
129 extern UBYTE
*KW_VARS
;
130 extern struct cfg_variable variables
[];
133 * Parse the "Query" commands
136 getvalue(struct CSource
*args
, UBYTE
**errstrp
, struct CSource
*res
)
138 UBYTE Buffer
[KEYWORDLEN
];
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
) {
149 csprintf(res
, ERR_ILLEGAL_VAR
, "getvalue", Buffer
);
150 *errstrp
= res
->CS_Buffer
;
154 if (variables
[var
].flags
& VF_TABLE
) {
155 if (ReadItem(Buffer
, sizeof(Buffer
), args
) <= 0 ||
156 (index
= FindArg((UBYTE
*)variables
[var
].index
, Buffer
)) < 0) {
158 csprintf(res
, ERR_ILLEGAL_IND
, "getvalue", Buffer
);
159 *errstrp
= res
->CS_Buffer
;
166 switch (variables
[var
].type
) {
168 if (variables
[var
].value
) {
169 if (vlen
= (*(var_f
)(variables
[var
].value
))(args
, errstrp
, res
))
172 *errstrp
= ERR_ILLEGAL_VAR
;
175 value
= (char *)1; /* successful flag.. */
176 continue; /* while() */
179 vlen
= ultoa(((LONG
*)variables
[var
].value
)[index
], Buffer
);
183 value
= ((UBYTE
**)variables
[var
].value
)[index
];
184 vlen
= strlen(value
);
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);
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
)
209 if (i
< nth
) { /* value not found */
210 *errstrp
= ERR_VALUE
;
214 * find the length of the answer
217 while(*p
&& *p
!= '=' && *p
!= ',')
224 /* prepend by space? */
226 res
->CS_Buffer
[res
->CS_CurChr
++] = ' ';
227 if (vlen
+ res
->CS_CurChr
> res
->CS_Length
) {
228 *errstrp
= ERR_TOO_LONG
;
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
;
239 res
->CS_Buffer
[res
->CS_CurChr
] = '\0';
244 * Parse the "Set" commands
246 * TODO: notifications for VAR_INET;
249 setvalue(struct CSource
*args
, UBYTE
**errstrp
, struct CSource
*res
)
251 UBYTE Buffer
[KEYWORDLEN
];
252 LONG BufLen
= sizeof(Buffer
);
256 void *dp
= NULL
; /* pointer to data item */
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
)))) {
265 csprintf(res
, (var
< 0) ? ERR_ILLEGAL_VAR
: ERR_NOWRITE
,
267 *errstrp
= res
->CS_Buffer
;
270 if (variables
[var
].flags
& VF_TABLE
) {
271 if (ReadItem(Buffer
, BufLen
, args
) <= 0 ||
272 (index
= FindArg((UBYTE
*)variables
[var
].index
, Buffer
)) < 0) {
274 csprintf(res
, ERR_ILLEGAL_IND
, "setvalue", Buffer
);
275 *errstrp
= res
->CS_Buffer
;
282 if (variables
[var
].type
!= VAR_FLAG
&&
283 *CURRENT(args
) == '=')
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
) {
293 if (variables
[var
].notify
) {
294 if (vlen
= (*(var_f
)(variables
[var
].notify
))(args
, errstrp
, res
))
297 *errstrp
= ERR_ILLEGAL_VAR
;
302 if ((vlen
= StrToLong(CURRENT(args
), &item
)) <= 0)
304 if (variables
[var
].notify
)
305 if (!(*variables
[var
].notify
)(dp
, item
)) {
306 *errstrp
= ERR_VALUE
;
310 args
->CS_CurChr
+= vlen
;
313 if (ReadItem(Buffer
, BufLen
, args
) <= 0)
315 vlen
= strlen(Buffer
) + 1;
316 value
= bsd_malloc(vlen
, M_CFGVAR
, M_WAITOK
);
318 *errstrp
= ERR_MEMORY
;
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
;
328 if (variables
[var
].flags
& VF_FREE
) {
329 bsd_free(*(UBYTE
**)dp
, M_CFGVAR
);
331 *(UBYTE
**)dp
= value
;
332 variables
[var
].flags
|= VF_FREE
;
335 /* Currently, nameservice cannot be used */
336 if (ReadItem(Buffer
, BufLen
, args
) <= 0)
338 if (!__inet_aton(Buffer
, (struct in_addr
*)dp
))
342 if (ReadItem(Buffer
, BufLen
, args
) <= 0)
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)
351 * Set the new value. Note that there is no notify function, since
352 * the notify field was used for the template.
362 if (item
!= ITEM_NOTHING
) {
364 *errstrp
= ERR_SYNTAX
;
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';
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
;
386 return parsefile(buf
, errstrp
, res
);
391 * Parse a 'WITH' command
394 readfile(struct CSource
*args
, UBYTE
**errstrp
, struct CSource
*res
)
396 *errstrp
= "readfile() is currently unimplemented\n";
400 #define CMDLINETEMP "WITH/K,NOO=NOCONFIG/S,DEBUG/S"
404 #define CL_DEBUG 2 /* Currently default, does nothing */
411 parsefile(UBYTE
const *name
, UBYTE
**errstrp
, struct CSource
*res
)
413 LONG retval
= RETURN_OK
, ioerr
= 0;
418 #if defined(__AROS__)
419 D(bug("[AROSTCP](amiga_config.c) parsefile('%s')\n",name
));
422 D(Printf("Loading config file: %s\n",name
);)
423 buf
= AllocMem(CONFIGLINELEN
, MEMF_PUBLIC
);
427 if (fh
= Open(name
, MODE_OLDFILE
)) {
428 while (FGets(fh
, buf
, CONFIGLINELEN
)) {
432 arg
.CS_Length
= strlen(buf
);
434 retval
= setvalue(&arg
, errstrp
, res
);
436 if (retval
== RETURN_OK
)
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
);
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
));
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
);
451 /* Check file error */
460 Fault(ioerr
, name
, res
->CS_Buffer
, res
->CS_Length
);
461 *errstrp
= res
->CS_Buffer
;
462 retval
= RETURN_ERROR
;
465 error_request("Unable to open configuration file\n%s", (IPTR
)*errstrp
);
467 FreeMem(buf
, CONFIGLINELEN
);
469 *errstrp
= ERR_MEMORY
;
470 retval
= RETURN_FAIL
;
477 * Read command line arguments and configuration file
482 UBYTE result
[REPLYBUFLEN
+ 1]; /* for error returns */
484 struct RDArgs
*rdargs
= NULL
;
485 IPTR args
[CL_SIZE
] = { 0 };
488 #if defined(__AROS__)
489 D(bug("[AROSTCP](amiga_config.c) readconfig()\n"));
492 res
.CS_Buffer
= result
;
493 res
.CS_Length
= sizeof(result
);
496 /* Parse command line arguments, if any */
497 rdargs
= ReadArgs(cmd_template
, args
, NULL
);
500 #if defined(__AROS__)
501 D(bug("[AROSTCP](amiga_config.c) readconfig: Bad Args\n"));
503 Printf("Argument error. Template: %s\n", cmd_template
);
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
);
519 #if defined(__AROS__)
520 D(bug("[AROSTCP](amiga_config.c) readconfig: TCP/IP Configuration: %s\n", errstr
));
522 Printf("TCP/IP Configuration: %s\n", errstr
);
525 return ((BOOL
)!error
);
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";
540 { ROUTE_NET
, ROUTE_HOST
, ROUTE_DESTINATION
, ROUTE_GATEWAY
, ROUTE_INTERFACE
,
541 ROUTE_HOPCOUNT
, ROUTE_TEMPLATE_SIZE
};
546 * Parse route command
549 parseroute(struct CSource
*args
, UBYTE
**errstrp
, struct CSource
*res
)
551 #if defined(__AROS__)
552 D(bug("[AROSTCP](amiga_config.c) parseroute()\n"));
555 *errstrp
= "ROUTE not implemented.\n";
558 UBYTE Buffer
[KEYWORDLEN
];
559 LONG BufLen
= sizeof(Buffer
);
560 struct RDArgs
*rdargs
;
561 IPTR argArray
[ROUTE_TEMPLATE_SIZE
] = { 0 };
565 void *dp
= NULL
; /* pointer to data item */
567 struct sockaddr_in destination
, gateway
, netmask
;
572 if ((item
= ReadItem(Buffer
, BufLen
, args
)) <= 0
573 || (req
= FindArg(KW_ROUTE_CMDS
, Buffer
)) < 0) {
574 *errstrp
= ERR_SYNTAX
;
578 if (req
== 0) { /* RESET, delete all routes */
579 *errstrp
= "route reset is currently unimplemented\n";
583 if (req
== RTM_CHANGE
) {
584 *errstrp
= "route change is currently unimplemented\n";
587 if (req
== RTM_GET
) {
588 *errstrp
= "route get is currently unimplemented\n";
593 * Initialize the RDArgs structure for ReadArgs()
595 rdargs
= AllocDosObjectTags(DOS_RDARGS
, TAG_END
);
596 if (rdargs
== NULL
) {
597 *errstrp
= ERR_MEMORY
;
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
;
616 * Find destination host/network
620 if (!argArray
[ROUTE_INTERFACE
])
621 flags
|= RTF_GATEWAY
;
622 if (argArray
[ROUTE_HOST
])
626 error
= rtrequest(req
, &destination
, &gateway
,
627 (flags
& RTF_HOST
) ? NULL
: &netmask
,
628 flags
, (struct rtentry
**)0);
632 FreeDosObject(DOS_RDARGS
, rdargs
);