summaryrefslogtreecommitdiff
path: root/jni/src/discovery.c (plain)
blob: c92ceef27019ee853dca0fedc3376e1acc255a43
1/***********************************************************************
2*
3* discovery.c
4*
5* Perform PPPoE discovery
6*
7* Copyright (C) 1999 by Roaring Penguin Software Inc.
8*
9* LIC: GPL
10*
11***********************************************************************/
12
13static char const RCSID[] =
14"$Id$";
15
16#include "pppoe.h"
17
18#ifdef HAVE_SYSLOG_H
19#include <syslog.h>
20#include <android/log.h>
21#define syslog(prio, fmt...) \
22 __android_log_print(prio, "PPPOE", fmt)
23#endif
24
25#include <string.h>
26#include <stdlib.h>
27#include <errno.h>
28
29#ifdef HAVE_SYS_TIME_H
30#include <sys/time.h>
31#endif
32#include <time.h>
33
34#ifdef HAVE_SYS_UIO_H
35#include <sys/uio.h>
36#endif
37
38#ifdef HAVE_UNISTD_H
39#include <unistd.h>
40#endif
41
42#ifdef USE_LINUX_PACKET
43#include <sys/ioctl.h>
44#include <fcntl.h>
45#endif
46
47#include <signal.h>
48
49/* Supplied by pppd if we're a plugin */
50extern int persist;
51
52/**********************************************************************
53*%FUNCTION: parseForHostUniq
54*%ARGUMENTS:
55* type -- tag type
56* len -- tag length
57* data -- tag data.
58* extra -- user-supplied pointer. This is assumed to be a pointer to int.
59*%RETURNS:
60* Nothing
61*%DESCRIPTION:
62* If a HostUnique tag is found which matches our PID, sets *extra to 1.
63***********************************************************************/
64static void
65parseForHostUniq(UINT16_t type, UINT16_t len, unsigned char *data,
66 void *extra)
67{
68 int *val = (int *) extra;
69 if (type == TAG_HOST_UNIQ && len == sizeof(pid_t)) {
70 pid_t tmp;
71 memcpy(&tmp, data, len);
72 if (tmp == getpid()) {
73 *val = 1;
74 }
75 }
76}
77
78/**********************************************************************
79*%FUNCTION: packetIsForMe
80*%ARGUMENTS:
81* conn -- PPPoE connection info
82* packet -- a received PPPoE packet
83*%RETURNS:
84* 1 if packet is for this PPPoE daemon; 0 otherwise.
85*%DESCRIPTION:
86* If we are using the Host-Unique tag, verifies that packet contains
87* our unique identifier.
88***********************************************************************/
89static int
90packetIsForMe(PPPoEConnection *conn, PPPoEPacket *packet)
91{
92 int forMe = 0;
93
94 /* If packet is not directed to our MAC address, forget it */
95 if (memcmp(packet->ethHdr.h_dest, conn->myEth, ETH_ALEN)) return 0;
96
97 /* If we're not using the Host-Unique tag, then accept the packet */
98 if (!conn->useHostUniq) return 1;
99
100 parsePacket(packet, parseForHostUniq, &forMe);
101 return forMe;
102}
103
104/**********************************************************************
105*%FUNCTION: parsePADOTags
106*%ARGUMENTS:
107* type -- tag type
108* len -- tag length
109* data -- tag data
110* extra -- extra user data. Should point to a PacketCriteria structure
111* which gets filled in according to selected AC name and service
112* name.
113*%RETURNS:
114* Nothing
115*%DESCRIPTION:
116* Picks interesting tags out of a PADO packet
117***********************************************************************/
118static void
119parsePADOTags(UINT16_t type, UINT16_t len, unsigned char *data,
120 void *extra)
121{
122 struct PacketCriteria *pc = (struct PacketCriteria *) extra;
123 PPPoEConnection *conn = pc->conn;
124 int i;
125
126 switch(type) {
127 case TAG_AC_NAME:
128 pc->seenACName = 1;
129 if (conn->printACNames) {
130 printf("Access-Concentrator: %.*s\n", (int) len, data);
131 }
132 if (conn->acName && len == strlen(conn->acName) &&
133 !strncmp((char *) data, conn->acName, len)) {
134 pc->acNameOK = 1;
135 }
136 break;
137 case TAG_SERVICE_NAME:
138 pc->seenServiceName = 1;
139 if (conn->printACNames && len > 0) {
140 printf(" Service-Name: %.*s\n", (int) len, data);
141 }
142 if (conn->serviceName && len == strlen(conn->serviceName) &&
143 !strncmp((char *) data, conn->serviceName, len)) {
144 pc->serviceNameOK = 1;
145 }
146 break;
147 case TAG_AC_COOKIE:
148 if (conn->printACNames) {
149 printf("Got a cookie:");
150 /* Print first 20 bytes of cookie */
151 for (i=0; i<len && i < 20; i++) {
152 printf(" %02x", (unsigned) data[i]);
153 }
154 if (i < len) printf("...");
155 printf("\n");
156 }
157 conn->cookie.type = htons(type);
158 conn->cookie.length = htons(len);
159 memcpy(conn->cookie.payload, data, len);
160 break;
161 case TAG_RELAY_SESSION_ID:
162 if (conn->printACNames) {
163 printf("Got a Relay-ID:");
164 /* Print first 20 bytes of relay ID */
165 for (i=0; i<len && i < 20; i++) {
166 printf(" %02x", (unsigned) data[i]);
167 }
168 if (i < len) printf("...");
169 printf("\n");
170 }
171 conn->relayId.type = htons(type);
172 conn->relayId.length = htons(len);
173 memcpy(conn->relayId.payload, data, len);
174 break;
175 case TAG_SERVICE_NAME_ERROR:
176 if (conn->printACNames) {
177 printf("Got a Service-Name-Error tag: %.*s\n", (int) len, data);
178 } else {
179 pktLogErrs("PADO", type, len, data, extra);
180 exit(1);
181 }
182 break;
183 case TAG_AC_SYSTEM_ERROR:
184 if (conn->printACNames) {
185 printf("Got a System-Error tag: %.*s\n", (int) len, data);
186 } else {
187 pktLogErrs("PADO", type, len, data, extra);
188 exit(1);
189 }
190 break;
191 case TAG_GENERIC_ERROR:
192 if (conn->printACNames) {
193 printf("Got a Generic-Error tag: %.*s\n", (int) len, data);
194 } else {
195 pktLogErrs("PADO", type, len, data, extra);
196 exit(1);
197 }
198 break;
199 }
200}
201
202/**********************************************************************
203*%FUNCTION: parsePADSTags
204*%ARGUMENTS:
205* type -- tag type
206* len -- tag length
207* data -- tag data
208* extra -- extra user data (pointer to PPPoEConnection structure)
209*%RETURNS:
210* Nothing
211*%DESCRIPTION:
212* Picks interesting tags out of a PADS packet
213***********************************************************************/
214static void
215parsePADSTags(UINT16_t type, UINT16_t len, unsigned char *data,
216 void *extra)
217{
218 PPPoEConnection *conn = (PPPoEConnection *) extra;
219 switch(type) {
220 case TAG_SERVICE_NAME:
221 syslog(LOG_DEBUG, "PADS: Service-Name: '%.*s'", (int) len, data);
222 break;
223 case TAG_GENERIC_ERROR:
224 case TAG_AC_SYSTEM_ERROR:
225 case TAG_SERVICE_NAME_ERROR:
226 pktLogErrs("PADS", type, len, data, extra);
227 conn->PADSHadError = 1;
228 break;
229 case TAG_RELAY_SESSION_ID:
230 conn->relayId.type = htons(type);
231 conn->relayId.length = htons(len);
232 memcpy(conn->relayId.payload, data, len);
233 break;
234 }
235}
236
237/***********************************************************************
238*%FUNCTION: sendPADI
239*%ARGUMENTS:
240* conn -- PPPoEConnection structure
241*%RETURNS:
242* Nothing
243*%DESCRIPTION:
244* Sends a PADI packet
245***********************************************************************/
246static void
247sendPADI(PPPoEConnection *conn)
248{
249 PPPoEPacket packet;
250 unsigned char *cursor = packet.payload;
251 PPPoETag *svc = (PPPoETag *) (&packet.payload);
252 UINT16_t namelen = 0;
253 UINT16_t plen;
254 int omit_service_name = 0;
255
256 if (conn->serviceName) {
257 namelen = (UINT16_t) strlen(conn->serviceName);
258 if (!strcmp(conn->serviceName, "NO-SERVICE-NAME-NON-RFC-COMPLIANT")) {
259 omit_service_name = 1;
260 }
261 }
262
263 /* Set destination to Ethernet broadcast address */
264 memset(packet.ethHdr.h_dest, 0xFF, ETH_ALEN);
265 memcpy(packet.ethHdr.h_source, conn->myEth, ETH_ALEN);
266
267 packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
268 packet.ver = 1;
269 packet.type = 1;
270 packet.code = CODE_PADI;
271 packet.session = 0;
272
273 if (!omit_service_name) {
274 plen = TAG_HDR_SIZE + namelen;
275 CHECK_ROOM(cursor, packet.payload, plen);
276
277 svc->type = TAG_SERVICE_NAME;
278 svc->length = htons(namelen);
279
280 if (conn->serviceName) {
281 memcpy(svc->payload, conn->serviceName, strlen(conn->serviceName));
282 }
283 cursor += namelen + TAG_HDR_SIZE;
284 } else {
285 plen = 0;
286 }
287
288 /* If we're using Host-Uniq, copy it over */
289 if (conn->useHostUniq) {
290 PPPoETag hostUniq;
291 pid_t pid = getpid();
292 hostUniq.type = htons(TAG_HOST_UNIQ);
293 hostUniq.length = htons(sizeof(pid));
294 memcpy(hostUniq.payload, &pid, sizeof(pid));
295 CHECK_ROOM(cursor, packet.payload, sizeof(pid) + TAG_HDR_SIZE);
296 memcpy(cursor, &hostUniq, sizeof(pid) + TAG_HDR_SIZE);
297 cursor += sizeof(pid) + TAG_HDR_SIZE;
298 plen += sizeof(pid) + TAG_HDR_SIZE;
299 }
300
301 packet.length = htons(plen);
302
303 sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE));
304#ifdef DEBUGGING_ENABLED
305 if (conn->debugFile) {
306 dumpPacket(conn->debugFile, &packet, "SENT");
307 fprintf(conn->debugFile, "\n");
308 fflush(conn->debugFile);
309 }
310#endif
311}
312
313/**********************************************************************
314*%FUNCTION: waitForPADO
315*%ARGUMENTS:
316* conn -- PPPoEConnection structure
317* timeout -- how long to wait (in seconds)
318*%RETURNS:
319* Nothing
320*%DESCRIPTION:
321* Waits for a PADO packet and copies useful information
322***********************************************************************/
323static void
324waitForPADO(PPPoEConnection *conn, int timeout)
325{
326 fd_set readable;
327 int r;
328 struct timeval tv;
329 struct timeval expire_at;
330 struct timeval now;
331
332 PPPoEPacket packet;
333 int len;
334
335 struct PacketCriteria pc;
336 pc.conn = conn;
337 pc.acNameOK = (conn->acName) ? 0 : 1;
338 pc.serviceNameOK = (conn->serviceName) ? 0 : 1;
339 pc.seenACName = 0;
340 pc.seenServiceName = 0;
341
342 if (gettimeofday(&expire_at, NULL) < 0) {
343 fatalSys("gettimeofday (waitForPADO)");
344 }
345 expire_at.tv_sec += timeout;
346
347 do {
348 if (BPF_BUFFER_IS_EMPTY) {
349 if (gettimeofday(&now, NULL) < 0) {
350 fatalSys("gettimeofday (waitForPADO)");
351 }
352 tv.tv_sec = expire_at.tv_sec - now.tv_sec;
353 tv.tv_usec = expire_at.tv_usec - now.tv_usec;
354 if (tv.tv_usec < 0) {
355 tv.tv_usec += 1000000;
356 if (tv.tv_sec) {
357 tv.tv_sec--;
358 } else {
359 /* Timed out */
360 return;
361 }
362 }
363 if (tv.tv_sec <= 0 && tv.tv_usec <= 0) {
364 /* Timed out */
365 return;
366 }
367
368 FD_ZERO(&readable);
369 FD_SET(conn->discoverySocket, &readable);
370
371 while(1) {
372 r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv);
373 if (r >= 0 || errno != EINTR) {
374 syslog( LOG_INFO, "waitForPADO: (r >= 0 || errno != EINTR)\n");
375 break;
376 }
377 }
378
379 if (r < 0) {
380 fatalSys("select (waitForPADO)");
381 }
382 if (r == 0) {
383 /* Timed out */
384 return;
385 }
386 }
387
388 /* Get the packet */
389 receivePacket(conn->discoverySocket, &packet, &len);
390
391 /* Check length */
392 if (ntohs(packet.length) + HDR_SIZE > (unsigned int)len) {
393 syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
394 (unsigned int) ntohs(packet.length));
395 continue;
396 }
397
398#ifdef USE_BPF
399 /* If it's not a Discovery packet, loop again */
400 if (etherType(&packet) != Eth_PPPOE_Discovery) continue;
401#endif
402
403#ifdef DEBUGGING_ENABLED
404 if (conn->debugFile) {
405 dumpPacket(conn->debugFile, &packet, "RCVD");
406 fprintf(conn->debugFile, "\n");
407 fflush(conn->debugFile);
408 }
409#endif
410 /* If it's not for us, loop again */
411 if (!packetIsForMe(conn, &packet)) continue;
412
413 if (packet.code == CODE_PADO) {
414 if (NOT_UNICAST(packet.ethHdr.h_source)) {
415 printErr("Ignoring PADO packet from non-unicast MAC address");
416 continue;
417 }
418 parsePacket(&packet, parsePADOTags, &pc);
419 if (!pc.seenACName) {
420 printErr("Ignoring PADO packet with no AC-Name tag");
421 continue;
422 }
423 if (!pc.seenServiceName) {
424 printErr("Ignoring PADO packet with no Service-Name tag");
425 continue;
426 }
427 conn->numPADOs++;
428 if (pc.acNameOK && pc.serviceNameOK) {
429 memcpy(conn->peerEth, packet.ethHdr.h_source, ETH_ALEN);
430 if (conn->printACNames) {
431 printf("AC-Ethernet-Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
432 (unsigned) conn->peerEth[0],
433 (unsigned) conn->peerEth[1],
434 (unsigned) conn->peerEth[2],
435 (unsigned) conn->peerEth[3],
436 (unsigned) conn->peerEth[4],
437 (unsigned) conn->peerEth[5]);
438 printf("--------------------------------------------------\n");
439 continue;
440 }
441 conn->discoveryState = STATE_RECEIVED_PADO;
442 break;
443 }
444 }
445 } while (conn->discoveryState != STATE_RECEIVED_PADO);
446}
447
448/***********************************************************************
449*%FUNCTION: sendPADR
450*%ARGUMENTS:
451* conn -- PPPoE connection structur
452*%RETURNS:
453* Nothing
454*%DESCRIPTION:
455* Sends a PADR packet
456***********************************************************************/
457static void
458sendPADR(PPPoEConnection *conn)
459{
460 PPPoEPacket packet;
461 PPPoETag *svc = (PPPoETag *) packet.payload;
462 unsigned char *cursor = packet.payload;
463
464 UINT16_t namelen = 0;
465 UINT16_t plen;
466
467 if (conn->serviceName) {
468 namelen = (UINT16_t) strlen(conn->serviceName);
469 }
470 plen = TAG_HDR_SIZE + namelen;
471 CHECK_ROOM(cursor, packet.payload, plen);
472
473 memcpy(packet.ethHdr.h_dest, conn->peerEth, ETH_ALEN);
474 memcpy(packet.ethHdr.h_source, conn->myEth, ETH_ALEN);
475
476 packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
477 packet.ver = 1;
478 packet.type = 1;
479 packet.code = CODE_PADR;
480 packet.session = 0;
481
482 svc->type = TAG_SERVICE_NAME;
483 svc->length = htons(namelen);
484 if (conn->serviceName) {
485 memcpy(svc->payload, conn->serviceName, namelen);
486 }
487 cursor += namelen + TAG_HDR_SIZE;
488
489 /* If we're using Host-Uniq, copy it over */
490 if (conn->useHostUniq) {
491 PPPoETag hostUniq;
492 pid_t pid = getpid();
493 hostUniq.type = htons(TAG_HOST_UNIQ);
494 hostUniq.length = htons(sizeof(pid));
495 memcpy(hostUniq.payload, &pid, sizeof(pid));
496 CHECK_ROOM(cursor, packet.payload, sizeof(pid)+TAG_HDR_SIZE);
497 memcpy(cursor, &hostUniq, sizeof(pid) + TAG_HDR_SIZE);
498 cursor += sizeof(pid) + TAG_HDR_SIZE;
499 plen += sizeof(pid) + TAG_HDR_SIZE;
500 }
501
502 /* Copy cookie and relay-ID if needed */
503 if (conn->cookie.type) {
504 CHECK_ROOM(cursor, packet.payload,
505 ntohs(conn->cookie.length) + TAG_HDR_SIZE);
506 memcpy(cursor, &conn->cookie, ntohs(conn->cookie.length) + TAG_HDR_SIZE);
507 cursor += ntohs(conn->cookie.length) + TAG_HDR_SIZE;
508 plen += ntohs(conn->cookie.length) + TAG_HDR_SIZE;
509 }
510
511 if (conn->relayId.type) {
512 CHECK_ROOM(cursor, packet.payload,
513 ntohs(conn->relayId.length) + TAG_HDR_SIZE);
514 memcpy(cursor, &conn->relayId, ntohs(conn->relayId.length) + TAG_HDR_SIZE);
515 cursor += ntohs(conn->relayId.length) + TAG_HDR_SIZE;
516 plen += ntohs(conn->relayId.length) + TAG_HDR_SIZE;
517 }
518
519 packet.length = htons(plen);
520 sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE));
521#ifdef DEBUGGING_ENABLED
522 if (conn->debugFile) {
523 dumpPacket(conn->debugFile, &packet, "SENT");
524 fprintf(conn->debugFile, "\n");
525 fflush(conn->debugFile);
526 }
527#endif
528}
529
530/**********************************************************************
531*%FUNCTION: waitForPADS
532*%ARGUMENTS:
533* conn -- PPPoE connection info
534* timeout -- how long to wait (in seconds)
535*%RETURNS:
536* Nothing
537*%DESCRIPTION:
538* Waits for a PADS packet and copies useful information
539***********************************************************************/
540static void
541waitForPADS(PPPoEConnection *conn, int timeout)
542{
543 fd_set readable;
544 int r;
545 struct timeval tv;
546 struct timeval expire_at;
547 struct timeval now;
548
549 PPPoEPacket packet;
550 int len;
551
552 if (gettimeofday(&expire_at, NULL) < 0) {
553 fatalSys("gettimeofday (waitForPADS)");
554 }
555 expire_at.tv_sec += timeout;
556
557 do {
558 if (BPF_BUFFER_IS_EMPTY) {
559 if (gettimeofday(&now, NULL) < 0) {
560 fatalSys("gettimeofday (waitForPADS)");
561 }
562 tv.tv_sec = expire_at.tv_sec - now.tv_sec;
563 tv.tv_usec = expire_at.tv_usec - now.tv_usec;
564 if (tv.tv_usec < 0) {
565 tv.tv_usec += 1000000;
566 if (tv.tv_sec) {
567 tv.tv_sec--;
568 } else {
569 /* Timed out */
570 return;
571 }
572 }
573 if (tv.tv_sec <= 0 && tv.tv_usec <= 0) {
574 /* Timed out */
575 return;
576 }
577
578 FD_ZERO(&readable);
579 FD_SET(conn->discoverySocket, &readable);
580
581 while(1) {
582 r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv);
583 if (r >= 0 || errno != EINTR) break;
584 }
585 if (r < 0) {
586 fatalSys("select (waitForPADS)");
587 }
588 if (r == 0) {
589 /* Timed out */
590 return;
591 }
592 }
593
594 /* Get the packet */
595 receivePacket(conn->discoverySocket, &packet, &len);
596
597 /* Check length */
598 if (ntohs(packet.length) + HDR_SIZE > (unsigned int)len) {
599 syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
600 (unsigned int) ntohs(packet.length));
601 continue;
602 }
603
604#ifdef USE_BPF
605 /* If it's not a Discovery packet, loop again */
606 if (etherType(&packet) != Eth_PPPOE_Discovery) continue;
607#endif
608#ifdef DEBUGGING_ENABLED
609 if (conn->debugFile) {
610 dumpPacket(conn->debugFile, &packet, "RCVD");
611 fprintf(conn->debugFile, "\n");
612 fflush(conn->debugFile);
613 }
614#endif
615 /* If it's not from the AC, it's not for me */
616 if (memcmp(packet.ethHdr.h_source, conn->peerEth, ETH_ALEN)) continue;
617
618 /* If it's not for us, loop again */
619 if (!packetIsForMe(conn, &packet)) continue;
620
621 /* Is it PADS? */
622 if (packet.code == CODE_PADS) {
623 /* Parse for goodies */
624 conn->PADSHadError = 0;
625 parsePacket(&packet, parsePADSTags, conn);
626 if (!conn->PADSHadError) {
627 conn->discoveryState = STATE_SESSION;
628 break;
629 }
630 }
631 } while (conn->discoveryState != STATE_SESSION);
632
633 /* Don't bother with ntohs; we'll just end up converting it back... */
634 conn->session = packet.session;
635
636 syslog(LOG_INFO, "PPP session is %d (0x%x)", (int) ntohs(conn->session),
637 (unsigned int) ntohs(conn->session));
638
639 /* RFC 2516 says session id MUST NOT be zero or 0xFFFF */
640 if (ntohs(conn->session) == 0 || ntohs(conn->session) == 0xFFFF) {
641 syslog(LOG_ERR, "Access concentrator used a session value of %x -- the AC is violating RFC 2516", (unsigned int) ntohs(conn->session));
642 }
643}
644
645/**********************************************************************
646*%FUNCTION: discovery
647*%ARGUMENTS:
648* conn -- PPPoE connection info structure
649*%RETURNS:
650* Nothing
651*%DESCRIPTION:
652* Performs the PPPoE discovery phase
653***********************************************************************/
654static struct timeval current_time;
655
656static int g_padi_sent = 0;
657void
658discovery(PPPoEConnection *conn)
659{
660 int padiAttempts = 0;
661 int padrAttempts = 0;
662 int timeout = conn->discoveryTimeout;
663
664 fprintf(stderr, "discovery: timeout = %d\n", timeout);
665
666 /* Skip discovery? */
667 if (conn->skipDiscovery) {
668 conn->discoveryState = STATE_SESSION;
669 if (conn->killSession) {
670 sendPADT(conn, "RP-PPPoE: Session killed manually");
671 exit(0);
672 }
673 return;
674 }
675
676 do {
677 padiAttempts++;
678 if (padiAttempts > MAX_PADI_ATTEMPTS) {
679 if (persist) {
680 padiAttempts = 0;
681 timeout = conn->discoveryTimeout;
682 printErr("Timeout waiting for PADO packets");
683 } else {
684 rp_fatal("Timeout waiting for PADO packets");
685 }
686 }
687 fprintf(stderr, "sendPADI\n");
688 syslog( LOG_INFO, "sendPADI\n");
689 sendPADI(conn);
690
691 conn->discoveryState = STATE_SENT_PADI;
692 gettimeofday(&current_time, NULL);
693 fprintf(stderr, "before: sec = %d, usec = %d\n", (int)current_time.tv_sec, (int)current_time.tv_usec);
694 waitForPADO(conn, timeout);
695 gettimeofday(&current_time, NULL);
696 fprintf(stderr, "after: sec = %d, usec = %d\n", (int)current_time.tv_sec, (int)current_time.tv_usec);
697 /* If we're just probing for access concentrators, don't do
698 exponential backoff. This reduces the time for an unsuccessful
699 probe to 15 seconds. */
700 if (!conn->printACNames) {
701 timeout *= 2;
702 }
703 if (conn->printACNames && conn->numPADOs) {
704 break;
705 }
706 } while (conn->discoveryState == STATE_SENT_PADI);
707
708 /* If we're only printing access concentrator names, we're done */
709 if (conn->printACNames) {
710 exit(0);
711 }
712
713 timeout = conn->discoveryTimeout;
714 do {
715 padrAttempts++;
716 if (padrAttempts > MAX_PADI_ATTEMPTS) {
717 if (persist) {
718 padrAttempts = 0;
719 timeout = conn->discoveryTimeout;
720 printErr("Timeout waiting for PADS packets");
721 } else {
722 rp_fatal("Timeout waiting for PADS packets");
723 }
724 }
725 fprintf(stderr, "sendPADR\n");
726 syslog( LOG_INFO, "sendPADR\n");
727 sendPADR(conn);
728 conn->discoveryState = STATE_SENT_PADR;
729 waitForPADS(conn, timeout);
730 timeout *= 2;
731 } while (conn->discoveryState == STATE_SENT_PADR);
732
733 /* We're done. */
734 conn->discoveryState = STATE_SESSION;
735 return;
736}
737