void remove_modules(void)
{
system("/sbin/rmmod kaodv &>/dev/null");
system("/sbin/rmmod ip_queue &>/dev/null");
}
void host_init(char *ifname)
{
struct sockaddr_in *ina;
char buf[1024], tmp_ifname[IFNAMSIZ],
ifnames[(IFNAMSIZ + 1) * MAX_NR_INTERFACES], *iface;
struct ifconf ifc;
struct ifreq ifreq, *ifr;
int i, iw_sock, if_sock = 0;
memset(&this_host, 0, sizeof(struct host_info));
memset(dev_indices, 0, sizeof(unsigned int) * MAX_NR_INTERFACES);
/* Intitialize the local sequence number an rreq_id to zero */
this_host.seqno = 1;
this_host.rreq_id = 0;
/* load the seqno from file if present */
load_seqno();
if (!ifname) {
/* No interface was given... search for first wireless. */
iw_sock = socket(PF_INET, SOCK_DGRAM, 0);
ifc.ifc_len = sizeof(buf);
ifc.ifc_buf = buf;
if (ioctl(iw_sock, SIOCGIFCONF, &ifc) < 0) {
fprintf(stderr, "Could not get wireless info\n");
exit(-1);
}
ifr = ifc.ifc_req;
for (i = ifc.ifc_len / sizeof(struct ifreq); i >= 0; i--, ifr++) {
struct iwreq req;
strcpy(req.ifr_name, ifr->ifr_name);
if (ioctl(iw_sock, SIOCGIWNAME, &req) >= 0) {
strcpy(tmp_ifname, ifr->ifr_name);
break;
}
}
/* Did we find a wireless interface? */
if (!strlen(tmp_ifname)) {
fprintf(stderr, "\nCould not find a wireless interface!\n");
fprintf(stderr, "Use -i <interface> to override...\n\n");
exit(-1);
}
strcpy(ifreq.ifr_name, tmp_ifname);
if (ioctl(iw_sock, SIOCGIFINDEX, &ifreq) < 0) {
alog(LOG_ERR, errno, __FUNCTION__,
"Could not get index of %s", tmp_ifname);
close(if_sock);
exit(-1);
}
close(iw_sock);
ifname = tmp_ifname;
alog(LOG_NOTICE, 0, __FUNCTION__,
"Attaching to %s, override with -i <if1,if2,...>.", tmp_ifname);
}
strcpy(ifnames, ifname);
/* Zero interfaces enabled so far... */
this_host.nif = 0;
gettimeofday(&this_host.bcast_time, NULL);
/* Find the indices of all interfaces to broadcast on... */
if_sock = socket(AF_INET, SOCK_DGRAM, 0);
iface = strtok(ifname, ",");
/* OK, now lookup interface information, and store it... */
do {
strcpy(ifreq.ifr_name, iface);
if (ioctl(if_sock, SIOCGIFINDEX, &ifreq) < 0) {
alog(LOG_ERR, errno, __FUNCTION__, "Could not get index of %s",
iface);
close(if_sock);
exit(-1);
}
this_host.devs[this_host.nif].ifindex = ifreq.ifr_ifindex;
dev_indices[this_host.nif++] = ifreq.ifr_ifindex;
strcpy(DEV_IFINDEX(ifreq.ifr_ifindex).ifname, iface);
/* Get IP-address of interface... */
ina = get_if_info(iface, SIOCGIFADDR);
if (ina == NULL)
exit(-1);
DEV_IFINDEX(ifreq.ifr_ifindex).ipaddr = ina->sin_addr;
/* Get netmask of interface... */
ina = get_if_info(iface, SIOCGIFNETMASK);
if (ina == NULL)
exit(-1);
DEV_IFINDEX(ifreq.ifr_ifindex).netmask = ina->sin_addr;
ina = get_if_info(iface, SIOCGIFBRDADDR);
if (ina == NULL)
exit(-1);
DEV_IFINDEX(ifreq.ifr_ifindex).broadcast = ina->sin_addr;
DEV_IFINDEX(ifreq.ifr_ifindex).enabled = 1;
if (this_host.nif >= MAX_NR_INTERFACES)
break;
} while ((iface = strtok(NULL, ",")));
close(if_sock);
/* Load kernel modules */
load_modules(ifnames);
/* Enable IP forwarding and set other kernel options... */
if (set_kernel_options() < 0) {
fprintf(stderr, "Could not set kernel options!\n");
exit(-1);
}
}
static void load_seqno() {
FILE *seqno_fd;
char buffer[15];
if ( (seqno_fd = fopen(SEQNO_FILE,"r")) == NULL ) {
alog(LOG_INFO,0,__FUNCTION__,
"unable to open file: %s, setting seqno = 1",
SEQNO_FILE);
return;
}
if ( fgets(buffer,15,seqno_fd) == NULL) {
fprintf(stderr,"error reading file %s",SEQNO_FILE);
exit(-1);
}
this_host.seqno = atoi(buffer);
if (this_host.seqno == 0) {
alog(LOG_DEBUG,0,__FUNCTION__,"seqno=0 not allowed, using 1");
this_host.seqno = 1;
}
DEBUG(LOG_DEBUG,0,"Loaded sequence number %lu",this_host.seqno);
}
static void store_seqno() {
FILE *seqno_fd;
if ( (seqno_fd = fopen(SEQNO_FILE,"w")) == NULL ) {
alog(LOG_INFO,0,__FUNCTION__,
"unable to open file: %s",
SEQNO_FILE);
return;
}
if (this_host.seqno == 0) {
alog(LOG_DEBUG,0,__FUNCTION__,"seqno=0 not allowed, using 1");
this_host.seqno = 1;
}
fprintf(seqno_fd,"%u",this_host.seqno);
DEBUG(LOG_DEBUG,0,"Saved sequence number %lu",this_host.seqno);
}
/* This signal handler ensures clean exits */
void signal_handler(int type)
{
switch (type) {
case SIGSEGV:
alog(LOG_ERR, 0, __FUNCTION__, "SEGMENTATION FAULT!!!! Exiting!!! "
"To get a core dump, compile with DEBUG option.");
case SIGINT:
case SIGHUP:
case SIGTERM:
default:
exit(0);
}
}
int main(int argc, char **argv)
{
static char *ifname = NULL; /* Name of interface to attach to */
fd_set rfds, readers;
int n, nfds = 0, i;
int daemonize = 0;
struct timeval *timeout;
/* Remember the name of the executable... */
progname = strrchr(argv[0], '/');
if (progname)
progname++;
else
progname = argv[0];
/* Use debug output as default */
debug = 1;
/* init libgcrypt */
gcry_control (GCRYCTL_SET_THREAD_CBS,&gcry_threads_pthread);
gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
if (!gcry_check_version (GCRYPT_VERSION)) {
printf("libcrypt failed load\n");
exit(1);
}
/* Parse command line: */
while (1) {
int opt;
opt = getopt_long(argc, argv, "i:fjln:dghoq:r:m:s:uwxDLRSV", longopts, 0);
if (opt == EOF)
break;
switch (opt) {
case 0:
break;
case 'd':
debug = 0;
daemonize = 1;
break;
case 'f':
llfeedback = 1;
active_route_timeout = ACTIVE_ROUTE_TIMEOUT_LLF;
break;
case 'g':
rreq_gratuitous = !rreq_gratuitous;
break;
case 'i':
ifname = optarg;
break;
case 'j':
hello_jittering = !hello_jittering;
break;
case 'l':
log_to_file = !log_to_file;
break;
case 'n':
if (optarg && isdigit(*optarg)) {
receive_n_hellos = atoi(optarg);
if (receive_n_hellos < 2) {
fprintf(stderr, "-n should be at least 2!\n");
exit(-1);
}
}
break;
case 'o':
optimized_hellos = !optimized_hellos;
break;
case 'q':
if (optarg && isdigit(*optarg))
hello_qual_threshold = atoi(optarg);
break;
case 'r':
if (optarg && isdigit(*optarg))
rt_log_interval = atof(optarg) * 1000;
break;
case 'u':
unidir_hack = !unidir_hack;
fprintf(stderr, "unidir hack unsupported!\n");
exit(-1);
break;
case 'w':
internet_gw_mode = !internet_gw_mode;
fprintf(stderr, "internet gw mode unsupported!\n");
exit(-1);
break;
case 'x':
expanding_ring_search = !expanding_ring_search;
break;
case 'L':
local_repair = !local_repair;
break;
case 'D':
wait_on_reboot = !wait_on_reboot;
break;
case 'S':
double_sign = !double_sign;
break;
case 'R':
ratelimit = !ratelimit;
break;
case 'm':
my_hash_function = gcry_to_hash(gcry_md_map_name(optarg));
if (my_hash_function <= 0) {
fprintf(stderr, "message digest alg not supported\n");
exit(-1);
}
break;
case 's':
my_hash_function_sign = gcry_to_hash_f(gcry_md_map_name(optarg));
if (my_hash_function_sign <= 0) {
fprintf(stderr, "message digest alg not supported\n");
exit(-1);
}
break;
case 'V':
printf
("\nSAODV v%s, %s based on AODV-UU %s\n"
"© CEFRIEL. © Uppsala University & Ericsson AB.\n"
"Author: Francesco Dolcini, <francesco.dolcini@students.cefriel.it>\n"
"Author: Erik Nordström, <erik.nordstrom@it.uu.se>\n\n",
SAODV_VERSION, SAODV_DRAFT_VERSION, AODV_UU_VERSION);
exit(0);
break;
case '?':
case ':':
exit(0);
default:
usage(0);
}
}
/* Check that we are running as root */
if (geteuid() != 0) {
fprintf(stderr, "must be root\n");
exit(1);
}
/* Detach from terminal */
if (daemonize) {
if (fork() != 0)
exit(0);
/* Close stdin, stdout and stderr... */
/* close(0); */
close(1);
close(2);
setsid();
}
/* Make sure we cleanup at exit... */
atexit((void *) &cleanup);
/* Initialize data structures and services... */
rt_table_init();
log_init();
packet_queue_init();
host_init(ifname);
packet_input_init();
aodv_socket_init();
aodv_ver_pipe_init();
key_init();
crypto_init();
saodv_adapt_init();
#ifdef LLFEEDBACK
if (llfeedback) {
llf_init();
}
#endif
/* Catch SIGHUP, SIGINT and SIGTERM type signals */
signal(SIGHUP, signal_handler);
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
/* Only capture segmentation faults when we are not debugging... */
#ifndef DEBUG
signal(SIGSEGV, signal_handler);
#endif
/* Set sockets to watch... */
FD_ZERO(&readers);
for (i = 0; i < nr_callbacks; i++) {
FD_SET(callbacks[i].fd, &readers);
if (callbacks[i].fd >= nfds)
nfds = callbacks[i].fd + 1;
}
/* Set the wait on reboot timer... */
if (wait_on_reboot) {
timer_init(&worb_timer, wait_on_reboot_timeout, &wait_on_reboot);
timer_set_timeout(&worb_timer, DELETE_PERIOD);
alog(LOG_NOTICE, 0, __FUNCTION__,
"In wait on reboot for %d milliseconds. Disable with \"-D\".",
DELETE_PERIOD);
}
/* Schedule the first Hello */
if (!optimized_hellos && !llfeedback)
hello_start();
if (rt_log_interval)
log_rt_table_init();
while (1) {
memcpy((char *) &rfds, (char *) &readers, sizeof(rfds));
timeout = timer_age_queue();
if ((n = select(nfds, &rfds, NULL, NULL, timeout)) < 0) {
if (errno != EINTR)
alog(LOG_WARNING, errno, __FUNCTION__,
"Failed select (main loop)");
continue;
}
if (n > 0) {
for (i = 0; i < nr_callbacks; i++) {
if (FD_ISSET(callbacks[i].fd, &rfds)) {
/* We don't want any timer SIGALRM's while executing the
callback functions, therefore we block the timer... */
(*callbacks[i].func) (callbacks[i].fd);
}
}
}
} /* Main loop */
return 0;
}
static void cleanup(void)
{
DEBUG(LOG_DEBUG, 0, "CLEANING UP!");
store_seqno();
remove_modules();
rt_table_destroy();
packet_input_cleanup();
packet_queue_destroy();
aodv_socket_cleanup();
key_cleanup();
crypto_cleanup();
saodv_adapt_cleanup();
#ifdef LLFEEDBACK
if (llfeedback)
llf_cleanup();
#endif
log_cleanup();
}