Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[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  *      @(#) $DragonFly: src/usr.sbin/atm/atmarpd/atmarpd.c,v 1.2 2003/06/17 04:29:52 dillon Exp $
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 /*
67  * Global variables
68  */
69 char            *prog;
70 int             atmarp_debug_mode = 0;
71 int             atmarp_max_socket = 0;
72 Atmarp_intf     *atmarp_intf_head = (Atmarp_intf *)0;
73 Atmarp_slis     *atmarp_slis_head = (Atmarp_slis *)0;
74 FILE            *atmarp_log_file = (FILE *)0;
75 char            *atmarp_log_file_name = (char *)0;
76 Harp_timer      cache_timer, perm_timer;
77
78
79 /*
80  * Print a usage message
81  *
82  * Arguments:
83  *      none
84  *
85  * Returns:
86  *      exits, does not return
87  *
88  */
89 void
90 usage()
91 {
92         fprintf(stderr, "usage: %s [-d] [-l <log_file>] <net_intf> ...\n", prog);
93         exit(1);
94 }
95
96
97 /*
98  * Process command line parameters
99  *
100  * Arguments:
101  *      argc    number of command-line arguments
102  *      argv    list of pointers to command-line arguments
103  *
104  * Returns:
105  *      none
106  *
107  */
108 static void
109 initialize(argc, argv)
110         int     argc;
111         char    *argv[];
112
113 {
114         int     i, rc;
115
116         /*
117          * Save program name, ignoring any path components
118          */
119         if ((prog = (char *)strrchr(argv[0], '/')) != NULL)
120                 prog++;
121         else
122                 prog = argv[0];
123
124         /*
125          * Make sure we're being invoked by the super user
126          */
127         i = getuid();
128         if (i != 0) {
129                 fprintf(stderr, "%s: You must be root to run this program\n",
130                                 prog);
131                 exit(1);
132         }
133
134         /*
135          * Scan arguments, checking for options
136          */
137         for (i = 1; i < argc; i++) {
138                 if (argv[i][0] == '-') {
139                         if (strcmp(argv[i], "-d") == 0) {
140                                 atmarp_debug_mode = TRUE;
141                         } else if (strcmp(argv[i], "-l") == 0) {
142                                 i++;
143                                 if (i >= argc) {
144                                         fprintf(stderr, "%s: Log file name missing\n",
145                                                 prog);
146                                         exit(1);
147                                 }
148                                 atmarp_log_file_name = argv[i];
149                         } else {
150                                 fprintf(stderr, "%s: Unrecognized option \"%s\"\n",
151                                                 prog, argv[i]);
152                                 exit(1);
153                         }
154                 } else {
155                         /*
156                          * Parameter is a network interface name
157                          */
158                         rc = atmarp_cfg_netif(argv[i]);
159                         if (rc) {
160                                 fprintf(stderr, "%s: Error configuring network interface %s\n",
161                                                 prog, argv[i]);
162                                 exit(1);
163                         }
164                 }
165         }
166
167         /*
168          * Make sure we had at least one interface configured
169          */
170         if (!atmarp_intf_head) {
171                 usage();
172         }
173 }
174
175
176 /*
177  * Daemon housekeeping
178  *
179  * Arguments:
180  *      None
181  *
182  * Returns:
183  *      None
184  *
185  */
186 static void
187 start_daemon()
188
189 {
190         int     dpid, fd, file_count, rc;
191
192         /*
193          * Ignore selected signals
194          */
195 #ifdef SIGTTOU
196         signal(SIGTTOU, SIG_IGN);
197 #endif
198 #ifdef SIGTTIN
199         signal(SIGTTIN, SIG_IGN);
200 #endif
201 #ifdef SIGTSTP
202         signal(SIGTSTP, SIG_IGN);
203 #endif
204 #ifdef SIGPIPE
205         signal(SIGPIPE, SIG_IGN);
206 #endif
207
208         /*
209          * Skip putting things into the background if we're
210          * in debugging mode
211          */
212         if (atmarp_debug_mode)
213                 goto daemon_bypass;
214
215         /*
216          * Set up syslog for error logging
217          */
218         if (!atmarp_log_file) {
219                 openlog(prog, LOG_PID | LOG_CONS, LOG_DAEMON);
220         }
221
222         /*
223          * Put the daemon into the background
224          */
225         dpid = fork();
226         if (dpid < 0) {
227                 atmarp_log(LOG_ERR, "fork failed");
228                 exit(1);
229         }
230         if (dpid > 0) {
231                 /*
232                  * This is the parent process--just exit and let
233                  * the daughter do all the work
234                  */
235                 exit(0);
236         }
237
238         /*
239          * Disassociate from any controlling terminal
240          */
241         rc = setpgrp(0, getpid());
242         if (rc < 0) {
243                 atmarp_log(LOG_ERR, "can't change process group");
244                 exit(1);
245         }
246         fd = open(_PATH_TTY, O_RDWR);
247         if (fd >= 0) {
248                 ioctl(fd, TIOCNOTTY, (char *)0);
249                 close(fd);
250         }
251
252         /*
253          * Close all open file descriptors
254          */
255         file_count = getdtablesize();
256         for (fd=0; fd<file_count; fd++) {
257                 close(fd);
258         }
259
260         /*
261          * Open log file, if specified
262          */
263         if (atmarp_log_file_name) {
264                 atmarp_log_file = fopen(atmarp_log_file_name, "a");
265                 if (!atmarp_log_file) {
266                         atmarp_log(LOG_ERR, "%s: Can't open log file \'%s\'\n",
267                                         prog, atmarp_log_file_name);
268                         exit(1);
269                 }
270         }
271
272         /*
273          * Set up and start interval timer
274          */
275 daemon_bypass:
276         init_timer();
277
278         /*
279          * Move to a safe directory
280          */
281         chdir(ATMARP_DIR);
282
283         /*
284          * Clear the file mode creation mask
285          */
286         umask(0);
287
288
289         /*
290          * Set up signal handlers
291          */
292         rc = (int)signal(SIGINT, atmarp_sigint);
293         if (rc == -1) {
294                 atmarp_log(LOG_ERR, "SIGINT signal setup failed");
295                 exit(1);
296         }
297 }
298
299
300 /*
301  * Main line code
302  *
303  * The ATMARP server resides in the kernel, while SCSP runs as a daemon
304  * in user space.  This program exists to provide an interface between
305  * the two.  It periodically polls the kernel to get the ATMARP cache
306  * and passes information about new entries to SCSP.  It also accepts
307  * new information from SCSP and passes it to the kernel.
308  *
309  * Arguments:
310  *      argc    number of command-line arguments
311  *      argv    list of pointers to command-line arguments
312  *
313  * Returns:
314  *      none
315  *
316  */
317 int
318 main(argc, argv)
319         int     argc;
320         char    *argv[];
321
322 {
323         int             i, rc;
324         fd_set          read_set, write_set, except_set;
325         Atmarp_intf     *aip;
326
327         /*
328          * Process command line arguments
329          */
330         initialize(argc, argv);
331
332         /*
333          * Put the daemon into the background
334          */
335         start_daemon();
336
337         /*
338          * Start the cache update timer
339          */
340         HARP_TIMER(&cache_timer, ATMARP_CACHE_INTERVAL,
341                         atmarp_cache_timeout);
342
343         /*
344          * Start the permanent cache entry timer
345          */
346         HARP_TIMER(&perm_timer, ATMARP_PERM_INTERVAL,
347                         atmarp_perm_timeout);
348
349         /*
350          * Establish a connection to SCSP for each interface.  If a
351          * connect fails, it will be retried when the cache update
352          * timer fires.
353          */
354         for (aip = atmarp_intf_head; aip; aip = aip->ai_next) {
355                 if (atmarp_if_ready(aip)) {
356                         (void)atmarp_scsp_connect(aip);
357                 }
358         }
359
360         /*
361          * Read the cache from the kernel
362          */
363         atmarp_get_updated_cache();
364
365         /*
366          * Main program loop -- wait for data to come in from SCSP.
367          * When the timer fires, it will be handled elsewhere.
368          */
369         while (1) {
370                 /*
371                  * Wait for input from SCSP
372                  */
373                 FD_ZERO(&read_set);
374                 FD_ZERO(&write_set);
375                 FD_ZERO(&except_set);
376                 for (aip = atmarp_intf_head; aip; aip = aip->ai_next) {
377                         if (aip->ai_scsp_sock != -1) {
378                                 FD_SET(aip->ai_scsp_sock, &read_set);
379                         }
380                 }
381                 rc = select(atmarp_max_socket + 1,
382                                 &read_set, &write_set,
383                                 &except_set, (struct timeval *)0);
384                 if (rc < 0) {
385                         if (harp_timer_exec) {
386                                 timer_proc();
387                                 continue;
388                         } else if (errno == EINTR) {
389                                 continue;
390                         } else {
391                                 atmarp_log(LOG_ERR, "Select failed");
392                                 abort();
393                         }
394                 }
395
396                 /*
397                  * Read and process the input from SCSP
398                  */
399                 for (i = 0; i <= atmarp_max_socket; i++) {
400                         if (FD_ISSET(i, &read_set)) {
401                                 aip = atmarp_find_intf_sock(i);
402                                 if (aip)
403                                         rc = atmarp_scsp_read(aip);
404                         }
405                 }
406         }
407 }