int NS_CLASS locality(struct in_addr dest, unsigned int ifindex) { #ifndef NS_PORT if (gw_prefix) { if ((dest.s_addr & DEV_IFINDEX(ifindex).netmask.s_addr) == (DEV_IFINDEX(ifindex).ipaddr.s_addr & DEV_IFINDEX(ifindex). netmask.s_addr)) return HOST_ADHOC; else return HOST_INET; } else { struct hostent *hent; hent = gethostbyaddr(&dest, sizeof(struct in_addr), AF_INET); if (!hent) { switch (h_errno) { case HOST_NOT_FOUND: DEBUG(LOG_DEBUG, 0, "RREQ for Non-Internet dest %s", ip_to_str(dest)); return HOST_UNKNOWN; default: DEBUG(LOG_DEBUG, 0, "Unknown DNS error"); break; } } else return HOST_INET; } #else char *dstnet = Address::instance().get_subnetaddr(dest.s_addr); char *subnet = Address::instance().get_subnetaddr(DEV_NR(NS_DEV_NR).ipaddr.s_addr); DEBUG(LOG_DEBUG, 0, "myaddr=%d, dest=%d dstnet=%s subnet=%s", DEV_NR(NS_DEV_NR).ipaddr.s_addr, dest.s_addr, dstnet, subnet); if (subnet != NULL) { if (dstnet != NULL) { if (strcmp(dstnet, subnet) != 0) { delete[]dstnet; return HOST_INET; } delete[]dstnet; } delete[]subnet; } assert(dstnet == NULL); return HOST_UNKNOWN; #endif return HOST_UNKNOWN; }
void NS_CLASS local_repair_timeout(void *arg) { rt_table_t *rt; struct in_addr rerr_dest; RERR *rerr = NULL; rt = (rt_table_t *) arg; if (!rt) return; rerr_dest.s_addr = AODV_BROADCAST; /* Default destination */ /* Unset the REPAIR flag */ rt->flags &= ~RT_REPAIR; #ifndef NS_PORT nl_send_del_route_msg(rt->dest_addr, rt->next_hop, rt->hcnt); #endif /* Route should already be invalidated. */ if (rt->nprec) { rerr = rerr_create(0, rt->dest_addr, rt->dest_seqno); if (rt->nprec == 1) { rerr_dest = FIRST_PREC(rt->precursors)->neighbor; aodv_socket_send((AODV_msg *) rerr, rerr_dest, RERR_CALC_SIZE(rerr), 1, &DEV_IFINDEX(rt->ifindex)); } else { int i; for (i = 0; i < MAX_NR_INTERFACES; i++) { if (!DEV_NR(i).enabled) continue; aodv_socket_send((AODV_msg *) rerr, rerr_dest, RERR_CALC_SIZE(rerr), 1, &DEV_NR(i)); } } DEBUG(LOG_DEBUG, 0, "Sending RERR about %s to %s", ip_to_str(rt->dest_addr), ip_to_str(rerr_dest)); } precursor_list_destroy(rt); /* Purge any packets that may be queued */ /* packet_queue_set_verdict(rt->dest_addr, PQ_DROP); */ rt->rt_timer.handler = &NS_CLASS route_delete_timeout; timer_set_timeout(&rt->rt_timer, DELETE_PERIOD); DEBUG(LOG_DEBUG, 0, "%s removed in %u msecs", ip_to_str(rt->dest_addr), DELETE_PERIOD); }
void NS_CLASS rrep_send(RREP * rrep, rt_table_t * rev_rt, rt_table_t * fwd_rt, int size) { u_int8_t rrep_flags = 0; struct in_addr dest; if (!rev_rt) { DEBUG(LOG_WARNING, 0, "Can't send RREP, rev_rt = NULL!"); return; } dest.s_addr = rrep->dest_addr; /* Check if we should request a RREP-ACK */ if ((rev_rt->state == VALID && rev_rt->flags & RT_UNIDIR) || (rev_rt->hcnt == 1 && unidir_hack)) { rt_table_t *neighbor = rt_table_find(rev_rt->next_hop); if (neighbor && neighbor->state == VALID && !neighbor->ack_timer.used) { /* If the node we received a RREQ for is a neighbor we are probably facing a unidirectional link... Better request a RREP-ack */ rrep_flags |= RREP_ACK; neighbor->flags |= RT_UNIDIR; /* Must remove any pending hello timeouts when we set the RT_UNIDIR flag, else the route may expire after we begin to ignore hellos... */ timer_remove(&neighbor->hello_timer); neighbor_link_break(neighbor); DEBUG(LOG_DEBUG, 0, "Link to %s is unidirectional!", ip_to_str(neighbor->dest_addr)); timer_set_timeout(&neighbor->ack_timer, NEXT_HOP_WAIT); } } DEBUG(LOG_DEBUG, 0, "Sending RREP to next hop %s about %s->%s", ip_to_str(rev_rt->next_hop), ip_to_str(rev_rt->dest_addr), ip_to_str(dest)); aodv_socket_send((AODV_msg *) rrep, rev_rt->next_hop, size, MAXTTL, &DEV_IFINDEX(rev_rt->ifindex)); /* Update precursor lists */ if (fwd_rt) { precursor_add(fwd_rt, rev_rt->next_hop); precursor_add(rev_rt, fwd_rt->next_hop); } if (!llfeedback && optimized_hellos) hello_start(); }
void NS_CLASS rrep_forward(RREP * rrep, int size, rt_table_t * rev_rt, rt_table_t * fwd_rt, int ttl) { /* Sanity checks... */ if (!fwd_rt || !rev_rt) { DEBUG(LOG_WARNING, 0, "Could not forward RREP because of NULL route!"); return; } if (!rrep) { DEBUG(LOG_WARNING, 0, "No RREP to forward!"); return; } DEBUG(LOG_DEBUG, 0, "Forwarding RREP to %s", ip_to_str(rev_rt->next_hop)); /* Here we should do a check if we should request a RREP_ACK, i.e we suspect a unidirectional link.. But how? */ if (0) { rt_table_t *neighbor; /* If the source of the RREP is not a neighbor we must find the neighbor (link) entry which is the next hop towards the RREP source... */ if (rev_rt->dest_addr.s_addr != rev_rt->next_hop.s_addr) neighbor = rt_table_find(rev_rt->next_hop); else neighbor = rev_rt; if (neighbor && !neighbor->ack_timer.used) { /* If the node we received a RREQ for is a neighbor we are probably facing a unidirectional link... Better request a RREP-ack */ rrep->a = 1; neighbor->flags |= RT_UNIDIR; timer_set_timeout(&neighbor->ack_timer, NEXT_HOP_WAIT); } } rrep = (RREP *) aodv_socket_queue_msg((AODV_msg *) rrep, size); rrep->hcnt = fwd_rt->hcnt; /* Update the hopcount */ aodv_socket_send((AODV_msg *) rrep, rev_rt->next_hop, size, ttl, &DEV_IFINDEX(rev_rt->ifindex)); precursor_add(fwd_rt, rev_rt->next_hop); precursor_add(rev_rt, fwd_rt->next_hop); rt_table_update_timeout(rev_rt, ACTIVE_ROUTE_TIMEOUT); }
void NS_CLASS local_repair_timeout(void *arg) { rt_table_t *rt; u_int32_t rerr_dest = AODV_BROADCAST; RERR *rerr = NULL; rt = (rt_table_t *) arg; if (!rt) return; /* Unset the REPAIR flag */ rt->flags &= ~RT_REPAIR; rt->rt_timer.handler = &NS_CLASS route_delete_timeout; timer_set_timeout(&rt->rt_timer, DELETE_PERIOD); DEBUG(LOG_DEBUG, 0, "%s removed in %u msecs", ip_to_str(rt->dest_addr), DELETE_PERIOD); /* Route should already be invalidated. */ if (rt->nprec) { rerr = rerr_create(0, rt->dest_addr, rt->dest_seqno); if (rt->nprec == 1) { rerr_dest = FIRST_PREC(rt->precursors)->neighbor; aodv_socket_send((AODV_msg *) rerr, rerr_dest, RERR_CALC_SIZE(rerr), 1, &DEV_IFINDEX(rt->ifindex)); } else { int i; for (i = 0; i < MAX_NR_INTERFACES; i++) { if (!DEV_NR(i).enabled) continue; aodv_socket_send((AODV_msg *) rerr, rerr_dest, RERR_CALC_SIZE(rerr), 1, &DEV_NR(i)); } } DEBUG(LOG_DEBUG, 0, "Sending RERR about %s to %s", ip_to_str(rt->dest_addr), ip_to_str(rerr_dest)); } precursor_list_destroy(rt); }
static void packet_input(int fd) #endif { rt_table_t *fwd_rt, *rev_rt, *next_hop_rt = NULL; struct in_addr dest_addr, src_addr; u_int8_t rreq_flags = 0; unsigned int ifindex; struct ip_data *ipd = NULL; int pkt_flags = 0; #ifdef NS_PORT ifindex = NS_IFINDEX; /* Always use ns interface */ fwd_rt = NULL; /* For broadcast we provide no next hop */ ipd = NULL; /* No ICMP messaging */ struct hdr_cmn *ch = HDR_CMN(p); struct hdr_ip *ih = HDR_IP(p); src_addr.s_addr = ih->saddr(); dest_addr.s_addr = ih->daddr(); /* If this is a TCP packet and we don't have a route, we should set the gratuituos flag in the RREQ. */ if (ch->ptype() == PT_TCP) { rreq_flags |= RREQ_GRATUITOUS; } #else int status; char buf[sizeof(struct nlmsghdr)+sizeof(ipq_packet_msg_t)+BUFSIZE]; char *dev_name; ipq_packet_msg_t *pkt; struct iphdr *ip; struct udphdr *udp; struct icmphdr *icmp = NULL; status = ipq_read(h, buf, sizeof(buf), -1); if (status < 0) { DEBUG(LOG_DEBUG, 0, "%s", ipq_errstr()); ipq_perror(NULL); return; } if (ipq_message_type(buf) == NLMSG_ERROR) { fprintf(stderr, "ERROR packet_input: Check that the ip_queue.o module is loaded.\n"); die(h); } pkt = ipq_get_packet(buf); #ifdef DEBUG_PACKET DEBUG(LOG_DEBUG, 0, "Protocol %u indev=%s outdev=%s\n", pkt->hw_protocol, pkt->indev_name, pkt->outdev_name); #endif if (pkt->hook == 0) dev_name = pkt->indev_name; else if (pkt->hook == 3) dev_name = pkt->outdev_name; else dev_name = NULL; /* We know from kaodv.c that this is an IP packet */ ip = (struct iphdr *) pkt->payload; dest_addr.s_addr = ip->daddr; src_addr.s_addr = ip->saddr; switch (ip->protocol) { /* Don't process AODV control packets (UDP on port 654). They are accounted for on the aodv socket */ case IPPROTO_UDP: udp = (struct udphdr *) ((char *) ip + (ip->ihl << 2)); if (ntohs(udp->dest) == AODV_PORT || ntohs(udp->source) == AODV_PORT) goto accept; break; /* If this is a TCP packet and we don't have a route, we should set the gratuituos flag in the RREQ. */ case IPPROTO_TCP: rreq_flags |= RREQ_GRATUITOUS; break; /* We set the gratuitous flag also on ICMP ECHO requests, since the destination will also need a route back for the reply... */ case IPPROTO_ICMP: icmp = (struct icmphdr *) ((char *) ip + (ip->ihl << 2)); if (icmp->type == ICMP_ECHO) rreq_flags |= RREQ_GRATUITOUS; #ifdef DEBUG_PACKET DEBUG(LOG_INFO, 0, "setting G flag for RREQ to %s", ip_to_str(dest_addr)); #endif break; #ifdef CONFIG_GATEWAY case IPPROTO_MIPE: if (internet_gw_mode) { ip = ip_pkt_decapsulate(ip); if (ip == NULL) { DEBUG(LOG_ERR, 0, "Decapsulation failed..."); exit(-1); } pkt_flags |= PKT_DEC; } break; #endif /* CONFIG_GATEWAY */ } #ifdef DEBUG_PACKET DEBUG(LOG_INFO, 0, "pkt to %s", ip_to_str(dest_addr)); #endif if (dev_name) { ifindex = name2index(dev_name); if (ifindex < 0) { DEBUG(LOG_ERR, 0, "name2index error!"); return; } } else ifindex = 0; #endif /* NS_PORT */ /* If the packet is not interesting we just let it go through... */ if (dest_addr.s_addr == AODV_BROADCAST || dest_addr.s_addr == DEV_IFINDEX(ifindex).broadcast.s_addr) { #ifdef NS_PORT /* Limit Non AODV broadcast packets (Rolf Winter * <[email protected]). */ ih->ttl() = ih->ttl() - 1; if(ih->ttl() < 1) Packet::free(p); else sendPacket(p, dest_addr, 0.0); return; #else goto accept; #endif } /* Find the entry of the neighboring node and the destination (if any). */ rev_rt = rt_table_find(src_addr); fwd_rt = rt_table_find(dest_addr); #ifdef CONFIG_GATEWAY /* Check if we have a route and it is an Internet destination (Should be * encapsulated and routed through the gateway). */ if (fwd_rt && (fwd_rt->state == VALID) && (fwd_rt->flags & RT_INET_DEST)) { /* The destination should be relayed through the IG */ rt_table_update_timeout(fwd_rt, ACTIVE_ROUTE_TIMEOUT); #ifdef NS_PORT p = pkt_encapsulate(p, fwd_rt->next_hop); if (p == NULL) { DEBUG(LOG_ERR, 0, "IP Encapsulation failed!"); return; } /* Update pointers to headers */ ch = HDR_CMN(p); ih = HDR_IP(p); #else ip = ip_pkt_encapsulate(ip, fwd_rt->next_hop, BUFSIZE); if (ip == NULL) { DEBUG(LOG_ERR, 0, "Minimal IP Encapsulation failed!"); exit(-1); } #endif dest_addr = fwd_rt->next_hop; fwd_rt = rt_table_find(dest_addr); pkt_flags |= PKT_ENC; } #endif /* CONFIG_GATEWAY */ /* UPDATE TIMERS on active forward and reverse routes... */ /* When forwarding a packet, we update the lifetime of the destination's routing table entry, as well as the entry for the next hop neighbor (if not the same). AODV draft 10, section 6.2. */ if (fwd_rt && fwd_rt->state == VALID && dest_addr.s_addr != DEV_IFINDEX(ifindex).ipaddr.s_addr) { rt_table_update_timeout(fwd_rt, ACTIVE_ROUTE_TIMEOUT); next_hop_rt = rt_table_find(fwd_rt->next_hop); if (next_hop_rt && next_hop_rt->state == VALID && next_hop_rt->dest_addr.s_addr != fwd_rt->dest_addr.s_addr) rt_table_update_timeout(next_hop_rt, ACTIVE_ROUTE_TIMEOUT); } /* Also update the reverse route and reverse next hop along the path back, since routes between originators and the destination are expected to be symmetric. */ if (rev_rt && rev_rt->state == VALID) { rt_table_update_timeout(rev_rt, ACTIVE_ROUTE_TIMEOUT); next_hop_rt = rt_table_find(rev_rt->next_hop); if (next_hop_rt && next_hop_rt->state == VALID && rev_rt && next_hop_rt->dest_addr.s_addr != rev_rt->dest_addr.s_addr) rt_table_update_timeout(next_hop_rt, ACTIVE_ROUTE_TIMEOUT); /* Update HELLO timer of next hop neighbor if active */ if (!llfeedback && next_hop_rt->hello_timer.used) { struct timeval now; gettimeofday(&now, NULL); hello_update_timeout(next_hop_rt, &now, ALLOWED_HELLO_LOSS * HELLO_INTERVAL); } } /* OK, the timeouts have been updated. Now see if either: 1. The packet is for this node -> ACCEPT. 2. The packet is not for this node -> Send RERR (someone want's this node to forward packets although there is no route) or Send RREQ. */ /* If the packet is destined for this node, then just accept it. */ if (memcmp(&dest_addr, &DEV_IFINDEX(ifindex).ipaddr, sizeof(struct in_addr)) == 0) { #ifdef NS_PORT ch->size() -= IP_HDR_LEN; // cut off IP header size 4/7/99 -dam target_->recv(p, (Handler*)0); p = 0; return; #else goto accept; #endif } if (!fwd_rt || fwd_rt->state == INVALID || (fwd_rt->hcnt == 1 && (fwd_rt->flags & RT_UNIDIR))) { /* Check if the route is marked for repair or is INVALID. In * that case, do a route discovery. */ if (fwd_rt && (fwd_rt->flags & RT_REPAIR)) goto route_discovery; /* If a packet is received on the NF_IP_PRE_ROUTING hook, i.e. inbound on the interface and we don't have a route to the destination, we should send an RERR to the source and then drop the package... */ /* NF_IP_PRE_ROUTING = 0 */ #ifdef NS_PORT #define PACKET_IS_INBOUND ch->direction() == hdr_cmn::UP #else #define PACKET_IS_INBOUND pkt->hook == 0 #endif if (PACKET_IS_INBOUND) { struct in_addr rerr_dest; RERR *rerr; #ifdef NS_PORT struct in_addr nh; nh.s_addr = ch->prev_hop_; DEBUG(LOG_DEBUG, 0, "No route, src=%s dest=%s prev_hop=%s - DROPPING!", ip_to_str(src_addr), ip_to_str(dest_addr), ip_to_str(nh)); #endif if (fwd_rt) { rerr = rerr_create(0, fwd_rt->dest_addr, fwd_rt->dest_seqno); rt_table_update_timeout(fwd_rt, DELETE_PERIOD); } else rerr = rerr_create(0, dest_addr, 0); DEBUG(LOG_DEBUG, 0, "Sending RERR to prev hop %s for unknown dest %s", ip_to_str(src_addr), ip_to_str(dest_addr)); /* Unicast the RERR to the source of the data transmission * if possible, otherwise we broadcast it. */ if (rev_rt && rev_rt->state == VALID) rerr_dest = rev_rt->next_hop; else rerr_dest.s_addr = AODV_BROADCAST; aodv_socket_send((AODV_msg *) rerr, rerr_dest, RERR_CALC_SIZE(rerr), 1, &DEV_IFINDEX(ifindex)); if (wait_on_reboot) { DEBUG(LOG_DEBUG, 0, "Wait on reboot timer reset."); timer_set_timeout(&worb_timer, DELETE_PERIOD); } #ifdef NS_PORT /* DEBUG(LOG_DEBUG, 0, "Dropping pkt uid=%d", ch->uid()); */ drop(p, DROP_RTR_NO_ROUTE); #else status = ipq_set_verdict(h, pkt->packet_id, NF_DROP, 0, NULL); if (status < 0) die(h); #endif return; } route_discovery: /* Buffer packets... Packets are queued by the ip_queue.o module already. We only need to save the handle id, and return the proper verdict when we know what to do... */ #ifdef NS_PORT packet_queue_add(p, dest_addr); #else packet_queue_add(pkt->packet_id, dest_addr, ip); #ifdef CONFIG_GATEWAY /* In gateway mode we handle packets in userspace */ ipq_set_verdict(h, pkt->packet_id, NF_DROP, 0, NULL); #endif /* Already seeking the destination? Then do not allocate any memory or generate a RREQ. */ if (seek_list_find(dest_addr)) return; /* If the request is generated locally by an application, we save the IP header + 64 bits of data for sending an ICMP Destination Host Unreachable in case we don't find a route... */ if (src_addr.s_addr == DEV_IFINDEX(ifindex).ipaddr.s_addr && ip && pkt->data_len >= (ip->ihl << 2) + 8) { ipd = (struct ip_data *) malloc(sizeof(struct ip_data)); if (ipd == NULL) { perror("Malloc for IP data failed!"); exit(-1); } /* IP header + 64 bits data (8 bytes) */ ipd->len = (ip->ihl << 2) + 8; memcpy(ipd->data, ip, ipd->len); } else ipd = NULL; #endif if (fwd_rt && (fwd_rt->flags & RT_REPAIR)) rreq_local_repair(fwd_rt, src_addr, ipd); else rreq_route_discovery(dest_addr, rreq_flags, ipd); return; } else { #ifdef NS_PORT /* DEBUG(LOG_DEBUG, 0, "Sending pkt uid=%d", ch->uid()); */ sendPacket(p, fwd_rt->next_hop, 0.0); #else accept: if (pkt_flags & PKT_ENC || (pkt_flags & PKT_DEC)) status = ipq_set_verdict(h, pkt->packet_id, NF_ACCEPT, ntohs(ip->tot_len), (unsigned char *)ip); else status = ipq_set_verdict(h, pkt->packet_id, NF_ACCEPT, 0, NULL); if (status < 0) die(h); #endif /* When forwarding data, make sure we are sending HELLO messages */ gettimeofday(&this_host.fwd_time, NULL); if (!llfeedback && optimized_hellos) hello_start(); } }
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); 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); /* Intitialize the local sequence number an rreq_id to zero */ this_host.seqno = 1; this_host.rreq_id = 0; /* 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); } }
void rrep_process(RREP * rrep, int rreplen, u_int32_t ip_src, u_int32_t ip_dst, int ip_ttl, unsigned int ifindex) { u_int32_t rrep_dest, rrep_orig, rrep_lifetime, rrep_seqno; rt_table_t *fwd_rt, *rev_rt; /* Convert to correct byte order on affeected fields: */ rrep_dest = ntohl(rrep->dest_addr); rrep_orig = ntohl(rrep->orig_addr); rrep_seqno = ntohl(rrep->dest_seqno); rrep_lifetime = ntohl(rrep->lifetime); if (rreplen < RREP_SIZE) { log(LOG_WARNING, 0, "rrep_process: IP data field too short (%u bytes)" " from %s to %s", rreplen, ip_to_str(ip_src), ip_to_str(ip_dst)); return; } /* Ignore messages which aim to a create a route to one self */ if (memcmp(&rrep_dest, &DEV_IFINDEX(ifindex).ipaddr, sizeof(u_int32_t)) == 0 && memcmp(&rrep_orig, &DEV_IFINDEX(ifindex).ipaddr, sizeof(u_int32_t)) == 0) return; /* Check if this was a hello message... */ if (ip_ttl == 1) { if (memcmp(&ip_src, &DEV_IFINDEX(ifindex).ipaddr, sizeof(u_int32_t)) != 0) hello_process(rrep, rreplen, ifindex); return; } #ifdef DEBUG log(LOG_DEBUG, 0, "RREP_process: from=%s about %s->%s", ip_to_str(ip_src), ip_to_str(rrep_orig), ip_to_str(rrep_dest)); log_pkt_fields((AODV_msg *) rrep); #endif /* When a node receives a RREP, it first increments the hop count in the RREP, to account for the extra hop */ rrep->hcnt++; /* ---------- CHECK IF WE SHOULD MAKE A FORWARD ROUTE ------------ We update or insert a forward route only if: (i) the Destination Sequence Number in the RREP is greater than the node's copy of the destination sequence number, or (ii) the sequence numbers are the same, but the route is no longer active or the Hop Count in RREP is smaller than the hop count in route table entry. */ fwd_rt = rt_table_find(rrep_dest); if (fwd_rt == NULL) { /* We didn't have an existing entry, so we insert a new one. */ fwd_rt = rt_table_insert(rrep_dest, ip_src, rrep->hcnt, rrep_seqno, rrep_lifetime, FWD_ROUTE, ifindex); } else if ((rrep_seqno > fwd_rt->dest_seqno) || (((rrep_seqno == fwd_rt->dest_seqno) && IS_INFTY(fwd_rt->hcnt)) || (fwd_rt->flags & UNIDIR) || (rrep->hcnt < fwd_rt->hcnt))) { fwd_rt = rt_table_update(fwd_rt, ip_src, rrep->hcnt, rrep_seqno, rrep_lifetime, FWD_ROUTE); } else return; /* Check if this RREP was for us (i.e. we previously made a RREQ for this host). */ if (memcmp(&rrep_orig, &DEV_IFINDEX(ifindex).ipaddr, sizeof(u_int32_t)) == 0) { /* Remove destination from seeking list since a route has been found. */ if (seek_list_remove(rrep_dest)) packet_buff_send(rrep_dest); /* If the RREP_ACK flag is set we must send a RREP acknowledgement to the destination that replied... */ if (rrep->a) { RREP_ack *rrep_ack; rrep_ack = rrep_ack_create(); aodv_socket_send((AODV_msg *) rrep_ack, fwd_rt->next_hop, NEXT_HOP_WAIT, MAXTTL, &DEV_IFINDEX(fwd_rt->ifindex)); /* Remove RREP_ACK flag... */ rrep->a = 0; } } else { /* --- Here we FORWARD the RREP on the REVERSE route --- */ /* If the current node is not the source node as indicated by the Source IP Address in the RREP message AND a forward route has been created or updated as described before, the node consults its route table entry for the source node to determine the next hop for the RREP packet, and then forwards the RREP towards the source with its Hop Count incremented by one. */ if ((rev_rt = rt_table_find_active(rrep_orig)) != NULL) { /* Here we should do a check if we should request a RREP_ACK, i.e we suspect a unidirectional link.. But how? */ if (0) { rt_table_t *neighbor; /* If the source of the RREP is not a neighbor we must find the neighbor (link) entry which is the next hop towards the RREP source... */ if (rev_rt->dest_addr != rev_rt->next_hop) neighbor = rt_table_find(rev_rt->next_hop); else neighbor = rev_rt; if (neighbor != NULL && !neighbor->ack_timer.used) { /* If the node we received a RREQ for is a neighbor we are probably facing a unidirectional link... Better request a RREP-ack */ rrep->a = 1; neighbor->flags |= UNIDIR; timer_add_msec(&neighbor->ack_timer, NEXT_HOP_WAIT); } } rrep = (RREP *) aodv_socket_queue_msg((AODV_msg *) rrep, rreplen); aodv_socket_send((AODV_msg *) rrep, rev_rt->next_hop, RREP_SIZE, --ip_ttl, &DEV_IFINDEX(rev_rt->ifindex)); /* The neighboring nodes to which a RREP was forwarded should be added as a precursor node. */ if (fwd_rt != NULL) precursor_add(fwd_rt, rev_rt->next_hop); /* At each node the (reverse) route used to forward the RREP has its lifetime changed to current time plus ACTIVE_ROUTE_TIMEOUT. */ rt_table_update_timeout(rev_rt, ACTIVE_ROUTE_TIMEOUT); } } }
static void packet_input(int fd) #endif { rt_table_t *fwd_rt, *rev_rt, *repair_rt, *next_hop_rt; u_int32_t dest_addr, src_addr; u_int8_t rreq_flags = 0; unsigned int ifindex; struct ip_data *ipd = NULL; #ifdef NS_PORT ifindex = NS_IFINDEX; // Always use ns interface fwd_rt = NULL; // In case of broadcast we provide no next hop ipd = NULL; // No ICMP messaging struct hdr_cmn *ch = HDR_CMN(p); struct hdr_ip *ih = HDR_IP(p); src_addr = ih->saddr(); dest_addr = ih->daddr(); /* Any packets with our IP address as destination arriving here are packets that weren't caught by any agent attached to the node. Throw away those. */ if (dest_addr == DEV_IFINDEX(ifindex).ipaddr) { DEBUG(LOG_WARNING, 0, "processPacket: Received orphan packet. Throwing it away."); Packet::free(p); return; } /* If this is a TCP packet and we don't have a route, we should set the gratuituos flag in the RREQ. */ if (ch->ptype() == PT_TCP) { rreq_flags |= RREQ_GRATUITOUS; } #else int status; char buf[BUFSIZE], *dev_name; ipq_packet_msg_t *pkt; struct iphdr *ip; struct udphdr *udp; struct icmphdr *icmp = NULL; ipq_read(h, buf, BUFSIZE, 0); status = ipq_message_type(buf); if (status == NLMSG_ERROR) { fprintf(stderr, "ERROR packet_input: Check that the ip_queue.o module is loaded.\n"); die(h); } pkt = ipq_get_packet(buf); #ifdef DEBUG_PACKET DEBUG(LOG_DEBUG, 0, "Protocol %u indev=%s outdev=%s\n", pkt->hw_protocol, pkt->indev_name, pkt->outdev_name); #endif if (pkt->hook == 0) dev_name = pkt->indev_name; else if (pkt->hook == 3) dev_name = pkt->outdev_name; else dev_name = NULL; /* We know from kaodv.c that this is an IP packet */ ip = (struct iphdr *) pkt->payload; dest_addr = ntohl(ip->daddr); src_addr = ntohl(ip->saddr); switch (ip->protocol) { /* Don't process AODV control packets (UDP on port 654). They are accounted for on the aodv socket */ case IPPROTO_UDP: udp = (struct udphdr *) ((char *) ip + (ip->ihl << 2)); if (ntohs(udp->dest) == AODV_PORT || ntohs(udp->source) == AODV_PORT) goto accept; break; /* If this is a TCP packet and we don't have a route, we should set the gratuituos flag in the RREQ. */ case IPPROTO_TCP: rreq_flags |= RREQ_GRATUITOUS; break; /* We set the gratuitous flag also on ICMP ECHO requests, since the destination will also need a route back for the reply... */ case IPPROTO_ICMP: icmp = (struct icmphdr *) ((char *) ip + (ip->ihl << 2)); if (icmp->type == ICMP_ECHO) rreq_flags |= RREQ_GRATUITOUS; #ifdef DEBUG_PACKET DEBUG(LOG_INFO, 0, "packet_input: setting G flag for RREQ to %s", ip_to_str(dest_addr)); #endif break; default: } #ifdef DEBUG_PACKET DEBUG(LOG_INFO, 0, "packet_input: pkt to %s", ip_to_str(dest_addr)); #endif if (dev_name) ifindex = if_nametoindex(dev_name); else ifindex = 0; #endif /* NS_PORT */ /* If the packet is not interesting we just let it go through... */ if ((dest_addr == AODV_BROADCAST) || (dest_addr == DEV_IFINDEX(ifindex).ipaddr) || (dest_addr == DEV_IFINDEX(ifindex).broadcast) || ((internet_gw_mode && this_host.gateway_mode) && ((dest_addr & DEV_IFINDEX(ifindex).netmask) != DEV_IFINDEX(ifindex).broadcast))) goto accept; /* Find the entry of the neighboring node and the destination (if any). */ rev_rt = rt_table_find_active(src_addr); fwd_rt = rt_table_find_active(dest_addr); /* If a packet is received on the NF_IP_PRE_ROUTING hook, i.e. inbound on the interface and we don't have a route to the destination, we should send an RERR to the source and then drop the package... */ /* NF_IP_PRE_ROUTING = 0 */ #ifdef NS_PORT #define PACKET_IS_INBOUND ch->direction() == hdr_cmn::UP #else #define PACKET_IS_INBOUND pkt->hook == 0 #endif if ((dest_addr != DEV_IFINDEX(ifindex).ipaddr) && (!fwd_rt && PACKET_IS_INBOUND)) { rt_table_t *rt_entry; u_int32_t rerr_dest; RERR *rerr; DEBUG(LOG_DEBUG, 0, "packet_input: Sending RERR for unknown dest %s", ip_to_str(dest_addr)); /* There is an expired entry in the routing table we want to send along the seqno in the RERR... */ rt_entry = rt_table_find(dest_addr); if (rt_entry) { rerr = rerr_create(0, rt_entry->dest_addr, rt_entry->dest_seqno); rt_table_update_timeout(rt_entry, DELETE_PERIOD); } else rerr = rerr_create(0, dest_addr, 0); /* Unicast the RERR to the source of the data transmission if * possible, otherwise we broadcast it. */ if (rev_rt) rerr_dest = rev_rt->next_hop; else rerr_dest = AODV_BROADCAST; aodv_socket_send((AODV_msg *) rerr, rerr_dest, RERR_CALC_SIZE(rerr), 1, &DEV_IFINDEX(ifindex)); if (wait_on_reboot) { DEBUG(LOG_DEBUG, 0, "packet_input: Wait on reboot timer reset."); timer_add_msec(&worb_timer, DELETE_PERIOD); } #ifdef NS_PORT drop(p, DROP_RTR_NO_ROUTE); #else status = ipq_set_verdict(h, pkt->packet_id, NF_DROP, 0, NULL); if (status < 0) die(h); #endif return; } /* Check if the route is currently in repair. In that case just buffer the packet */ repair_rt = rt_table_find(dest_addr); if (repair_rt && (repair_rt->flags & LREPAIR)) { #ifdef NS_PORT packet_queue_add(p, dest_addr); #else packet_queue_add(pkt->packet_id, dest_addr); #endif return; } /* update_timers: */ /* When forwarding a packet, we update the lifetime of the destination's routing table entry, as well as the entry for the next hop neighbor (if not the same). AODV draft 10, section 6.2. */ if (fwd_rt && dest_addr != DEV_IFINDEX(ifindex).ipaddr) { rt_table_update_timeout(fwd_rt, ACTIVE_ROUTE_TIMEOUT); next_hop_rt = rt_table_find_active(fwd_rt->next_hop); if (next_hop_rt && next_hop_rt->dest_addr != fwd_rt->dest_addr) rt_table_update_timeout(next_hop_rt, ACTIVE_ROUTE_TIMEOUT); } /* Also update the reverse route and reverse next hop along the path back, since routes between originators and the destination are expected to be symmetric. */ if (rev_rt) { rt_table_update_timeout(rev_rt, ACTIVE_ROUTE_TIMEOUT); next_hop_rt = rt_table_find_active(rev_rt->next_hop); if (next_hop_rt && next_hop_rt->dest_addr != fwd_rt->dest_addr) rt_table_update_timeout(next_hop_rt, ACTIVE_ROUTE_TIMEOUT); } #ifdef DEBUG_PACKET DEBUG(LOG_INFO, 0, "packet_input: d=%s s=%s", ip_to_str(dest_addr), ip_to_str(src_addr)); #endif /* DEBUG_PACKET */ if (!fwd_rt || (fwd_rt->hcnt == 1 && (fwd_rt->flags & UNIDIR))) { /* Buffer packets... Packets are queued by the ip_queue_aodv.o module already. We only need to save the handle id, and return the proper verdict when we know what to do... */ #ifdef NS_PORT packet_queue_add(p, dest_addr); #else packet_queue_add(pkt->packet_id, dest_addr); /* If the request is generated locally by an application, we save the IP header + 64 bits of data for sending an ICMP Destination Host Unreachable in case we don't find a route... */ if (src_addr == DEV_IFINDEX(ifindex).ipaddr) { ipd = (struct ip_data *) malloc(sizeof(struct ip_data)); if (ipd < 0) { perror("Malloc for IP data failed!"); exit(-1); } ipd->len = (ip->ihl << 2) + 8; /* IP header + 64 bits data (8 bytes) */ memcpy(ipd->data, ip, ipd->len); } else ipd = NULL; #endif rreq_route_discovery(dest_addr, rreq_flags, ipd); return; } accept: #ifdef NS_PORT if (fwd_rt) sendPacket(p, fwd_rt->next_hop, 0.0); else drop(p, DROP_RTR_NO_ROUTE); #else status = ipq_set_verdict(h, pkt->packet_id, NF_ACCEPT, 0, NULL); if (status < 0) die(h); #endif return; }
void NS_CLASS rrep_process(RREP * rrep, int rreplen, struct in_addr ip_src, struct in_addr ip_dst, int ip_ttl, unsigned int ifindex) { u_int32_t rrep_lifetime, rrep_seqno, rrep_new_hcnt; u_int8_t pre_repair_hcnt = 0, pre_repair_flags = 0; rt_table_t *fwd_rt, *rev_rt; AODV_ext *ext; unsigned int extlen = 0; int rt_flags = 0; struct in_addr rrep_dest, rrep_orig; #ifdef CONFIG_GATEWAY struct in_addr inet_dest_addr; int inet_rrep = 0; #endif /* Convert to correct byte order on affeected fields: */ rrep_dest.s_addr = rrep->dest_addr; rrep_orig.s_addr = rrep->orig_addr; rrep_seqno = ntohl(rrep->dest_seqno); rrep_lifetime = ntohl(rrep->lifetime); /* Increment RREP hop count to account for intermediate node... */ rrep_new_hcnt = rrep->hcnt + 1; if (rreplen < (int)RREP_SIZE) { alog(LOG_WARNING, 0, __FUNCTION__, "IP data field too short (%u bytes)" " from %s to %s", rreplen, ip_to_str(ip_src), ip_to_str(ip_dst)); return; } /* Ignore messages which aim to a create a route to one self */ if (rrep_dest.s_addr == DEV_IFINDEX(ifindex).ipaddr.s_addr) return; DEBUG(LOG_DEBUG, 0, "from %s about %s->%s", ip_to_str(ip_src), ip_to_str(rrep_orig), ip_to_str(rrep_dest)); #ifdef DEBUG_OUTPUT log_pkt_fields((AODV_msg *) rrep); #endif /* Determine whether there are any extensions */ ext = (AODV_ext *) ((char *)rrep + RREP_SIZE); while ((rreplen - extlen) > RREP_SIZE) { switch (ext->type) { case RREP_EXT: DEBUG(LOG_INFO, 0, "RREP include EXTENSION"); /* Do something here */ break; #ifdef CONFIG_GATEWAY case RREP_INET_DEST_EXT: if (ext->length == sizeof(u_int32_t)) { /* Destination address in RREP is the gateway address, while the * extension holds the real destination */ memcpy(&inet_dest_addr, AODV_EXT_DATA(ext), ext->length); DEBUG(LOG_DEBUG, 0, "RREP_INET_DEST_EXT: <%s>", ip_to_str(inet_dest_addr)); /* This was a RREP from a gateway */ rt_flags |= RT_GATEWAY; inet_rrep = 1; break; } #endif default: alog(LOG_WARNING, 0, __FUNCTION__, "Unknown or bad extension %d", ext->type); break; } extlen += AODV_EXT_SIZE(ext); ext = AODV_EXT_NEXT(ext); } /* ---------- CHECK IF WE SHOULD MAKE A FORWARD ROUTE ------------ */ fwd_rt = rt_table_find(rrep_dest); rev_rt = rt_table_find(rrep_orig); if (!fwd_rt) { /* We didn't have an existing entry, so we insert a new one. */ fwd_rt = rt_table_insert(rrep_dest, ip_src, rrep_new_hcnt, rrep_seqno, rrep_lifetime, VALID, rt_flags, ifindex); } else if (fwd_rt->dest_seqno == 0 || (int32_t) rrep_seqno > (int32_t) fwd_rt->dest_seqno || (rrep_seqno == fwd_rt->dest_seqno && (fwd_rt->state == INVALID || fwd_rt->flags & RT_UNIDIR || rrep_new_hcnt < fwd_rt->hcnt))) { pre_repair_hcnt = fwd_rt->hcnt; pre_repair_flags = fwd_rt->flags; fwd_rt = rt_table_update(fwd_rt, ip_src, rrep_new_hcnt, rrep_seqno, rrep_lifetime, VALID, rt_flags | fwd_rt->flags); } else { if (fwd_rt->hcnt > 1) { DEBUG(LOG_DEBUG, 0, "Dropping RREP, fwd_rt->hcnt=%d fwd_rt->seqno=%ld", fwd_rt->hcnt, fwd_rt->dest_seqno); } return; } /* If the RREP_ACK flag is set we must send a RREP acknowledgement to the destination that replied... */ if (rrep->a) { RREP_ack *rrep_ack; rrep_ack = rrep_ack_create(); aodv_socket_send((AODV_msg *) rrep_ack, fwd_rt->next_hop, NEXT_HOP_WAIT, MAXTTL, &DEV_IFINDEX(fwd_rt->ifindex)); /* Remove RREP_ACK flag... */ rrep->a = 0; } /* Check if this RREP was for us (i.e. we previously made a RREQ for this host). */ if (rrep_orig.s_addr == DEV_IFINDEX(ifindex).ipaddr.s_addr) { #ifdef CONFIG_GATEWAY if (inet_rrep) { rt_table_t *inet_rt; inet_rt = rt_table_find(inet_dest_addr); /* Add a "fake" route indicating that this is an Internet * destination, thus should be encapsulated and routed through a * gateway... */ if (!inet_rt) rt_table_insert(inet_dest_addr, rrep_dest, rrep_new_hcnt, 0, rrep_lifetime, VALID, RT_INET_DEST, ifindex); else if (inet_rt->state == INVALID || rrep_new_hcnt < inet_rt->hcnt) { rt_table_update(inet_rt, rrep_dest, rrep_new_hcnt, 0, rrep_lifetime, VALID, RT_INET_DEST | inet_rt->flags); } else { DEBUG(LOG_DEBUG, 0, "INET Response, but no update %s", ip_to_str(inet_dest_addr)); } } #endif /* CONFIG_GATEWAY */ /* If the route was previously in repair, a NO DELETE RERR should be sent to the source of the route, so that it may choose to reinitiate route discovery for the destination. Fixed a bug here that caused the repair flag to be unset and the RERR never being sent. Thanks to McWood <*****@*****.**> for discovering this. */ if (pre_repair_flags & RT_REPAIR) { if (fwd_rt->hcnt > pre_repair_hcnt) { RERR *rerr; u_int8_t rerr_flags = 0; struct in_addr dest; dest.s_addr = AODV_BROADCAST; rerr_flags |= RERR_NODELETE; rerr = rerr_create(rerr_flags, fwd_rt->dest_addr, fwd_rt->dest_seqno); if (fwd_rt->nprec) aodv_socket_send((AODV_msg *) rerr, dest, RERR_CALC_SIZE(rerr), 1, &DEV_IFINDEX(fwd_rt-> ifindex)); } } } else { /* --- Here we FORWARD the RREP on the REVERSE route --- */ if (rev_rt && rev_rt->state == VALID) { rrep_forward(rrep, rreplen, rev_rt, fwd_rt, --ip_ttl); } else { DEBUG(LOG_DEBUG, 0, "Could not forward RREP - NO ROUTE!!!"); } } if (!llfeedback && optimized_hellos) hello_start(); }
static void nl_callback(int sock) { int len, attrlen; socklen_t addrlen; struct nlmsghdr *nlm; struct nlmsgerr *nlmerr; char buf[BUFLEN]; struct in_addr dest_addr, src_addr; struct ifaddrmsg *ifm; struct rtattr *rta; kaodv_rt_msg_t *m; rt_table_t *rt, *fwd_rt, *rev_rt = NULL; addrlen = sizeof(peer); len = recvfrom(sock, buf, BUFLEN, 0, (struct sockaddr *)&peer, &addrlen); if (len <= 0) return; nlm = (struct nlmsghdr *)buf; switch (nlm->nlmsg_type) { case NLMSG_ERROR: nlmerr = NLMSG_DATA(nlm); if (nlmerr->error == 0) { DEBUG(LOG_DEBUG, 0, "NLMSG_ACK"); } else DEBUG(LOG_DEBUG, 0, "NLMSG_ERROR, error=%d", nlmerr->error); break; case RTM_NEWLINK: DEBUG(LOG_DEBUG, 0, "RTM_NEWADDR"); break; case RTM_NEWADDR: DEBUG(LOG_DEBUG, 0, "RTM_NEWADDR"); ifm = NLMSG_DATA(nlm); rta = (struct rtattr *)((char *)ifm + sizeof(ifm)); attrlen = nlm->nlmsg_len - sizeof(struct nlmsghdr) - sizeof(struct ifaddrmsg); for (; RTA_OK(rta, attrlen); rta = RTA_NEXT(rta, attrlen)) { if (rta->rta_type == IFA_ADDRESS) { struct in_addr ifaddr; memcpy(&ifaddr, RTA_DATA(rta), RTA_PAYLOAD(rta)); DEBUG(LOG_DEBUG, 0, "Interface index %d changed address to %s", ifm->ifa_index, ip_to_str(ifaddr)); } } break; case KAODVM_TIMEOUT: m = NLMSG_DATA(nlm); dest_addr.s_addr = m->dst; DEBUG(LOG_DEBUG, 0, "Got TIMEOUT msg from kernel for %s", ip_to_str(dest_addr)); rt = rt_table_find(dest_addr); if (rt && rt->state == VALID) route_expire_timeout(rt); else DEBUG(LOG_DEBUG, 0, "Got rt timeoute event but there is no route"); break; case KAODVM_NOROUTE: m = NLMSG_DATA(nlm); dest_addr.s_addr = m->dst; DEBUG(LOG_DEBUG, 0, "Got NOROUTE msg from kernel for %s", ip_to_str(dest_addr)); rreq_route_discovery(dest_addr, 0, NULL); break; case KAODVM_REPAIR: m = NLMSG_DATA(nlm); dest_addr.s_addr = m->dst; src_addr.s_addr = m->src; DEBUG(LOG_DEBUG, 0, "Got REPAIR msg from kernel for %s", ip_to_str(dest_addr)); fwd_rt = rt_table_find(dest_addr); if (fwd_rt) rreq_local_repair(fwd_rt, src_addr, NULL); break; case KAODVM_ROUTE_UPDATE: m = NLMSG_DATA(nlm); dest_addr.s_addr = m->dst; src_addr.s_addr = m->src; if (dest_addr.s_addr == AODV_BROADCAST || dest_addr.s_addr == DEV_IFINDEX(m->ifindex).broadcast.s_addr) return; fwd_rt = rt_table_find(dest_addr); rev_rt = rt_table_find(src_addr); rt_table_update_route_timeouts(fwd_rt, rev_rt); break; case KAODVM_SEND_RERR: m = NLMSG_DATA(nlm); dest_addr.s_addr = m->dst; src_addr.s_addr = m->src; if (dest_addr.s_addr == AODV_BROADCAST || dest_addr.s_addr == DEV_IFINDEX(m->ifindex).broadcast.s_addr) return; fwd_rt = rt_table_find(dest_addr); rev_rt = rt_table_find(src_addr); do { struct in_addr rerr_dest; RERR *rerr; DEBUG(LOG_DEBUG, 0, "Sending RERR for unsolicited message from %s to dest %s", ip_to_str(src_addr), ip_to_str(dest_addr)); if (fwd_rt) { rerr = rerr_create(0, fwd_rt->dest_addr, fwd_rt->dest_seqno); rt_table_update_timeout(fwd_rt, DELETE_PERIOD); } else rerr = rerr_create(0, dest_addr, 0); /* Unicast the RERR to the source of the data transmission * if possible, otherwise we broadcast it. */ if (rev_rt && rev_rt->state == VALID) rerr_dest = rev_rt->next_hop; else rerr_dest.s_addr = AODV_BROADCAST; aodv_socket_send((AODV_msg *) rerr, rerr_dest, RERR_CALC_SIZE(rerr), 1, &DEV_IFINDEX(m->ifindex)); if (wait_on_reboot) { DEBUG(LOG_DEBUG, 0, "Wait on reboot timer reset."); timer_set_timeout(&worb_timer, DELETE_PERIOD); } } while (0); break; default: DEBUG(LOG_DEBUG, 0, "Got mesg type=%d\n", nlm->nlmsg_type); } }