Initial import from FreeBSD RELENG_4:
[dragonfly.git] / usr.sbin / atm / atmarpd / atmarpd.c
1 /*
2  *
3  * ===================================
4  * HARP  |  Host ATM Research Platform
5  * ===================================
6  *
7  *
8  * This Host ATM Research Platform ("HARP") file (the "Software") is
9  * made available by Network Computing Services, Inc. ("NetworkCS")
10  * "AS IS".  NetworkCS does not provide maintenance, improvements or
11  * support of any kind.
12  *
13  * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
14  * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
15  * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
16  * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
17  * In no event shall NetworkCS be responsible for any damages, including
18  * but not limited to consequential damages, arising from or relating to
19  * any use of the Software or related support.
20  *
21  * Copyright 1994-1998 Network Computing Services, Inc.
22  *
23  * Copies of this Software may be made, however, the above copyright
24  * notice must be reproduced on all copies.
25  *
26  *      @(#) $FreeBSD: src/usr.sbin/atm/atmarpd/atmarpd.c,v 1.3.2.1 2000/12/11 01:03:29 obrien Exp $
27  *
28  */
29
30 /*
31  * Server Cache Synchronization Protocol (SCSP) Support
32  * ----------------------------------------------------
33  *
34  * SCSP-ATMARP server interface: main line code
35  *
36  */
37
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/socket.h>
41 #include <sys/stat.h>
42 #include <sys/ttycom.h>
43 #include <net/if.h>
44 #include <netinet/in.h>
45 #include <netatm/queue.h>
46 #include <netatm/atm.h>
47 #include <netatm/atm_if.h>
48 #include <netatm/atm_sap.h>
49 #include <netatm/atm_sys.h>
50 #include <netatm/atm_ioctl.h>
51
52 #include <errno.h>
53 #include <fcntl.h>
54 #include <libatm.h>
55 #include <paths.h>
56 #include <stdio.h>
57 #include <string.h>
58 #include <syslog.h>
59 #include <unistd.h>
60
61 #include "../scspd/scsp_msg.h"
62 #include "../scspd/scsp_if.h"
63 #include "../scspd/scsp_var.h"
64 #include "atmarp_var.h"
65
66 #ifndef lint
67 __RCSID("@(#) $FreeBSD: src/usr.sbin/atm/atmarpd/atmarpd.c,v 1.3.2.1 2000/12/11 01:03:29 obrien Exp $");
68 #endif
69
70
71 /*
72  * Global variables
73  */
74 char            *prog;
75 int             atmarp_debug_mode = 0;
76 int             atmarp_max_socket = 0;
77 Atmarp_intf     *atmarp_intf_head = (Atmarp_intf *)0;
78 Atmarp_slis     *atmarp_slis_head = (Atmarp_slis *)0;
79 FILE            *atmarp_log_file = (FILE *)0;
80 char            *atmarp_log_file_name = (char *)0;
81 Harp_timer      cache_timer, perm_timer;
82
83
84 /*
85  * Print a usage message
86  *
87  * Arguments:
88  *      none
89  *
90  * Returns:
91  *      exits, does not return
92  *
93  */
94 void
95 usage()
96 {
97         fprintf(stderr, "usage: %s [-d] [-l <log_file>] <net_intf> ...\n", prog);
98         exit(1);
99 }
100
101
102 /*
103  * Process command line parameters
104  *
105  * Arguments:
106  *      argc    number of command-line arguments
107  *      argv    list of pointers to command-line arguments
108  *
109  * Returns:
110  *      none
111  *
112  */
113 static void
114 initialize(argc, argv)
115         int     argc;
116         char    *argv[];
117
118 {
119         int     i, rc;
120
121         /*
122          * Save program name, ignoring any path components
123          */
124         if ((prog = (char *)strrchr(argv[0], '/')) != NULL)
125                 prog++;
126         else
127                 prog = argv[0];
128
129         /*
130          * Make sure we're being invoked by the super user
131          */
132         i = getuid();
133         if (i != 0) {
134                 fprintf(stderr, "%s: You must be root to run this program\n",
135                                 prog);
136                 exit(1);
137         }
138
139         /*
140          * Scan arguments, checking for options
141          */
142         for (i = 1; i < argc; i++) {
143                 if (argv[i][0] == '-') {
144                         if (strcmp(argv[i], "-d") == 0) {
145                                 atmarp_debug_mode = TRUE;
146                         } else if (strcmp(argv[i], "-l") == 0) {
147                                 i++;
148                                 if (i >= argc) {
149                                         fprintf(stderr, "%s: Log file name missing\n",
150                                                 prog);
151                                         exit(1);
152                                 }
153                                 atmarp_log_file_name = argv[i];
154                         } else {
155                                 fprintf(stderr, "%s: Unrecognized option \"%s\"\n",
156                                                 prog, argv[i]);
157                                 exit(1);
158                         }
159                 } else {
160                         /*
161                          * Parameter is a network interface name
162                          */
163                         rc = atmarp_cfg_netif(argv[i]);
164                         if (rc) {
165                                 fprintf(stderr, "%s: Error configuring network interface %s\n",
166                                                 prog, argv[i]);
167                                 exit(1);
168                         }
169                 }
170         }
171
172         /*
173          * Make sure we had at least one interface configured
174          */
175         if (!atmarp_intf_head) {
176                 usage();
177         }
178 }
179
180
181 /*
182  * Daemon housekeeping
183  *
184  * Arguments:
185  *      None
186  *
187  * Returns:
188  *      None
189  *
190  */
191 static void
192 start_daemon()
193
194 {
195         int     dpid, fd, file_count, rc;
196
197         /*
198          * Ignore selected signals
199          */
200 #ifdef SIGTTOU
201         signal(SIGTTOU, SIG_IGN);
202 #endif
203 #ifdef SIGTTIN
204         signal(SIGTTIN, SIG_IGN);
205 #endif
206 #ifdef SIGTSTP
207         signal(SIGTSTP, SIG_IGN);
208 #endif
209 #ifdef SIGPIPE
210         signal(SIGPIPE, SIG_IGN);
211 #endif
212
213         /*
214          * Skip putting things into the background if we're
215          * in debugging mode
216          */
217         if (atmarp_debug_mode)
218                 goto daemon_bypass;
219
220         /*
221          * Set up syslog for error logging
222          */
223         if (!atmarp_log_file) {
224                 openlog(prog, LOG_PID | LOG_CONS, LOG_DAEMON);
225         }
226
227         /*
228          * Put the daemon into the background
229          */
230         dpid = fork();
231         if (dpid < 0) {
232                 atmarp_log(LOG_ERR, "fork failed");
233                 exit(1);
234         }
235         if (dpid > 0) {
236                 /*
237                  * This is the parent process--just exit and let
238                  * the daughter do all the work
239                  */
240                 exit(0);
241         }
242
243         /*
244          * Disassociate from any controlling terminal
245          */
246         rc = setpgrp(0, getpid());
247         if (rc < 0) {
248                 atmarp_log(LOG_ERR, "can't change process group");
249                 exit(1);
250         }
251         fd = open(_PATH_TTY, O_RDWR);
252         if (fd >= 0) {
253                 ioctl(fd, TIOCNOTTY, (char *)0);
254                 close(fd);
255         }
256
257         /*
258          * Close all open file descriptors
259          */
260         file_count = getdtablesize();
261         for (fd=0; fd<file_count; fd++) {
262                 close(fd);
263         }
264
265         /*
266          * Open log file, if specified
267          */
268         if (atmarp_log_file_name) {
269                 atmarp_log_file = fopen(atmarp_log_file_name, "a");
270                 if (!atmarp_log_file) {
271                         atmarp_log(LOG_ERR, "%s: Can't open log file \'%s\'\n",
272                                         prog, atmarp_log_file_name);
273                         exit(1);
274                 }
275         }
276
277         /*
278          * Set up and start interval timer
279          */
280 daemon_bypass:
281         init_timer();
282
283         /*
284          * Move to a safe directory
285          */
286         chdir(ATMARP_DIR);
287
288         /*
289          * Clear the file mode creation mask
290          */
291         umask(0);
292
293
294         /*
295          * Set up signal handlers
296          */
297         rc = (int)signal(SIGINT, atmarp_sigint);
298         if (rc == -1) {
299                 atmarp_log(LOG_ERR, "SIGINT signal setup failed");
300                 exit(1);
301         }
302 }
303
304
305 /*
306  * Main line code
307  *
308  * The ATMARP server resides in the kernel, while SCSP runs as a daemon
309  * in user space.  This program exists to provide an interface between
310  * the two.  It periodically polls the kernel to get the ATMARP cache
311  * and passes information about new entries to SCSP.  It also accepts
312  * new information from SCSP and passes it to the kernel.
313  *
314  * Arguments:
315  *      argc    number of command-line arguments
316  *      argv    list of pointers to command-line arguments
317  *
318  * Returns:
319  *      none
320  *
321  */
322 int
323 main(argc, argv)
324         int     argc;
325         char    *argv[];
326
327 {
328         int             i, rc;
329         fd_set          read_set, write_set, except_set;
330         Atmarp_intf     *aip;
331
332         /*
333          * Process command line arguments
334          */
335         initialize(argc, argv);
336
337         /*
338          * Put the daemon into the background
339          */
340         start_daemon();
341
342         /*
343          * Start the cache update timer
344          */
345         HARP_TIMER(&cache_timer, ATMARP_CACHE_INTERVAL,
346                         atmarp_cache_timeout);
347
348         /*
349          * Start the permanent cache entry timer
350          */
351         HARP_TIMER(&perm_timer, ATMARP_PERM_INTERVAL,
352                         atmarp_perm_timeout);
353
354         /*
355          * Establish a connection to SCSP for each interface.  If a
356          * connect fails, it will be retried when the cache update
357          * timer fires.
358          */
359         for (aip = atmarp_intf_head; aip; aip = aip->ai_next) {
360                 if (atmarp_if_ready(aip)) {
361                         (void)atmarp_scsp_connect(aip);
362                 }
363         }
364
365         /*
366          * Read the cache from the kernel
367          */
368         atmarp_get_updated_cache();
369
370         /*
371          * Main program loop -- wait for data to come in from SCSP.
372          * When the timer fires, it will be handled elsewhere.
373          */
374         while (1) {
375                 /*
376                  * Wait for input from SCSP
377                  */
378                 FD_ZERO(&read_set);
379                 FD_ZERO(&write_set);
380                 FD_ZERO(&except_set);
381                 for (aip = atmarp_intf_head; aip; aip = aip->ai_next) {
382                         if (aip->ai_scsp_sock != -1) {
383                                 FD_SET(aip->ai_scsp_sock, &read_set);
384                         }
385                 }
386                 rc = select(atmarp_max_socket + 1,
387                                 &read_set, &write_set,
388                                 &except_set, (struct timeval *)0);
389                 if (rc < 0) {
390                         if (harp_timer_exec) {
391                                 timer_proc();
392                                 continue;
393                         } else if (errno == EINTR) {
394                                 continue;
395                         } else {
396                                 atmarp_log(LOG_ERR, "Select failed");
397                                 abort();
398                         }
399                 }
400
401                 /*
402                  * Read and process the input from SCSP
403                  */
404                 for (i = 0; i <= atmarp_max_socket; i++) {
405                         if (FD_ISSET(i, &read_set)) {
406                                 aip = atmarp_find_intf_sock(i);
407                                 if (aip)
408                                         rc = atmarp_scsp_read(aip);
409                         }
410                 }
411         }
412 }