]> git.ozlabs.org Git - ppp.git/blob - pppd/plugins/pppoe/pppoe-discovery.c
Merge branch 'pppoe-discovery' of https://github.com/pali/ppp
[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 #ifdef HAVE_UNISTD_H
28 #include <unistd.h>
29 #endif
30
31 #ifdef HAVE_NETPACKET_PACKET_H
32 #include <netpacket/packet.h>
33 #elif defined(HAVE_LINUX_IF_PACKET_H)
34 #include <linux/if_packet.h>
35 #endif
36
37 #ifdef HAVE_ASM_TYPES_H
38 #include <asm/types.h>
39 #endif
40
41 #ifdef HAVE_SYS_IOCTL_H
42 #include <sys/ioctl.h>
43 #endif
44
45 #include <errno.h>
46 #include <stdlib.h>
47 #include <string.h>
48
49 #ifdef HAVE_NET_IF_ARP_H
50 #include <net/if_arp.h>
51 #endif
52
53 int debug;
54 int got_sigterm;
55 int pppoe_verbose;
56 static FILE *debugFile;
57
58 void
59 fatal(char *fmt, ...)
60 {
61     va_list pvar;
62     va_start(pvar, fmt);
63     vfprintf(stderr, fmt, pvar);
64     va_end(pvar);
65     fputc('\n', stderr);
66     exit(1);
67 }
68
69 void
70 error(char *fmt, ...)
71 {
72     va_list pvar;
73     va_start(pvar, fmt);
74     vfprintf(stderr, fmt, pvar);
75     fputc('\n', stderr);
76     va_end(pvar);
77 }
78
79 void
80 warn(char *fmt, ...)
81 {
82     va_list pvar;
83     va_start(pvar, fmt);
84     vfprintf(stderr, fmt, pvar);
85     fputc('\n', stderr);
86     va_end(pvar);
87 }
88
89 void
90 info(char *fmt, ...)
91 {
92     va_list pvar;
93     va_start(pvar, fmt);
94     vprintf(fmt, pvar);
95     putchar('\n');
96     va_end(pvar);
97 }
98
99 void
100 init_pr_log(const char *prefix, int level)
101 {
102 }
103
104 void
105 end_pr_log(void)
106 {
107     fflush(debugFile);
108 }
109
110 void
111 pr_log(void *arg, char *fmt, ...)
112 {
113     va_list ap;
114     va_start(ap, fmt);
115     vfprintf(debugFile, fmt, ap);
116     va_end(ap);
117 }
118
119 size_t
120 strlcpy(char *dest, const char *src, size_t len)
121 {
122     size_t ret = strlen(src);
123
124     if (len != 0) {
125         if (ret < len)
126             strcpy(dest, src);
127         else {
128             strncpy(dest, src, len - 1);
129             dest[len-1] = 0;
130         }
131     }
132     return ret;
133 }
134
135 static char *
136 xstrdup(const char *s)
137 {
138     char *ret = strdup(s);
139     if (!ret) {
140         perror("strdup");
141         exit(1);
142     }
143     return ret;
144 }
145
146 int
147 get_time(struct timeval *tv)
148 {
149     return gettimeofday(tv, NULL);
150 }
151
152 static void
153 term_handler(int signum)
154 {
155     got_sigterm = 1;
156 }
157
158 static void usage(void);
159
160 int main(int argc, char *argv[])
161 {
162     int opt;
163     PPPoEConnection *conn;
164
165     signal(SIGINT, term_handler);
166     signal(SIGTERM, term_handler);
167
168     conn = malloc(sizeof(PPPoEConnection));
169     if (!conn) {
170         perror("malloc");
171         exit(1);
172     }
173
174     memset(conn, 0, sizeof(PPPoEConnection));
175
176     pppoe_verbose = 1;
177     conn->discoveryTimeout = PADI_TIMEOUT;
178     conn->discoveryAttempts = MAX_PADI_ATTEMPTS;
179
180     while ((opt = getopt(argc, argv, "I:D:VUQS:C:W:t:a:h")) > 0) {
181         switch(opt) {
182         case 'S':
183             conn->serviceName = xstrdup(optarg);
184             break;
185         case 'C':
186             conn->acName = xstrdup(optarg);
187             break;
188         case 't':
189             if (sscanf(optarg, "%d", &conn->discoveryTimeout) != 1) {
190                 fprintf(stderr, "Illegal argument to -t: Should be -t timeout\n");
191                 exit(EXIT_FAILURE);
192             }
193             if (conn->discoveryTimeout < 1) {
194                 conn->discoveryTimeout = 1;
195             }
196             break;
197         case 'a':
198             if (sscanf(optarg, "%d", &conn->discoveryAttempts) != 1) {
199                 fprintf(stderr, "Illegal argument to -a: Should be -a attempts\n");
200                 exit(EXIT_FAILURE);
201             }
202             if (conn->discoveryAttempts < 1) {
203                 conn->discoveryAttempts = 1;
204             }
205             break;
206         case 'U':
207             if(conn->hostUniq.length) {
208                 fprintf(stderr, "-U and -W are mutually exclusive\n");
209                 exit(EXIT_FAILURE);
210             } else {
211                 pid_t pid = getpid();
212                 conn->hostUniq.type = htons(TAG_HOST_UNIQ);
213                 conn->hostUniq.length = htons(sizeof(pid));
214                 memcpy(conn->hostUniq.payload, &pid, sizeof(pid));
215             }
216             break;
217         case 'W':
218             if(conn->hostUniq.length) {
219                 fprintf(stderr, "-U and -W are mutually exclusive\n");
220                 exit(EXIT_FAILURE);
221             }
222             if (!parseHostUniq(optarg, &conn->hostUniq)) {
223                 fprintf(stderr, "Invalid host-uniq argument: %s\n", optarg);
224                 exit(EXIT_FAILURE);
225             }
226             break;
227         case 'D':
228             pppoe_verbose = 2;
229             debug = 1;
230             debugFile = fopen(optarg, "w");
231             if (!debugFile) {
232                 fprintf(stderr, "Could not open %s: %s\n",
233                         optarg, strerror(errno));
234                 exit(1);
235             }
236             fprintf(debugFile, "pppoe-discovery from pppd %s\n", VERSION);
237             break;
238         case 'I':
239             conn->ifName = xstrdup(optarg);
240             break;
241         case 'Q':
242             pppoe_verbose = 0;
243             break;
244         case 'V':
245         case 'h':
246             usage();
247             exit(0);
248         default:
249             usage();
250             exit(1);
251         }
252     }
253
254     /* default interface name */
255     if (!conn->ifName)
256         conn->ifName = xstrdup("eth0");
257
258     conn->sessionSocket = -1;
259
260     conn->discoverySocket = openInterface(conn->ifName, Eth_PPPOE_Discovery, conn->myEth);
261     if (conn->discoverySocket < 0) {
262         perror("Cannot create PPPoE discovery socket");
263         exit(1);
264     }
265
266     discovery1(conn);
267
268     if (!conn->numPADOs)
269         exit(1);
270     else
271         exit(0);
272 }
273
274 static void
275 usage(void)
276 {
277     fprintf(stderr, "Usage: pppoe-discovery [options]\n");
278     fprintf(stderr, "Options:\n");
279     fprintf(stderr, "   -I if_name     -- Specify interface (default eth0)\n");
280     fprintf(stderr, "   -D filename    -- Log debugging information in filename.\n");
281     fprintf(stderr,
282             "   -t timeout     -- Initial timeout for discovery packets in seconds\n"
283             "   -a attempts    -- Number of discovery attempts\n"
284             "   -V             -- Print version and exit.\n"
285             "   -Q             -- Quit Mode: Do not print access concentrator names\n"
286             "   -S name        -- Set desired service name.\n"
287             "   -C name        -- Set desired access concentrator name.\n"
288             "   -U             -- Use Host-Unique to allow multiple PPPoE sessions.\n"
289             "   -W hexvalue    -- Set the Host-Unique to the supplied hex string.\n"
290             "   -h             -- Print usage information.\n");
291     fprintf(stderr, "\npppoe-discovery from pppd " VERSION "\n");
292 }