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