/** * @return * the MAC address of the main IP address */ unsigned char * getMainIpMacAddress(void) { if (!macSet) { struct ifreq ifr; unsigned char * macInIfr; struct interface *mainInterface = if_ifwithaddr(&olsr_cnf->main_addr); if (!mainInterface) { pudError(true, "Could not get the main interface"); return NULL; } macInIfr = getHardwareAddress(mainInterface->int_name, olsr_cnf->ip_version, &ifr); if (!macInIfr) { pudError(true, "Could not get the MAC address of the main interface"); return NULL; } memcpy(&mac[0], &macInIfr[0], PUD_NODEIDTYPE_MAC_BYTES); macSet = true; } return &mac[0]; }
/* ------------------------------------------------------------------------- * Function : BmfEncapsulationPacketReceived * Description: Handle a received BMF-encapsulation packet * Input : intf - the network interface on which the packet was received * forwardedBy - the IP node that forwarded the packet to me * forwardedTo - the destination IP address of the encapsulation * packet, in case the packet was received promiscuously. * Pass NULL if the packet is received normally (unicast or * broadcast). * encapsulationUdpData - the encapsulating IP UDP data, containting * the BMF encapsulation header, followed by the encapsulated * IP packet * Output : none * Return : none * Data Used : BmfInterfaces * ------------------------------------------------------------------------- */ static void BmfEncapsulationPacketReceived( struct TBmfInterface* intf, union olsr_ip_addr* forwardedBy, union olsr_ip_addr* forwardedTo, unsigned char* encapsulationUdpData) { int iAmMpr; /* True (1) if I am selected as MPR by 'forwardedBy' */ unsigned char* ipPacket; /* The encapsulated IP packet */ u_int16_t ipPacketLen; /* Length of the encapsulated IP packet */ struct ip* ipHeader; /* IP header inside the encapsulated IP packet */ union olsr_ip_addr mcSrc; /* Original source of the encapsulated multicast packet */ union olsr_ip_addr mcDst; /* Multicast destination of the encapsulated packet */ struct TEncapHeader* encapsulationHdr; struct TBmfInterface* walker; #ifndef NODEBUG struct ipaddr_str mcSrcBuf, mcDstBuf, forwardedByBuf, forwardedToBuf; #endif /* Are we talking to ourselves? */ if (if_ifwithaddr(forwardedBy) != NULL) { return; } /* Discard encapsulated packets received on a non-OLSR interface */ if (intf->olsrIntf == NULL) { return; } /* Retrieve details about the encapsulated IP packet */ ipPacket = GetIpPacket(encapsulationUdpData); ipPacketLen = GetIpTotalLength(ipPacket); ipHeader = GetIpHeader(encapsulationUdpData); mcSrc.v4 = ipHeader->ip_src; mcDst.v4 = ipHeader->ip_dst; /* Increase counter */ intf->nBmfPacketsRx++; /* Beware: not possible to call olsr_ip_to_string more than 4 times in same printf */ OLSR_PRINTF( 8, "%s: encapsulated pkt of %ld bytes incoming on \"%s\": %s->%s, forwarded by %s to %s\n", PLUGIN_NAME_SHORT, (long)ipPacketLen, intf->ifName, olsr_ip_to_string(&mcSrcBuf, &mcSrc), olsr_ip_to_string(&mcDstBuf, &mcDst), olsr_ip_to_string(&forwardedByBuf, forwardedBy), forwardedTo != NULL ? olsr_ip_to_string(&forwardedToBuf, forwardedTo) : "me"); /* Get encapsulation header */ encapsulationHdr = (struct TEncapHeader*) encapsulationUdpData; /* Verify correct format of BMF encapsulation header */ if (encapsulationHdr->type != BMF_ENCAP_TYPE || encapsulationHdr->len != BMF_ENCAP_LEN || ntohs(encapsulationHdr->reserved != 0)) { OLSR_PRINTF( 8, "%s: --> discarding: format of BMF encapsulation header not recognized\n", PLUGIN_NAME_SHORT); return; } /* Check if this packet was seen recently */ if (CheckAndMarkRecentPacket(ntohl(encapsulationHdr->crc32))) { /* Increase counter */ intf->nBmfPacketsRxDup++; OLSR_PRINTF( 8, "%s: --> discarding: packet is duplicate\n", PLUGIN_NAME_SHORT); return; } if (EtherTunTapFd >= 0) { /* Unpack the encapsulated IP packet and deliver it locally, by sending * a copy into the local IP stack via the EtherTunTap interface */ union olsr_ip_addr broadAddr; int nBytesToWrite, nBytesWritten; unsigned char* bufferToWrite; /* If the encapsulated IP packet is a local broadcast packet, * update its destination address to match the subnet of the EtherTunTap * interface */ broadAddr.v4.s_addr = htonl(EtherTunTapIpBroadcast); CheckAndUpdateLocalBroadcast(ipPacket, &broadAddr); bufferToWrite = ipPacket; nBytesToWrite = ipPacketLen; /* Write the packet into the EtherTunTap interface for local delivery */ nBytesWritten = write(EtherTunTapFd, bufferToWrite, nBytesToWrite); if (nBytesWritten != nBytesToWrite) { BmfPError("write() error forwarding encapsulated pkt on \"%s\"", EtherTunTapIfName); } else { OLSR_PRINTF( 8, "%s: --> unpacked and delivered locally on \"%s\"\n", PLUGIN_NAME_SHORT, EtherTunTapIfName); } } /* if (EtherTunTapFd >= 0) */ /* Check if I am MPR for the forwarder */ iAmMpr = (olsr_lookup_mprs_set(MainAddressOf(forwardedBy)) != NULL); /* Check with each network interface what needs to be done on it */ for (walker = BmfInterfaces; walker != NULL; walker = walker->next) { /* What to do with the packet on a non-OLSR interface? Unpack * encapsulated packet, and forward it. * * What to do with the packet on an OLSR interface? Forward it only * if the forwarding node has selected us as MPR (iAmMpr). * * Note that the packet is always coming in on an OLSR interface, because * it is an encapsulated BMF packet. */ /* To a non-OLSR interface: unpack the encapsulated IP packet and forward it */ if (walker->olsrIntf == NULL) { ForwardPacket (walker, ipPacket, ipPacketLen, "unpacked and forwarded to non-OLSR interface"); } /* if (walker->olsrIntf == NULL) */ /* To an OLSR interface: forward the packet, but only if this node is * selected as MPR by the forwarding node */ else if (iAmMpr) { EncapsulateAndForwardPacket ( walker, encapsulationUdpData, &mcSrc, forwardedBy, forwardedTo); } /* else if (iAmMpr) */ else /* walker->olsrIntf != NULL && !iAmMpr */ { #ifndef NODEBUG struct ipaddr_str buf; #endif /* 'walker' is an OLSR interface, but I am not selected as MPR. In that * case, don't forward. */ OLSR_PRINTF( 8, "%s: --> not forwarding on \"%s\": I am not selected as MPR by %s\n", PLUGIN_NAME_SHORT, walker->ifName, olsr_ip_to_string(&buf, forwardedBy)); } /* else */ } /* for */ } /* BmfEncapsulationPacketReceived */
void ifinit(void) { struct interface ifs, *ifp; int s; char buf[BUFSIZ], *cp, *cplim; struct ifconf ifc; struct ifreq ifreq, *ifr; struct sockaddr_in *sin; u_long i; if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { syslog(LOG_ERR, "socket: %m"); close(s); return; } ifc.ifc_len = sizeof (buf); ifc.ifc_buf = buf; if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) { syslog(LOG_ERR, "ioctl (get interface configuration)"); close(s); return; } ifr = ifc.ifc_req; lookforinterfaces = 0; cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */ for (cp = buf; cp < cplim; cp += sizeof (ifr->ifr_name) + sizeof(ifr->ifr_ifru)) { ifr = (struct ifreq *)cp; bzero((char *)&ifs, sizeof(ifs)); ifs.int_addr = ifr->ifr_addr; ifreq = *ifr; if (ioctl(s, SIOCGIFFLAGS, (char *)&ifreq) < 0) { syslog(LOG_ERR, "%s: ioctl (get interface flags)", ifr->ifr_name); continue; } ifs.int_flags = ifreq.ifr_flags | IFF_INTERFACE; if ((ifs.int_flags & IFF_UP) == 0 || ifr->ifr_addr.sa_family == AF_UNSPEC) { lookforinterfaces = 1; continue; } /* argh, this'll have to change sometime */ if (ifs.int_addr.sa_family != AF_INET) continue; if (ifs.int_flags & IFF_POINTOPOINT) { if (ioctl(s, SIOCGIFDSTADDR, (char *)&ifreq) < 0) { syslog(LOG_ERR, "%s: ioctl (get dstaddr)", ifr->ifr_name); continue; } if (ifr->ifr_addr.sa_family == AF_UNSPEC) { lookforinterfaces = 1; continue; } ifs.int_dstaddr = ifreq.ifr_dstaddr; } /* * already known to us? * This allows multiple point-to-point links * to share a source address (possibly with one * other link), but assumes that there will not be * multiple links with the same destination address. */ if (ifs.int_flags & IFF_POINTOPOINT) { if (if_ifwithdstaddr(&ifs.int_dstaddr)) continue; } else if (if_ifwithaddr(&ifs.int_addr)) continue; if (ifs.int_flags & IFF_LOOPBACK) { ifs.int_flags |= IFF_PASSIVE; foundloopback = 1; loopaddr = ifs.int_addr; for (ifp = ifnet; ifp; ifp = ifp->int_next) if (ifp->int_flags & IFF_POINTOPOINT) add_ptopt_localrt(ifp); } if (ifs.int_flags & IFF_BROADCAST) { if (ioctl(s, SIOCGIFBRDADDR, (char *)&ifreq) < 0) { syslog(LOG_ERR, "%s: ioctl (get broadaddr)", ifr->ifr_name); continue; } ifs.int_broadaddr = ifreq.ifr_broadaddr; } #ifdef SIOCGIFMETRIC if (ioctl(s, SIOCGIFMETRIC, (char *)&ifreq) < 0) { syslog(LOG_ERR, "%s: ioctl (get metric)", ifr->ifr_name); ifs.int_metric = 0; } else ifs.int_metric = ifreq.ifr_metric; #else ifs.int_metric = 0; #endif /* * Use a minimum metric of one; * treat the interface metric (default 0) * as an increment to the hop count of one. */ ifs.int_metric++; if (ioctl(s, SIOCGIFNETMASK, (char *)&ifreq) < 0) { syslog(LOG_ERR, "%s: ioctl (get netmask)", ifr->ifr_name); continue; } sin = (struct sockaddr_in *)&ifreq.ifr_addr; ifs.int_subnetmask = ntohl(sin->sin_addr.s_addr); sin = (struct sockaddr_in *)&ifs.int_addr; i = ntohl(sin->sin_addr.s_addr); if (IN_CLASSA(i)) ifs.int_netmask = IN_CLASSA_NET; else if (IN_CLASSB(i)) ifs.int_netmask = IN_CLASSB_NET; else ifs.int_netmask = IN_CLASSC_NET; ifs.int_net = i & ifs.int_netmask; ifs.int_subnet = i & ifs.int_subnetmask; if (ifs.int_subnetmask != ifs.int_netmask) ifs.int_flags |= IFF_SUBNET; ifp = (struct interface *)malloc(sizeof (struct interface)); if (ifp == 0) { printf("routed: out of memory\n"); break; } *ifp = ifs; /* * Count the # of directly connected networks * and point to point links which aren't looped * back to ourself. This is used below to * decide if we should be a routing ``supplier''. */ if ((ifs.int_flags & IFF_LOOPBACK) == 0 && ((ifs.int_flags & IFF_POINTOPOINT) == 0 || if_ifwithaddr(&ifs.int_dstaddr) == 0)) externalinterfaces++; /* * If we have a point-to-point link, we want to act * as a supplier even if it's our only interface, * as that's the only way our peer on the other end * can tell that the link is up. */ if ((ifs.int_flags & IFF_POINTOPOINT) && supplier < 0) supplier = 1; ifp->int_name = malloc(strlen(ifr->ifr_name) + 1); if (ifp->int_name == 0) { fprintf(stderr, "routed: ifinit: out of memory\n"); syslog(LOG_ERR, "routed: ifinit: out of memory\n"); close(s); return; } strcpy(ifp->int_name, ifr->ifr_name); *ifnext = ifp; ifnext = &ifp->int_next; traceinit(ifp); addrouteforif(ifp); } if (externalinterfaces > 1 && supplier < 0) supplier = 1; close(s); }
/** *Processes an list of neighbors from an incoming HELLO message. *@param neighbor the neighbor who sent the message. *@param message the HELLO message *@return nada */ static void process_message_neighbors(struct neighbor_entry *neighbor, const struct hello_message *message) { struct hello_neighbor *message_neighbors; for (message_neighbors = message->neighbors; message_neighbors != NULL; message_neighbors = message_neighbors->next) { union olsr_ip_addr *neigh_addr; struct neighbor_2_entry *two_hop_neighbor; /* *check all interfaces *so that we don't add ourselves to the *2 hop list *IMPORTANT! */ if (if_ifwithaddr(&message_neighbors->address) != NULL) continue; /* Get the main address */ neigh_addr = mid_lookup_main_addr(&message_neighbors->address); if (neigh_addr != NULL) { message_neighbors->address = *neigh_addr; } if (((message_neighbors->status == SYM_NEIGH) || (message_neighbors->status == MPR_NEIGH))) { struct neighbor_2_list_entry *two_hop_neighbor_yet = olsr_lookup_my_neighbors(neighbor, &message_neighbors->address); if (two_hop_neighbor_yet != NULL) { /* Updating the holding time for this neighbor */ olsr_set_timer(&two_hop_neighbor_yet->nbr2_list_timer, message->vtime, OLSR_NBR2_LIST_JITTER, OLSR_TIMER_ONESHOT, &olsr_expire_nbr2_list, two_hop_neighbor_yet, 0); two_hop_neighbor = two_hop_neighbor_yet->neighbor_2; /* * For link quality OLSR, reset the path link quality here. * The path link quality will be calculated in the second pass, below. * Keep the saved_path_link_quality for reference. */ if (olsr_cnf->lq_level > 0) { /* * loop through the one-hop neighbors that see this * 'two_hop_neighbor' */ struct neighbor_list_entry *walker; for (walker = two_hop_neighbor->neighbor_2_nblist.next; walker != &two_hop_neighbor->neighbor_2_nblist; walker = walker->next) { /* * have we found the one-hop neighbor that sent the * HELLO message that we're current processing? */ if (walker->neighbor == neighbor) { walker->path_linkcost = LINK_COST_BROKEN; } } } } else { two_hop_neighbor = olsr_lookup_two_hop_neighbor_table(&message_neighbors->address); if (two_hop_neighbor == NULL) { changes_neighborhood = true; changes_topology = true; two_hop_neighbor = olsr_malloc(sizeof(struct neighbor_2_entry), "Process HELLO"); two_hop_neighbor->neighbor_2_nblist.next = &two_hop_neighbor->neighbor_2_nblist; two_hop_neighbor->neighbor_2_nblist.prev = &two_hop_neighbor->neighbor_2_nblist; two_hop_neighbor->neighbor_2_pointer = 0; two_hop_neighbor->neighbor_2_addr = message_neighbors->address; olsr_insert_two_hop_neighbor_table(two_hop_neighbor); linking_this_2_entries(neighbor, two_hop_neighbor, message->vtime); } else { /* linking to this two_hop_neighbor entry */ changes_neighborhood = true; changes_topology = true; linking_this_2_entries(neighbor, two_hop_neighbor, message->vtime); } } } } /* Separate, second pass for link quality OLSR */ /* Separate, second and third pass for link quality OLSR */ if (olsr_cnf->lq_level > 0) { olsr_linkcost first_hop_pathcost; struct link_entry *lnk = get_best_link_to_neighbor(&neighbor->neighbor_main_addr); if (!lnk) return; /* calculate first hop path quality */ first_hop_pathcost = lnk->linkcost; /* * Second pass for link quality OLSR: calculate the best 2-hop * path costs to all the 2-hop neighbors indicated in the * HELLO message. Since the same 2-hop neighbor may be listed * more than once in the same HELLO message (each at a possibly * different quality) we want to select only the best one, not just * the last one listed in the HELLO message. */ for (message_neighbors = message->neighbors; message_neighbors != NULL; message_neighbors = message_neighbors->next) { if (if_ifwithaddr(&message_neighbors->address) != NULL) continue; if (((message_neighbors->status == SYM_NEIGH) || (message_neighbors->status == MPR_NEIGH))) { struct neighbor_list_entry *walker; struct neighbor_2_entry *two_hop_neighbor; struct neighbor_2_list_entry *two_hop_neighbor_yet = olsr_lookup_my_neighbors(neighbor, &message_neighbors->address); if (!two_hop_neighbor_yet) continue; two_hop_neighbor = two_hop_neighbor_yet->neighbor_2; /* * loop through the one-hop neighbors that see this * 'two_hop_neighbor' */ for (walker = two_hop_neighbor->neighbor_2_nblist.next; walker != &two_hop_neighbor->neighbor_2_nblist; walker = walker->next) { /* * have we found the one-hop neighbor that sent the * HELLO message that we're current processing? */ if (walker->neighbor == neighbor) { olsr_linkcost new_second_hop_linkcost, new_path_linkcost; // the link cost between the 1-hop neighbour and the // 2-hop neighbour new_second_hop_linkcost = message_neighbors->cost; // the total cost for the route // "us --- 1-hop --- 2-hop" new_path_linkcost = first_hop_pathcost + new_second_hop_linkcost; // Only copy the link quality if it is better than what we have // for this 2-hop neighbor if (new_path_linkcost < walker->path_linkcost) { walker->second_hop_linkcost = new_second_hop_linkcost; walker->path_linkcost = new_path_linkcost; walker->saved_path_linkcost = new_path_linkcost; changes_neighborhood = true; changes_topology = true; } } } } } } }
/* ------------------------------------------------------------------------- * Function : CreateBmfNetworkInterfaces * Description: Create a list of TBmfInterface objects, one for each network * interface on which BMF runs * Input : skipThisIntf - network interface to skip, if seen * Output : none * Return : fail (-1) or success (0) * Data Used : none * ------------------------------------------------------------------------- */ int CreateBmfNetworkInterfaces(struct interface *skipThisIntf) { int skfd; struct ifconf ifc; int numreqs = 30; struct ifreq *ifr; int n; int nOpenedSockets = 0; /* Clear input descriptor set */ FD_ZERO(&InputSet); skfd = socket(PF_INET, SOCK_DGRAM, 0); if (skfd < 0) { BmfPError("no inet socket available to retrieve interface list"); return -1; } /* Retrieve the network interface configuration list */ ifc.ifc_buf = NULL; for (;;) { ifc.ifc_len = sizeof(struct ifreq) * numreqs; ifc.ifc_buf = realloc(ifc.ifc_buf, ifc.ifc_len); if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0) { BmfPError("ioctl(SIOCGIFCONF) error"); close(skfd); free(ifc.ifc_buf); return -1; } if ((unsigned)ifc.ifc_len == sizeof(struct ifreq) * numreqs) { /* Assume it overflowed; double the space and try again */ numreqs *= 2; assert(numreqs < 1024); continue; /* for (;;) */ } break; /* for (;;) */ } /* for (;;) */ close(skfd); /* For each item in the interface configuration list... */ ifr = ifc.ifc_req; for (n = ifc.ifc_len / sizeof(struct ifreq); --n >= 0; ifr++) { struct interface *olsrIntf; union olsr_ip_addr ipAddr; /* Skip the BMF network interface itself */ //if (strncmp(ifr->ifr_name, EtherTunTapIfName, IFNAMSIZ) == 0) //{ // continue; /* for (n = ...) */ //} /* ...find the OLSR interface structure, if any */ ipAddr.v4 = ((struct sockaddr_in *)ARM_NOWARN_ALIGN(&ifr->ifr_addr))->sin_addr; olsrIntf = if_ifwithaddr(&ipAddr); if (skipThisIntf != NULL && olsrIntf == skipThisIntf) { continue; /* for (n = ...) */ } if (olsrIntf == NULL && !IsNonOlsrBmfIf(ifr->ifr_name)) { /* Interface is neither OLSR interface, nor specified as non-OLSR BMF * interface in the BMF plugin parameter list */ continue; /* for (n = ...) */ } if (!IsNonOlsrBmfIf(ifr->ifr_name)) { //If the interface is not specified in the configuration file then go ahead continue; /* for (n = ...) */ } //TODO: asser if->ifr_name is not talking OLSR //nOpenedSockets += CreateInterface(ifr->ifr_name, olsrIntf); nOpenedSockets += CreateInterface(ifr->ifr_name, NULL); } /* for (n = ...) */ free(ifc.ifc_buf); if (BmfInterfaces == NULL) { //OLSR_PRINTF(1, "%s: could not initialize any network interface\n", PLUGIN_NAME); } else { //OLSR_PRINTF(1, "%s: opened %d sockets\n", PLUGIN_NAME, nOpenedSockets); } return 0; } /* CreateBmfNetworkInterfaces */
/* * Find the network interfaces which have configured themselves. * If the interface is present but not yet up (for example an * ARPANET IMP), set the lookforinterfaces flag so we'll * come back later and look again. */ void ifinit(void) { struct interface ifs, *ifp; size_t needed; int mib[6], no_ipxaddr = 0, flags = 0; char *buf, *cplim, *cp; struct if_msghdr *ifm; struct ifa_msghdr *ifam; struct sockaddr_dl *sdl = NULL; mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = AF_IPX; mib[4] = NET_RT_IFLIST; mib[5] = 0; if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) quit("route-sysctl-estimate"); if ((buf = malloc(needed)) == NULL) quit("malloc"); if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) lookforinterfaces = 0; cplim = buf + needed; for (cp = buf; cp < cplim; cp += ifm->ifm_msglen) { ifm = (struct if_msghdr *)cp; if (ifm->ifm_type == RTM_IFINFO) { bzero(&ifs, sizeof(ifs)); ifs.int_flags = flags = ifm->ifm_flags | IFF_INTERFACE; if ((flags & IFF_UP) == 0 || no_ipxaddr) lookforinterfaces = 1; sdl = (struct sockaddr_dl *) (ifm + 1); sdl->sdl_data[sdl->sdl_nlen] = 0; no_ipxaddr = 1; continue; } if (ifm->ifm_type != RTM_NEWADDR) quit("ifinit: out of sync"); if ((flags & IFF_UP) == 0) continue; ifam = (struct ifa_msghdr *)ifm; info.rti_addrs = ifam->ifam_addrs; rt_xaddrs((char *)(ifam + 1), cp + ifam->ifam_msglen, &info); if (ifaaddr == 0) { syslog(LOG_ERR, "%s: (get addr)", sdl->sdl_data); continue; } ifs.int_addr = *ifaaddr; if (ifs.int_addr.sa_family != AF_IPX) continue; no_ipxaddr = 0; if (ifs.int_flags & IFF_POINTOPOINT) { if (brdaddr == 0) { syslog(LOG_ERR, "%s: (get dstaddr)", sdl->sdl_data); continue; } if (brdaddr->sa_family == AF_UNSPEC) { lookforinterfaces = 1; continue; } ifs.int_dstaddr = *brdaddr; } if (ifs.int_flags & IFF_BROADCAST) { if (brdaddr == 0) { syslog(LOG_ERR, "%s: (get broadaddr)", sdl->sdl_data); continue; } ifs.int_dstaddr = *brdaddr; } if (ifs.int_flags & IFF_LOOPBACK) { ifs.int_dstaddr = ifs.int_addr; } /* * already known to us? * what makes a POINTOPOINT if unique is its dst addr, * NOT its source address */ if ( ((ifs.int_flags & IFF_POINTOPOINT) && if_ifwithdstaddr(&ifs.int_dstaddr)) || ( ((ifs.int_flags & IFF_POINTOPOINT) == 0) && if_ifwithaddr(&ifs.int_addr))) continue; ifp = (struct interface *) malloc(sdl->sdl_nlen + 1 + sizeof(ifs)); if (ifp == NULL) { syslog(LOG_ERR, "IPXrouted: out of memory\n"); lookforinterfaces = 1; break; } *ifp = ifs; /* * Count the # of directly connected networks * and point to point links which aren't looped * back to ourself. This is used below to * decide if we should be a routing ``supplier''. */ if ((ifs.int_flags & IFF_POINTOPOINT) == 0 || if_ifwithaddr(&ifs.int_dstaddr) == 0) externalinterfaces++; /* * If we have a point-to-point link, we want to act * as a supplier even if it's our only interface, * as that's the only way our peer on the other end * can tell that the link is up. */ if ((ifs.int_flags & IFF_POINTOPOINT) && supplier < 0) supplier = 1; ifp->int_name = (char *)(ifp + 1); strcpy(ifp->int_name, sdl->sdl_data); ifp->int_metric = ifam->ifam_metric; ifp->int_next = ifnet; ifnet = ifp; traceinit(ifp); addrouteforif(ifp); } if (externalinterfaces > 1 && supplier < 0) supplier = 1; free(buf); }
/* * Reads kernel interface list and makes a copy for the local use. */ int initialize_interface(void) { size_t needed; int newif = FALSE, mib[6], flags = 0; char *buf, *cplim, *cp; struct interface *ifs, *ifp; struct preflist *plp = NULL; struct sockaddr_dl *sdl; register struct if_msghdr *ifm; register struct ifa_msghdr *ifam; int externalinterfaces = 0; /* I'm afraid of stack overflow. */ /* So work areas are malloc-ed. */ ifs = (struct interface *)malloc(sizeof(struct interface)); if (ifs == NULL) { syslog(LOG_ERR, "work area malloc: %m"); return -1; } mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = AF_INET6; mib[4] = NET_RT_IFLIST; mib[5] = 0; if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { free(ifs); syslog(LOG_ERR, "sysctl IFLIST 1 : %m"); return -1; } if ((buf = malloc(needed)) == NULL) { free(ifs); syslog(LOG_ERR, "sysctl IFLIST malloc : %m"); return -1; } if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { free(buf); free(ifs); syslog(LOG_ERR, "sysctl IFLIST 2 : %m"); return -1; } for (ifp = ifnet; ifp; ifp = ifp->if_next) { for (plp = ifp->if_ip6addr; plp; plp = plp->pl_next) plp->pl_flag = PL_DELADDR; for (plp = ifp->if_sladdr; plp; plp = plp->pl_next) plp->pl_flag = PL_DELADDR; for (plp = ifp->if_lladdr; plp; plp = plp->pl_next) plp->pl_flag = PL_DELADDR; } /* so, ifp is NULL now */ cplim = buf + needed; for (cp = buf; cp < cplim; cp += ifm->ifm_msglen) { ifm = (struct if_msghdr *)cp; if (ifm->ifm_type == RTM_IFINFO) { newif = FALSE; ifp = (struct interface *)NULL; if (ifm->ifm_addrs != RTA_IFP) continue; /* sanity check */ sdl = (struct sockaddr_dl *)(ifm + 1); if ((ifp = get_if_by_name(sdl)) == NULL) { /* Hack! */ /* IFF_RUNNING means 'has at least one linklocal' * <CAN_SEND> */ /* IFF_JOINED means 'joined multicast group' * <CAN_RECEIVE> */ flags = ifm->ifm_flags & ~(IFF_RUNNING | IFF_JOINED); if ((flags & IFF_UP) == 0) { ifp = NULL; continue; } bzero(ifs, sizeof(struct interface)); ifp = ifs; /* pointer copy */ newif = TRUE; /* already bzeroed, so trailing 0 is not needed */ strncpy(ifp->if_name, sdl->sdl_data, sdl->sdl_nlen); ifp->if_sdl = *sdl; /* struct copy */ ifp->if_flag = flags; } else { flags = ifm->ifm_flags; if ((flags & IFF_UP) == 0) { if (ifp->if_flag & IFF_JOINED) drop_multicast_group(ifp); ifp->if_flag = flags & ~(IFF_RUNNING | IFF_JOINED); /* if_freeaddresses( ifp ); */ /* free will be done in install_address */ ifp = NULL; continue; } if ((ifp->if_flag & IFF_UP) == 0) { /* wake up */ /* counter reset */ ifp->if_badpkt = ifp->if_badrte = ifp->if_updates = 0; } ifp->if_flag = (flags & ~(IFF_RUNNING | IFF_JOINED)) | (ifp->if_flag & (IFF_RUNNING | IFF_JOINED)); ifp->if_sdl = *sdl; /* maybe MAC address * was changed (?) */ } ifp->if_metrc = ifm->ifm_data.ifi_metric; /* maybe index was changed */ if_index(ifp) = ifm->ifm_index; ifp->if_lmtu = ifm->ifm_data.ifi_mtu; /* sanity check */ if (ifp->if_lmtu < (sizeof(struct rip6) + rt6_hdrlen + sizeof(struct route_entry))) { /* rt6_hdrlen may be HUGER than DEFAULT(576) */ ifp->if_flag &= ~IFF_UP; syslog(LOG_ERR, "Too small MTU"); ifp = NULL; newif = FALSE; } continue; } /* if(RTM_IFINFO) */ if (ifm->ifm_type != RTM_NEWADDR) { free(buf); free(ifs); syslog(LOG_ERR, "sysctl illegal data"); return -1; } if (ifp == NULL) continue; /* ifp without IFF_UP shall reach here */ /* First message is RTM_NEWADDR (not RTM_IFINFO) shall reach here */ ifam = (struct ifa_msghdr *)ifm; rtinfo.rti_addrs = ifam->ifam_addrs; plp = (struct preflist *)malloc(sizeof(struct preflist)); if (plp == NULL) { free(buf); free(ifs); syslog(LOG_ERR, "initialize_interface: malloc failed"); return -1; } bzero((void *)plp, sizeof(struct preflist)); if (get_address(ifam->ifam_addrs, (char *)(ifam + 1), (cp + ifam->ifam_msglen), plp) < 0) { free(plp); /* plp = NULL; */ continue; } if (flags & IFF_POINTOPOINT) { if (if_ifwithdstaddr(plp, ifp)) { /* address already on the interface list ( marked * OLDADDR ) */ free(plp); /* plp = NULL; */ continue; } } else { int i; #define vdst plp->pl_dest.s6_addr #define vsrc1 plp->pl_pref.prf_addr.s6_addr #define vsrc2 plp->pl_mask.s6_addr for (i = 0; i < sizeof(struct in6_addr); i++) vdst[i] = vsrc1[i] & vsrc2[i]; #undef vsrc2 #undef vsrc1 #undef vdst if (if_ifwithaddr(plp, ifp)) { /* address already on the interface list ( marked * OLDADDR ) */ free(plp); /* plp = NULL; */ continue; } } if (newif != FALSE) { if ((ifp = (struct interface *)malloc(sizeof(struct interface))) == NULL) { free(plp); free(buf); free(ifs); syslog(LOG_ERR, "initialize_interface: new if malloc :%m"); return -1; } *ifp = *ifs; /* struct copy */ ifp->if_next = ifnet; ifnet = ifp; newif = FALSE; /* CAUTION: this interface loop has * not been finished */ if ((ifp->if_flag & IFF_LOOPBACK) == 0) externalinterfaces++; } add_address(plp, ifp); /* plp = NULL; */ if (ifp->if_flag & IFF_LOOPBACK) foundloopback = 1; } /* for */ /* Unnumbered P2P check */ for (ifp = ifnet; ifp; ifp = ifp->if_next) { if (ifp->if_flag & IFF_POINTOPOINT && ifp->if_flag & IFF_UP) { for (plp = ifp->if_ip6addr; plp; plp = plp->pl_next) if (plp->pl_flag != PL_DELADDR) if_duplicate(plp, ifp); /* Duplicate address will be zeroed */ for (plp = ifp->if_sladdr; plp; plp = plp->pl_next) if (plp->pl_flag != PL_DELADDR) if_duplicate(plp, ifp); /* Duplicate address will be zeroed */ } } /* Even if we have only one (external) interface, RIPng works */ /* MODE_UNSPEC really needed ? */ if (externalinterfaces == 0) rt6_opmode = MODE_QUIET; free(buf); free(ifs); return 0; }