/** *IP version 4 * *@param ifp the interface to send on *@return nada */ static bool serialize_hna4(struct interface *ifp) { uint16_t remainsize, curr_size, needsize; /* preserve existing data in output buffer */ union olsr_message *m; struct hnapair *pair; struct ip_prefix_list *h; /* No hna nets */ if (ifp == NULL) { return false; } if (olsr_cnf->ip_version != AF_INET) { return false; } h = olsr_cnf->hna_entries; if (h == NULL) { return false; } remainsize = net_outbuffer_bytes_left(ifp); curr_size = OLSR_HNA_IPV4_HDRSIZE; /* calculate size needed for HNA */ needsize = curr_size; while (h) { needsize += olsr_cnf->ipsize*2; h = h->next; } h = olsr_cnf->hna_entries; /* Send pending packet if not room in buffer */ if (needsize > remainsize) { net_output(ifp); remainsize = net_outbuffer_bytes_left(ifp); } check_buffspace(curr_size, remainsize, "HNA"); m = (union olsr_message *)msg_buffer; /* Fill header */ m->v4.originator = olsr_cnf->main_addr.v4.s_addr; m->v4.hopcnt = 0; m->v4.ttl = MAX_TTL; m->v4.olsr_msgtype = HNA_MESSAGE; m->v4.olsr_vtime = ifp->valtimes.hna; pair = m->v4.message.hna.hna_net; for (; h != NULL; h = h->next) { union olsr_ip_addr ip_addr; if ((curr_size + (2 * olsr_cnf->ipsize)) > remainsize) { /* Only add HNA message if it contains data */ if (curr_size > OLSR_HNA_IPV4_HDRSIZE) { #ifdef DEBUG OLSR_PRINTF(BMSG_DBGLVL, "Sending partial(size: %d, buff left:%d)\n", curr_size, remainsize); #endif m->v4.seqno = htons(get_msg_seqno()); m->v4.olsr_msgsize = htons(curr_size); net_outbuffer_push(ifp, msg_buffer, curr_size); curr_size = OLSR_HNA_IPV4_HDRSIZE; pair = m->v4.message.hna.hna_net; } net_output(ifp); remainsize = net_outbuffer_bytes_left(ifp); check_buffspace(curr_size + (2 * olsr_cnf->ipsize), remainsize, "HNA2"); } #ifdef DEBUG OLSR_PRINTF(BMSG_DBGLVL, "\tNet: %s\n", olsr_ip_prefix_to_string(&h->net)); #endif olsr_prefix_to_netmask(&ip_addr, h->net.prefix_len); #ifdef linux if (olsr_cnf->smart_gw_active && is_prefix_inetgw(&h->net)) { /* this is the default route, overwrite it with the smart gateway */ olsr_modifiy_inetgw_netmask(&ip_addr, h->net.prefix_len); } #endif pair->addr = h->net.prefix.v4.s_addr; pair->netmask = ip_addr.v4.s_addr; pair++; curr_size += (2 * olsr_cnf->ipsize); } m->v4.seqno = htons(get_msg_seqno()); m->v4.olsr_msgsize = htons(curr_size); net_outbuffer_push(ifp, msg_buffer, curr_size); //printf("Sending HNA (%d bytes)...\n", outputsize); return false; }
static bool serialize_mid6(struct interface *ifp) { uint16_t remainsize, curr_size, needsize; /* preserve existing data in output buffer */ union olsr_message *m; struct midaddr6 *addrs6; struct interface *ifs; //printf("\t\tGenerating mid on %s\n", ifn->int_name); if ((olsr_cnf->ip_version != AF_INET6) || (!ifp) || (ifnet == NULL) || ((ifnet->int_next == NULL) && (ipequal(&olsr_cnf->main_addr, &ifnet->ip_addr)))) return false; remainsize = net_outbuffer_bytes_left(ifp); curr_size = OLSR_MID_IPV6_HDRSIZE; /* calculate size needed for HNA */ needsize = curr_size; for (ifs = ifnet; ifs != NULL; ifs = ifs->int_next) { needsize += olsr_cnf->ipsize*2; } /* Send pending packet if not room in buffer */ if (needsize > remainsize) { net_output(ifp); remainsize = net_outbuffer_bytes_left(ifp); } check_buffspace(curr_size, remainsize, "MID"); m = (union olsr_message *)msg_buffer; /* Build header */ m->v6.hopcnt = 0; m->v6.ttl = MAX_TTL; m->v6.olsr_msgtype = MID_MESSAGE; m->v6.olsr_vtime = ifp->valtimes.mid; /* Set main(first) address */ m->v6.originator = olsr_cnf->main_addr.v6; addrs6 = m->v6.message.mid.mid_addr; /* Don't add the main address... it's already there */ for (ifs = ifnet; ifs != NULL; ifs = ifs->int_next) { if (!ipequal(&olsr_cnf->main_addr, &ifs->ip_addr)) { #ifdef DEBUG struct ipaddr_str buf; #endif if ((curr_size + olsr_cnf->ipsize) > remainsize) { /* Only add MID message if it contains data */ if (curr_size > OLSR_MID_IPV6_HDRSIZE) { #ifdef DEBUG OLSR_PRINTF(BMSG_DBGLVL, "Sending partial(size: %d, buff left:%d)\n", curr_size, remainsize); #endif /* set size */ m->v6.olsr_msgsize = htons(curr_size); m->v6.seqno = htons(get_msg_seqno()); /* seqnumber */ net_outbuffer_push(ifp, msg_buffer, curr_size); curr_size = OLSR_MID_IPV6_HDRSIZE; addrs6 = m->v6.message.mid.mid_addr; } net_output(ifp); remainsize = net_outbuffer_bytes_left(ifp); check_buffspace(curr_size + olsr_cnf->ipsize, remainsize, "MID2"); } #ifdef DEBUG OLSR_PRINTF(BMSG_DBGLVL, "\t%s(%s)\n", olsr_ip_to_string(&buf, &ifs->ip_addr), ifs->int_name); #endif addrs6->addr = ifs->ip_addr.v6; addrs6++; curr_size += olsr_cnf->ipsize; } } m->v6.olsr_msgsize = htons(curr_size); m->v6.seqno = htons(get_msg_seqno()); /* seqnumber */ //printf("Sending MID (%d bytes)...\n", outputsize); if (curr_size > OLSR_MID_IPV6_HDRSIZE) net_outbuffer_push(ifp, msg_buffer, curr_size); return true; }
static bool serialize_tc6(struct tc_message *message, struct interface *ifp) { #ifdef DEBUG struct ipaddr_str buf; #endif uint16_t remainsize, curr_size; struct tc_mpr_addr *mprs; union olsr_message *m; struct olsr_tcmsg6 *tc6; struct neigh_info6 *mprsaddr6; bool found = false, partial_sent = false; if ((!message) || (!ifp) || (olsr_cnf->ip_version != AF_INET6)) return false; remainsize = net_outbuffer_bytes_left(ifp); m = (union olsr_message *)msg_buffer; tc6 = &m->v6.message.tc; mprsaddr6 = tc6->neigh; curr_size = OLSR_TC_IPV6_HDRSIZE; /* Send pending packet if not room in buffer */ if (curr_size > remainsize) { net_output(ifp); remainsize = net_outbuffer_bytes_left(ifp); } check_buffspace(curr_size, remainsize, "TC"); /* Fill header */ m->v6.olsr_vtime = ifp->valtimes.tc; m->v6.olsr_msgtype = TC_MESSAGE; m->v6.hopcnt = message->hop_count; m->v6.ttl = message->ttl; m->v6.originator = message->originator.v6; /* Fill TC header */ tc6->ansn = htons(message->ansn); tc6->reserved = 0; /*Looping trough MPR selectors */ for (mprs = message->multipoint_relay_selector_address; mprs != NULL; mprs = mprs->next) { /*If packet is to be chomped */ if ((curr_size + olsr_cnf->ipsize) > remainsize) { /* Only add TC message if it contains data */ if (curr_size > OLSR_TC_IPV6_HDRSIZE) { #ifdef DEBUG OLSR_PRINTF(BMSG_DBGLVL, "Sending partial(size: %d, buff left:%d)\n", curr_size, remainsize); #endif m->v6.olsr_msgsize = htons(curr_size); m->v6.seqno = htons(get_msg_seqno()); net_outbuffer_push(ifp, msg_buffer, curr_size); mprsaddr6 = tc6->neigh; curr_size = OLSR_TC_IPV6_HDRSIZE; found = false; partial_sent = true; } net_output(ifp); remainsize = net_outbuffer_bytes_left(ifp); check_buffspace(curr_size + olsr_cnf->ipsize, remainsize, "TC2"); } found = true; #ifdef DEBUG OLSR_PRINTF(BMSG_DBGLVL, "\t%s\n", olsr_ip_to_string(&buf, &mprs->address)); #endif mprsaddr6->addr = mprs->address.v6; curr_size += olsr_cnf->ipsize; mprsaddr6++; } if (found) { m->v6.olsr_msgsize = htons(curr_size); m->v6.seqno = htons(get_msg_seqno()); net_outbuffer_push(ifp, msg_buffer, curr_size); } else { if ((!partial_sent) && (!TIMED_OUT(send_empty_tc))) { OLSR_PRINTF(1, "TC: Sending empty package\n"); m->v6.olsr_msgsize = htons(curr_size); m->v6.seqno = htons(get_msg_seqno()); net_outbuffer_push(ifp, msg_buffer, curr_size); found = true; } } return found; }
static bool serialize_hello6(struct hello_message *message, struct interface *ifp) { uint16_t remainsize, curr_size; struct hello_neighbor *nb; union olsr_message *m; struct hellomsg6 *h6; struct hellinfo6 *hinfo6; union olsr_ip_addr *haddr; int i, j; bool first_entry; if ((!message) || (!ifp) || (olsr_cnf->ip_version != AF_INET6)) return false; remainsize = net_outbuffer_bytes_left(ifp); m = (union olsr_message *)msg_buffer; curr_size = OLSR_HELLO_IPV6_HDRSIZE; /* OLSR message header */ /* Send pending packet if not room in buffer */ if (curr_size > remainsize) { net_output(ifp); remainsize = net_outbuffer_bytes_left(ifp); } check_buffspace(curr_size + olsr_cnf->ipsize + 4, remainsize, "HELLO"); h6 = &m->v6.message.hello; hinfo6 = h6->hell_info; haddr = (union olsr_ip_addr *)hinfo6->neigh_addr; /* Fill message header */ m->v6.ttl = message->ttl; m->v6.hopcnt = 0; /* Set source(main) addr */ m->v6.originator = olsr_cnf->main_addr.v6; m->v6.olsr_msgtype = HELLO_MESSAGE; m->v6.olsr_vtime = ifp->valtimes.hello; /* Fill packet header */ h6->willingness = message->willingness; h6->htime = reltime_to_me(ifp->hello_etime); memset(&h6->reserved, 0, sizeof(uint16_t)); /* *Loops trough all possible neighbor statuses *The negbor list is grouped by status */ for (i = 0; i <= MAX_NEIGH; i++) { for (j = 0; j <= MAX_LINK; j++) { #ifdef DEBUG struct ipaddr_str buf; #endif first_entry = true; /* *Looping trough neighbors */ for (nb = message->neighbors; nb != NULL; nb = nb->next) { if ((nb->status != i) || (nb->link != j)) continue; #ifdef DEBUG OLSR_PRINTF(BMSG_DBGLVL, "\t%s - ", olsr_ip_to_string(&buf, &nb->address)); OLSR_PRINTF(BMSG_DBGLVL, "L:%d N:%d\n", j, i); #endif /* * If there is not enough room left * for the data in the outputbuffer * we must send a partial HELLO and * continue building the rest of the * data in a new HELLO message * * If this is the first neighbor in * a group, we must check for an extra * 4 bytes */ if ((curr_size + olsr_cnf->ipsize + (first_entry ? 4 : 0)) > remainsize) { /* Only send partial HELLO if it contains data */ if (curr_size > OLSR_HELLO_IPV6_HDRSIZE) { #ifdef DEBUG OLSR_PRINTF(BMSG_DBGLVL, "Sending partial(size: %d, buff left:%d)\n", curr_size, remainsize); #endif /* Complete the headers */ m->v6.seqno = htons(get_msg_seqno()); m->v6.olsr_msgsize = htons(curr_size); hinfo6->size = (char *)haddr - (char *)hinfo6; hinfo6->size = htons(hinfo6->size); /* Send partial packet */ net_outbuffer_push(ifp, msg_buffer, curr_size); curr_size = OLSR_HELLO_IPV6_HDRSIZE; h6 = &m->v6.message.hello; hinfo6 = h6->hell_info; haddr = (union olsr_ip_addr *)hinfo6->neigh_addr; /* Make sure typeheader is added */ first_entry = true; } net_output(ifp); /* Reset size and pointers */ remainsize = net_outbuffer_bytes_left(ifp); check_buffspace(curr_size + olsr_cnf->ipsize + 4, remainsize, "HELLO2"); } if (first_entry) { memset(&hinfo6->reserved, 0, sizeof(uint8_t)); /* Set link and status for this group of neighbors (this is the first) */ hinfo6->link_code = CREATE_LINK_CODE(i, j); curr_size += 4; /* HELLO type section header */ } *haddr = nb->address; /* Point to next address */ haddr++; curr_size += olsr_cnf->ipsize; /* IP address added */ first_entry = false; } /* looping trough neighbors */ if (!first_entry) { hinfo6->size = htons((char *)haddr - (char *)hinfo6); hinfo6 = (struct hellinfo6 *)((char *)haddr); haddr = (union olsr_ip_addr *)&hinfo6->neigh_addr; } } /* for j */ } /* for i */ m->v6.seqno = htons(get_msg_seqno()); m->v6.olsr_msgsize = htons(curr_size); net_outbuffer_push(ifp, msg_buffer, curr_size); /* HELLO is always buildt */ return true; }
/** *Check if a message is to be forwarded and forward *it if necessary. * *@param m the OLSR message to be forwarded *@param neighbour we received message from * *@returns positive if forwarded */ int olsr_forward_message(union olsr_message *m, struct interface *in_if, union olsr_ip_addr *from_addr) { union olsr_ip_addr *src; struct neighbor_entry *neighbor; int msgsize; struct interface *ifn; bool is_ttl_1 = false; /* * Sven-Ola: We should not flood the mesh with overdue messages. Because * of a bug in parser.c:parse_packet, we have a lot of messages because * all older olsrd's have lq_fish enabled. */ if (AF_INET == olsr_cnf->ip_version) { if (m->v4.ttl < 2 || 255 < (int)m->v4.hopcnt + (int)m->v4.ttl) is_ttl_1 = true; } else { if (m->v6.ttl < 2 || 255 < (int)m->v6.hopcnt + (int)m->v6.ttl) is_ttl_1 = true; } /* Lookup sender address */ src = mid_lookup_main_addr(from_addr); if (!src) src = from_addr; neighbor = olsr_lookup_neighbor_table(src); if (!neighbor) return 0; if (neighbor->status != SYM) return 0; /* Check MPR */ if (olsr_lookup_mprs_set(src) == NULL) { #ifdef DEBUG struct ipaddr_str buf; OLSR_PRINTF(5, "Forward - sender %s not MPR selector\n", olsr_ip_to_string(&buf, src)); #endif return 0; } if (olsr_message_is_duplicate(m)) { return 0; } /* Treat TTL hopcnt except for ethernet link */ if (!is_ttl_1) { if (olsr_cnf->ip_version == AF_INET) { /* IPv4 */ m->v4.hopcnt++; m->v4.ttl--; } else { /* IPv6 */ m->v6.hopcnt++; m->v6.ttl--; } } /* Update packet data */ msgsize = ntohs(m->v4.olsr_msgsize); /* looping trough interfaces */ for (ifn = ifnet; ifn; ifn = ifn->int_next) { /* do not retransmit out through the same interface if it has mode == ether */ if (ifn == in_if && ifn->mode == IF_MODE_ETHER) continue; /* do not forward TTL 1 messages to non-ether interfaces */ if (is_ttl_1 && ifn->mode != IF_MODE_ETHER) continue; if (net_output_pending(ifn)) { /* * Check if message is to big to be piggybacked */ if (net_outbuffer_push(ifn, m, msgsize) != msgsize) { /* Send */ net_output(ifn); /* Buffer message */ set_buffer_timer(ifn); if (net_outbuffer_push(ifn, m, msgsize) != msgsize) { OLSR_PRINTF(1, "Received message to big to be forwarded in %s(%d bytes)!", ifn->int_name, msgsize); olsr_syslog(OLSR_LOG_ERR, "Received message to big to be forwarded on %s(%d bytes)!", ifn->int_name, msgsize); } } } else { /* No forwarding pending */ set_buffer_timer(ifn); if (net_outbuffer_push(ifn, m, msgsize) != msgsize) { OLSR_PRINTF(1, "Received message to big to be forwarded in %s(%d bytes)!", ifn->int_name, msgsize); olsr_syslog(OLSR_LOG_ERR, "Received message to big to be forwarded on %s(%d bytes)!", ifn->int_name, msgsize); } } } return 1; }
/** Send the transmit buffer out over all designated interfaces, called as a timer callback and also immediately on an external state change. @param interfaces a bitmap defining which interfaces to send over */ static void txToAllOlsrInterfaces(TimedTxInterface interfaces) { /** txBuffer is used to concatenate the position update and cluster leader messages in */ unsigned char txBuffer[TX_BUFFER_SIZE_FOR_OLSR]; unsigned int txBufferBytesUsed = 0; #define txBufferBytesFree (sizeof(txBuffer) - txBufferBytesUsed) /* * The first message in txBuffer is an OLSR position update. * * The position update is always present. * * The second message is the cluster leader message, but only when uplink * was requested and correctly configured. */ UplinkMessage * pu_uplink = (UplinkMessage *) &txBuffer[0]; union olsr_message * pu = &pu_uplink->msg.olsrMessage; unsigned int pu_size = 0; union olsr_ip_addr gateway; MovementState externalState; nmeaINFO nmeaInfo; externalState = getExternalState(); /* only fixup timestamp when the position is valid _and_ when the position was not updated */ if (positionValid(&transmitGpsInformation.txPosition) && !transmitGpsInformation.positionUpdated) { nmea_time_now(&transmitGpsInformation.txPosition.nmeaInfo.utc, &transmitGpsInformation.txPosition.nmeaInfo.present); } nmeaInfo = transmitGpsInformation.txPosition.nmeaInfo; transmitGpsInformation.positionUpdated = false; gateway = transmitGpsInformation.txGateway; /* convert nmeaINFO to wireformat olsr message */ txBufferBytesUsed += sizeof(UplinkHeader); /* keep before txBufferSpaceFree usage */ pu_size = gpsToOlsr(&nmeaInfo, pu, txBufferBytesFree, ((externalState == MOVEMENT_STATE_STATIONARY) ? getUpdateIntervalStationary() : getUpdateIntervalMoving())); txBufferBytesUsed += pu_size; /* * push out to all OLSR interfaces */ if (((interfaces & TX_INTERFACE_OLSR) != 0) && getOlsrTtl() && (pu_size > 0)) { int r; struct interface *ifn; for (ifn = ifnet; ifn; ifn = ifn->int_next) { /* force the pending buffer out if there's not enough space for our message */ if ((int)pu_size > net_outbuffer_bytes_left(ifn)) { net_output(ifn); } r = net_outbuffer_push(ifn, pu, pu_size); if (r != (int) pu_size) { pudError( false, "Could not send to OLSR interface %s: %s (size=%u, r=%d)", ifn->int_name, ((r == -1) ? "no buffer was found" : (r == 0) ? "there was not enough room in the buffer" : "unknown reason"), pu_size, r); } } /* loopback to tx interface when so configured */ if (getUseLoopback()) { (void) packetReceivedFromOlsr(pu, NULL, NULL); } } /* push out over uplink when an uplink is configured */ if (((interfaces & TX_INTERFACE_UPLINK) != 0) && isUplinkAddrSet()) { int fd = getDownlinkSocketFd(); if (fd != -1) { union olsr_sockaddr * uplink_addr = getUplinkAddr(); void * addr; socklen_t addrSize; UplinkMessage * cl_uplink = (UplinkMessage *) &txBuffer[txBufferBytesUsed]; UplinkClusterLeader * cl = &cl_uplink->msg.clusterLeader; union olsr_ip_addr * cl_originator = getClusterLeaderOriginator(olsr_cnf->ip_version, cl); union olsr_ip_addr * cl_clusterLeader = getClusterLeaderClusterLeader(olsr_cnf->ip_version, cl); unsigned int cl_size = sizeof(UplinkClusterLeader) - sizeof(cl->leader) + ((olsr_cnf->ip_version == AF_INET) ? sizeof(cl->leader.v4) : sizeof(cl->leader.v6)); unsigned long long uplinkUpdateInterval = (externalState == MOVEMENT_STATE_STATIONARY) ? getUplinkUpdateIntervalStationary() : getUplinkUpdateIntervalMoving(); if (uplink_addr->in.sa_family == AF_INET) { addr = &uplink_addr->in4; addrSize = sizeof(struct sockaddr_in); } else { addr = &uplink_addr->in6; addrSize = sizeof(struct sockaddr_in6); } /* * position update message (pu) */ /* set header fields in position update uplink message and adjust * the validity time to the uplink validity time */ if (pu_size > 0) { PudOlsrPositionUpdate * pu_gpsMessage = getOlsrMessagePayload(olsr_cnf->ip_version, pu); setUplinkMessageType(&pu_uplink->header, POSITION); setUplinkMessageLength(&pu_uplink->header, pu_size); setUplinkMessageIPv6(&pu_uplink->header, (olsr_cnf->ip_version != AF_INET)); setUplinkMessagePadding(&pu_uplink->header, 0); /* fixup validity time */ setValidityTime(&pu_gpsMessage->validityTime, uplinkUpdateInterval); } /* * cluster leader message (cl) */ /* set cl_uplink header fields */ setUplinkMessageType(&cl_uplink->header, CLUSTERLEADER); setUplinkMessageLength(&cl_uplink->header, cl_size); setUplinkMessageIPv6(&cl_uplink->header, (olsr_cnf->ip_version != AF_INET)); setUplinkMessagePadding(&cl_uplink->header, 0); /* setup cl */ setClusterLeaderVersion(cl, PUD_WIRE_FORMAT_VERSION); setValidityTime(&cl->validityTime, uplinkUpdateInterval); /* really need 2 memcpy's here because of olsr_cnf->ipsize */ memcpy(cl_originator, &olsr_cnf->main_addr, olsr_cnf->ipsize); memcpy(cl_clusterLeader, &gateway, olsr_cnf->ipsize); txBufferBytesUsed += sizeof(UplinkHeader); txBufferBytesUsed += cl_size; errno = 0; if (sendto(fd, &txBuffer, txBufferBytesUsed, 0, addr, addrSize) < 0) { pudError(true, "Could not send to uplink (size=%u)", txBufferBytesUsed); } } } }