/**
 *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_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;
}
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;
}
Exemple #5
0
/**
 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);
			}
		}
	}
}