]> git.ozlabs.org Git - ppp.git/blob - pppd/plugins/pppoe/pppoe-discovery.c
pppd: Add support for registering ppp interface via Linux rtnetlink API
[ppp.git] / pppd / plugins / pppoe / pppoe-discovery.c
1 /*
2  * Perform PPPoE discovery
3  *
4  * Copyright (C) 2000-2001 by Roaring Penguin Software Inc.
5  * Copyright (C) 2004 Marco d'Itri <md@linux.it>
6  *
7  * This program may be distributed according to the terms of the GNU
8  * General Public License, version 2 or (at your option) any later version.
9  *
10  */
11
12 #ifdef HAVE_CONFIG_H
13 #include <config.h>
14 #endif
15
16 #include <stdarg.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <errno.h>
21 #include <string.h>
22 #include <time.h>
23 #include <signal.h>
24
25 #include "pppoe.h"
26
27 int debug;
28 int got_sigterm;
29 int pppoe_verbose;
30 static FILE *debugFile;
31
32 void
33 fatal(char *fmt, ...)
34 {
35     va_list pvar;
36     va_start(pvar, fmt);
37     vfprintf(stderr, fmt, pvar);
38     va_end(pvar);
39     fputc('\n', stderr);
40     exit(1);
41 }
42
43 void
44 error(char *fmt, ...)
45 {
46     va_list pvar;
47     va_start(pvar, fmt);
48     vfprintf(stderr, fmt, pvar);
49     fputc('\n', stderr);
50     va_end(pvar);
51 }
52
53 void
54 warn(char *fmt, ...)
55 {
56     va_list pvar;
57     va_start(pvar, fmt);
58     vfprintf(stderr, fmt, pvar);
59     fputc('\n', stderr);
60     va_end(pvar);
61 }
62
63 void
64 info(char *fmt, ...)
65 {
66     va_list pvar;
67     va_start(pvar, fmt);
68     vprintf(fmt, pvar);
69     putchar('\n');
70     va_end(pvar);
71 }
72
73 void
74 init_pr_log(const char *prefix, int level)
75 {
76 }
77
78 void
79 end_pr_log(void)
80 {
81     fflush(debugFile);
82 }
83
84 void
85 pr_log(void *arg, char *fmt, ...)
86 {
87     va_list ap;
88     va_start(ap, fmt);
89     vfprintf(debugFile, fmt, ap);
90     va_end(ap);
91 }
92
93 size_t
94 strlcpy(char *dest, const char *src, size_t len)
95 {
96     size_t ret = strlen(src);
97
98     if (len != 0) {
99         if (ret < len)
100             strcpy(dest, src);
101         else {
102             strncpy(dest, src, len - 1);
103             dest[len-1] = 0;
104         }
105     }
106     return ret;
107 }
108
109 static char *
110 xstrdup(const char *s)
111 {
112     char *ret = strdup(s);
113     if (!ret) {
114         perror("strdup");
115         exit(1);
116     }
117     return ret;
118 }
119
120 int
121 get_time(struct timeval *tv)
122 {
123     return gettimeofday(tv, NULL);
124 }
125
126 static void
127 term_handler(int signum)
128 {
129     got_sigterm = 1;
130 }
131
132 static void usage(void);
133
134 int main(int argc, char *argv[])
135 {
136     int opt;
137     PPPoEConnection *conn;
138
139     signal(SIGINT, term_handler);
140     signal(SIGTERM, term_handler);
141
142     conn = malloc(sizeof(PPPoEConnection));
143     if (!conn) {
144         perror("malloc");
145         exit(1);
146     }
147
148     memset(conn, 0, sizeof(PPPoEConnection));
149
150     pppoe_verbose = 1;
151     conn->discoveryTimeout = PADI_TIMEOUT;
152     conn->discoveryAttempts = MAX_PADI_ATTEMPTS;
153
154     while ((opt = getopt(argc, argv, "I:D:VUQS:C:W:t:a:h")) > 0) {
155         switch(opt) {
156         case 'S':
157             conn->serviceName = xstrdup(optarg);
158             break;
159         case 'C':
160             conn->acName = xstrdup(optarg);
161             break;
162         case 't':
163             if (sscanf(optarg, "%d", &conn->discoveryTimeout) != 1) {
164                 fprintf(stderr, "Illegal argument to -t: Should be -t timeout\n");
165                 exit(EXIT_FAILURE);
166             }
167             if (conn->discoveryTimeout < 1) {
168                 conn->discoveryTimeout = 1;
169             }
170             break;
171         case 'a':
172             if (sscanf(optarg, "%d", &conn->discoveryAttempts) != 1) {
173                 fprintf(stderr, "Illegal argument to -a: Should be -a attempts\n");
174                 exit(EXIT_FAILURE);
175             }
176             if (conn->discoveryAttempts < 1) {
177                 conn->discoveryAttempts = 1;
178             }
179             break;
180         case 'U':
181             if(conn->hostUniq.length) {
182                 fprintf(stderr, "-U and -W are mutually exclusive\n");
183                 exit(EXIT_FAILURE);
184             } else {
185                 pid_t pid = getpid();
186                 conn->hostUniq.type = htons(TAG_HOST_UNIQ);
187                 conn->hostUniq.length = htons(sizeof(pid));
188                 memcpy(conn->hostUniq.payload, &pid, sizeof(pid));
189             }
190             break;
191         case 'W':
192             if(conn->hostUniq.length) {
193                 fprintf(stderr, "-U and -W are mutually exclusive\n");
194                 exit(EXIT_FAILURE);
195             }
196             if (!parseHostUniq(optarg, &conn->hostUniq)) {
197                 fprintf(stderr, "Invalid host-uniq argument: %s\n", optarg);
198                 exit(EXIT_FAILURE);
199             }
200             break;
201         case 'D':
202             pppoe_verbose = 2;
203             debug = 1;
204             debugFile = fopen(optarg, "w");
205             if (!debugFile) {
206                 fprintf(stderr, "Could not open %s: %s\n",
207                         optarg, strerror(errno));
208                 exit(1);
209             }
210             fprintf(debugFile, "pppoe-discovery from pppd %s\n", VERSION);
211             break;
212         case 'I':
213             conn->ifName = xstrdup(optarg);
214             break;
215         case 'Q':
216             pppoe_verbose = 0;
217             break;
218         case 'V':
219         case 'h':
220             usage();
221             exit(0);
222         default:
223             usage();
224             exit(1);
225         }
226     }
227
228     if (optind != argc) {
229         fprintf(stderr, "%s: extra argument '%s'\n", argv[0], argv[optind]);
230         usage();
231         exit(EXIT_FAILURE);
232     }
233
234     if (!conn->ifName) {
235         fprintf(stderr, "Interface was not specified\n");
236         exit(EXIT_FAILURE);
237     }
238
239     conn->sessionSocket = -1;
240
241     conn->discoverySocket = openInterface(conn->ifName, Eth_PPPOE_Discovery, conn->myEth);
242     if (conn->discoverySocket < 0) {
243         perror("Cannot create PPPoE discovery socket");
244         exit(1);
245     }
246
247     discovery1(conn);
248
249     if (!conn->numPADOs)
250         exit(1);
251     else
252         exit(0);
253 }
254
255 static void
256 usage(void)
257 {
258     fprintf(stderr, "Usage: pppoe-discovery [options]\n");
259     fprintf(stderr, "Options:\n");
260     fprintf(stderr, "   -I if_name     -- Specify interface (mandatory option)\n");
261     fprintf(stderr, "   -D filename    -- Log debugging information in filename.\n");
262     fprintf(stderr,
263             "   -t timeout     -- Initial timeout for discovery packets in seconds\n"
264             "   -a attempts    -- Number of discovery attempts\n"
265             "   -V             -- Print version and exit.\n"
266             "   -Q             -- Quit Mode: Do not print access concentrator names\n"
267             "   -S name        -- Set desired service name.\n"
268             "   -C name        -- Set desired access concentrator name.\n"
269             "   -U             -- Use Host-Unique to allow multiple PPPoE sessions.\n"
270             "   -W hexvalue    -- Set the Host-Unique to the supplied hex string.\n"
271             "   -h             -- Print usage information.\n");
272     fprintf(stderr, "\npppoe-discovery from pppd " VERSION "\n");
273 }