/* Determine whether a given request should be forwarded. */ int request_redundant(struct interface *ifp, const unsigned char *prefix, unsigned char plen, const unsigned char *src_prefix, unsigned char src_plen, unsigned short seqno, const unsigned char *id) { struct resend *request; request = find_request(prefix, plen, src_prefix, src_plen, NULL); if(request == NULL || resend_expired(request)) return 0; if(memcmp(request->id, id, 8) == 0 && seqno_compare(request->seqno, seqno) > 0) return 0; if(request->ifp != NULL && request->ifp != ifp) return 0; if(request->max > 0) /* Will be resent. */ return 1; if(timeval_minus_msec(&now, &request->time) < (ifp ? MIN(ifp->hello_interval, 1000) : 1000)) /* Fairly recent. */ return 1; return 0; }
static int resend_expired(struct resend *resend) { switch(resend->kind) { case RESEND_REQUEST: return timeval_minus_msec(&now, &resend->time) >= REQUEST_TIMEOUT; default: return resend->max <= 0; } }
int main(int argc, char **argv) { int i, opt, rc; int sock; struct timeval now; gettime(&now); inet_pton(AF_INET6, "ff02::1:6", &babel_group); babel_port = 6696; srand(now.tv_sec ^ now.tv_usec); while(1) { opt = getopt(argc, argv, "p:u:h:c:"); if(opt < 0) break; switch(opt) { case 'p': /* prefix */ if(have_prefix) goto usage; rc = inet_pton(AF_INET6, optarg, &myprefix); if(rc != 1) goto usage; have_prefix = 1; break; case 'u': /* update interval */ update_interval = atoi(optarg); if(update_interval <= 0) goto usage; break; case 'h': /* hello interval */ hello_interval = atoi(optarg); if(hello_interval <= 0) goto usage; break; case 'c': /* link cost */ link_cost = atoi(optarg); if(link_cost <= 0) goto usage; break; default: goto usage; } } if(!have_prefix) fprintf(stderr, "Warning: you didn't ask me to announce a prefix.\n"); if(argc - optind > MAXINTERFACES) { fprintf(stderr, "Too many interfaces.\n"); exit(1); } for(i = 0; i < argc - optind; i++) { int index; index = if_nametoindex(argv[optind + i]); if(index <= 0) { fprintf(stderr, "Unknown interface %s\n", argv[i]); exit(1); } memset(&interfaces[i], 0, sizeof(interfaces[i])); interfaces[i].ifindex = index; interfaces[i].ifname = argv[optind + i]; rc = get_local_address(interfaces[i].ifindex, &interfaces[i].address); if(rc < 0) { perror("get_local_address"); fprintf(stderr, "Continuing anyway -- " "won't perform reachibility detection " "on interface %s.\n", interfaces[i].ifname); } interfaces[i].seqno = rand() & 0xFFFF; } numinterfaces = argc - optind; random_eui64(my_router_id); myseqno = rand() & 0xFFFF; sock = babel_socket(babel_port); if(sock < 0) { perror("babel_socket"); exit(1); } for(i = 0; i < numinterfaces; i++) { rc = join_group(sock, interfaces[i].ifindex, &babel_group); if(rc < 0) { perror("setsockopt(IPV6_JOIN_GROUP)"); exit(1); } } catch_signals(sigexit); while(!exiting) { struct sockaddr_in6 sin6; unsigned char buf[BUF_SIZE]; struct timeval tv, update, zerotv = {0, 0}; fd_set readfds; int hello_count = 0; /* Compute when to wake up. */ gettime(&now); timeval_add_msec(&tv, &last_hello, hello_interval * 700 + rand() % 300); timeval_add_msec(&update, &last_update, update_interval * 700 + rand() % 300); timeval_min(&tv, &update); if(selected_nexthop_metric < INFINITY) { int n = find_neighbour(selected_interface, &selected_nexthop, 0); assert(n >= 0); timeval_min(&tv, &neighbours[n].timeout); timeval_min(&tv, &selected_nexthop_timeout); } if(timeval_compare(&tv, &now) > 0) timeval_minus(&tv, &tv, &now); else tv = zerotv; FD_ZERO(&readfds); FD_SET(sock, &readfds); rc = select(sock + 1, &readfds, NULL, NULL, &tv); if(rc < 0 && errno != EINTR) { perror("select"); nap(1000); continue; } if(rc > 0) { /* Oh good, a packet. */ socklen_t sin6len = sizeof(sin6); rc = recvfrom(sock, buf, BUF_SIZE, 0, (struct sockaddr*)&sin6, &sin6len); if(rc < 0 || rc >= BUF_SIZE) { if(rc < 0 && errno != EAGAIN) { perror("recv"); nap(100); } continue; } if(sin6.sin6_family != PF_INET6) { fprintf(stderr, "Received unexpected packet in family %d.\n", sin6.sin6_family); nap(100); continue; } i = find_interface(sin6.sin6_scope_id); if(i < 0) { fprintf(stderr, "Received packet on unknown interface %d.\n", sin6.sin6_scope_id); nap(100); continue; } handle_packet(sock, buf, rc, &interfaces[i], &sin6.sin6_addr); } gettime(&now); if(selected_nexthop_metric < INFINITY) { int n = find_neighbour(selected_interface, &selected_nexthop, 0); assert(n >= 0); if(neighbour_expired(n, &now)) { /* Expire neighbour. */ flush_default_route(); delete_neighbour(n); } else if(timeval_compare(&now, &selected_nexthop_timeout) > 0) { /* Expire route. */ flush_default_route(); } /* Send a request? */ } /* Is it time to send hellos? */ if(timeval_minus_msec(&now, &last_hello) > hello_interval * 700) { for(i = 0; i < numinterfaces; i++) send_hello(sock, &interfaces[i]); last_hello = now; hello_count++; /* Make an expiry pass every ten hellos. */ if(hello_count >= 10) { expire_neighbours(); hello_count = 0; } } /* Is it time to send an update? */ if(timeval_minus_msec(&now, &last_update) > update_interval * 700) { for(i = 0; i < numinterfaces; i++) send_update(sock, &interfaces[i], 0); last_update = now; } } /* Send a bunch of retractions. */ for(i = 0; i < numinterfaces; i++) send_update(sock, &interfaces[i], 1); flush_default_route(); return 0; usage: fprintf(stderr, "Usage: sbabeld " "[-p prefix] [-u interval] [-h interval] [-c cost] interface...\n"); return 1; }