/*
 * The olsr.org Optimized Link-State Routing daemon(olsrd)
 * Copyright (c) 2004, Andreas Tønnesen(andreto@olsr.org)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions 
 * are met:
 *
 * * Redistributions of source code must retain the above copyright 
 *   notice, this list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright 
 *   notice, this list of conditions and the following disclaimer in 
 *   the documentation and/or other materials provided with the 
 *   distribution.
 * * Neither the name of olsr.org, olsrd nor the names of its 
 *   contributors may be used to endorse or promote products derived 
 *   from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * Visit http://www.olsr.org for more information.
 *
 * If you find this software useful feel free to make a donation
 * to the project. For more information see the website or contact
 * the copyright holders.
 *
 * $Id: rebuild_packet.c,v 1.22 2007/08/28 20:45:17 bernd67 Exp $
 */


#include "rebuild_packet.h"
#include "defs.h"
#include "olsr.h"
#include "mid_set.h"
#include "mantissa.h"

/**
 *Process/rebuild HNA message. Converts the OLSR
 *packet to the internal hna_message format.
 *@param hmsg the hna_message struct in wich infomation
 *is to be put.
 *@param m the entire OLSR message revieved.
 *@return negative on error
 */

void
hna_chgestruct(struct hna_message *hmsg, union olsr_message *m)
{
  struct hna_net_addr *hna_pairs, *tmp_pairs;
  int no_pairs, i;

  /*Check if everyting is ok*/
  if ((!m) || (m->v4.olsr_msgtype != HNA_MESSAGE))
    return;
  

  if(olsr_cnf->ip_version == AF_INET)
    {
      /* IPv4 */
      struct hnapair *haddr;

      haddr = m->v4.message.hna.hna_net;

      /*
       * How many HNA pairs?
       * nextmsg contains size of
       * the addresses + 12 bytes(nextmessage, from address and the header)
       */
      no_pairs = (ntohs(m->v4.olsr_msgsize) - 12) / 8;
      
      COPY_IP(&hmsg->originator, &m->v4.originator);
      hmsg->packet_seq_number = ntohs(m->v4.seqno);
      hmsg->hop_count =  m->v4.hopcnt;

      //printf("HNA from %s\n\n", olsr_ip_to_string((union olsr_ip_addr *)&hmsg->originator));

      /* Get vtime */
      hmsg->vtime = me_to_double(m->v4.olsr_vtime);

      tmp_pairs = NULL;
      hna_pairs = NULL;

      for(i = 0; i < no_pairs; i++)
	{
	  
	  hna_pairs = olsr_malloc(sizeof(struct hna_net_addr), "HNA chgestruct");
	  
	  
	  COPY_IP(&hna_pairs->net, &haddr->addr);
	  COPY_IP(&hna_pairs->netmask, &haddr->netmask);
	  hna_pairs->next = tmp_pairs;
	  
	  tmp_pairs = hna_pairs;
	  haddr++;
      
	}

    }
  else
    {
      /* IPv6 */
      struct hnapair6 *haddr6;

      haddr6 = m->v6.message.hna.hna_net;

      /*
       * How many HNA pairs?
       * nextmsg contains size of
       * the addresses + 12 bytes(nextmessage, from address and the header)
       */
      no_pairs = (ntohs(m->v6.olsr_msgsize) - 24) / 32; /* NB 32 not 8 */
      
      COPY_IP(&hmsg->originator, &m->v6.originator);
      hmsg->packet_seq_number = ntohs(m->v6.seqno);
      hmsg->hop_count =  m->v6.hopcnt;
      
      /* Get vtime */
      hmsg->vtime = me_to_double(m->v6.olsr_vtime);
      
      tmp_pairs = NULL;
      hna_pairs = NULL;
      
      for(i = 0; i < no_pairs; i++)
	{
	  
	  hna_pairs = olsr_malloc(sizeof(struct hna_net_addr), "HNA chgestruct 2");	  
	  
	  COPY_IP(&hna_pairs->net, &haddr6->addr);
	  hna_pairs->netmask.v6 = olsr_netmask_to_prefix((union olsr_ip_addr *)&haddr6->netmask);

	  hna_pairs->next = tmp_pairs;
	  
	  tmp_pairs = hna_pairs;
	  haddr6++;
	  
	}

      
    }      

  /* 
     tmp_pairs = hna_pairs;
	 
     while(tmp_pairs)
     {
     printf("\t net: %s ", ip_to_string(&tmp_pairs->net));
     printf("\t mask: %s\n", ip_to_string(&tmp_pairs->netmask));
     tmp_pairs = tmp_pairs->next;
     }
     printf("\n");
  */



  hmsg->hna_net = hna_pairs;
 
}


/**
 *Process/rebuild MID message. Converts the OLSR
 *packet to the internal mid_message format.
 *@param mmsg the mid_message struct in wich infomation
 *is to be put.
 *@param m the entire OLSR message revieved.
 *@return negative on error
 */

void
mid_chgestruct(struct mid_message *mmsg, union olsr_message *m)
{
  int i;
  struct mid_alias *alias, *alias_tmp;
  int no_aliases;

  /* Checking if everything is ok */
  if ((!m) || (m->v4.olsr_msgtype != MID_MESSAGE))
    return;

  alias = NULL;

  if(olsr_cnf->ip_version == AF_INET)
    {
      /* IPv4 */
      struct midaddr *maddr;

      maddr = m->v4.message.mid.mid_addr;
      /*
       * How many aliases?
       * nextmsg contains size of
       * the addresses + 12 bytes(nextmessage, from address and the header)
       */
      no_aliases =  ((ntohs(m->v4.olsr_msgsize) - 12) / 4);

      //printf("Aliases: %d\n", no_aliases);
      COPY_IP(&mmsg->mid_origaddr, &m->v4.originator);
      COPY_IP(&mmsg->addr, &m->v4.originator);
      /*seq number*/
      mmsg->mid_seqno = ntohs(m->v4.seqno);
      mmsg->mid_addr = NULL;

      /* Get vtime */
      mmsg->vtime = me_to_double(m->v4.olsr_vtime);

      //printf("Sequencenuber of MID from %s is %d\n", ip_to_string(&mmsg->addr), mmsg->mid_seqno);


      for(i = 0; i < no_aliases; i++)
	{
	  alias = olsr_malloc(sizeof(struct mid_alias), "MID chgestruct");
	  
	  COPY_IP(&alias->alias_addr, &maddr->addr);
	  alias->next = mmsg->mid_addr;
	  mmsg->mid_addr = alias;
	  maddr++;
	}
      
      
      if(olsr_cnf->debug_level > 1)
	{
	  OLSR_PRINTF(3, "Alias list for %s: ", ip_to_string(&mmsg->mid_origaddr.v4));
	  OLSR_PRINTF(3, "%s", ip_to_string(&mmsg->addr.v4));
	  alias_tmp = mmsg->mid_addr;
	  while(alias_tmp)
	    {
	      OLSR_PRINTF(3, " - %s", ip_to_string(&alias_tmp->alias_addr.v4));
	      alias_tmp = alias_tmp->next;
	    }
	  OLSR_PRINTF(3, "\n");
	}
    }
  else
    {
      /* IPv6 */
      struct midaddr6 *maddr6;

      maddr6 = m->v6.message.mid.mid_addr;
      /*
       * How many aliases?
       * nextmsg contains size of
       * the addresses + 12 bytes(nextmessage, from address and the header)
       */
      no_aliases =  ((ntohs(m->v6.olsr_msgsize) - 12) / 16); /* NB 16 */

      //printf("Aliases: %d\n", no_aliases);
      COPY_IP(&mmsg->mid_origaddr, &m->v6.originator);
      COPY_IP(&mmsg->addr, &m->v6.originator);
      /*seq number*/
      mmsg->mid_seqno = ntohs(m->v6.seqno);
      mmsg->mid_addr = NULL;

      /* Get vtime */
      mmsg->vtime = me_to_double(m->v6.olsr_vtime);

      //printf("Sequencenuber of MID from %s is %d\n", ip_to_string(&mmsg->addr), mmsg->mid_seqno);


      for(i = 0; i < no_aliases; i++)
	{
	  alias = olsr_malloc(sizeof(struct mid_alias), "MID chgestruct 2");
	  
	  //printf("Adding alias: %s\n", olsr_ip_to_string((union olsr_ip_addr *)&maddr6->addr));
	  COPY_IP(&alias->alias_addr, &maddr6->addr);
	  alias->next = mmsg->mid_addr;
	  mmsg->mid_addr = alias;
	   
	  maddr6++;
	}


      if(olsr_cnf->debug_level > 1)
	{
	  OLSR_PRINTF(3, "Alias list for %s", ip6_to_string(&mmsg->mid_origaddr.v6));
	  OLSR_PRINTF(3, "%s", ip6_to_string(&mmsg->addr.v6));

	  alias_tmp = mmsg->mid_addr;
	  while(alias_tmp)
	    {
	      OLSR_PRINTF(3, " - %s", ip6_to_string(&alias_tmp->alias_addr.v6));
	      alias_tmp = alias_tmp->next;
	    }
	  OLSR_PRINTF(3, "\n");
	}
    }

}




/**
 *Process/rebuild a message of unknown type. Converts the OLSR
 *packet to the internal unknown_message format.
 *@param umsg the unknown_message struct in wich infomation
 *is to be put.
 *@param m the entire OLSR message revieved.
 *@return negative on error
 */

void
unk_chgestruct(struct unknown_message *umsg, union olsr_message *m)
{

  /* Checking if everything is ok */
  if (!m)
    return;


  if(olsr_cnf->ip_version == AF_INET)
    {
      /* IPv4 */
      /* address */
      COPY_IP(&umsg->originator, &m->v4.originator);
      /*seq number*/
      umsg->seqno = ntohs(m->v4.seqno);
      /* type */
      umsg->type = m->v4.olsr_msgtype;
    }
  else
    {
      /* IPv6 */
      /* address */
      COPY_IP(&umsg->originator, &m->v6.originator);
      /*seq number*/
      umsg->seqno = ntohs(m->v6.seqno);
      /* type */
      umsg->type = m->v4.olsr_msgtype;
    }
  
}



/**
 *Process/rebuild HELLO message. Converts the OLSR
 *packet to the internal hello_message format.
 *@param hmsg the hello_message struct in wich infomation
 *is to be put.
 *@param m the entire OLSR message revieved.
 *@return negative on error
 */

void
hello_chgestruct(struct hello_message *hmsg, union olsr_message *m)
{
  union olsr_ip_addr *hadr;
  struct hello_neighbor *nb;
  
  hmsg->neighbors = NULL;

  if ((!m) || (m->v4.olsr_msgtype != HELLO_MESSAGE))
    return;

  if(olsr_cnf->ip_version == AF_INET)
    {
      struct hellinfo *hinf;

      /* IPv4 */
      COPY_IP(&hmsg->source_addr, &m->v4.originator);
      hmsg->packet_seq_number = ntohs(m->v4.seqno);


      /* Get vtime */
      hmsg->vtime = me_to_double(m->v4.olsr_vtime);

      /* Get htime */
      hmsg->htime = me_to_double(m->v4.message.hello.htime);

      /* Willingness */
      hmsg->willingness = m->v4.message.hello.willingness;

      OLSR_PRINTF(3, "Got HELLO vtime: %f htime: %f\n", hmsg->vtime, hmsg->htime);

      for (hinf = m->v4.message.hello.hell_info; 
	   (char *)hinf < ((char *)m + (ntohs(m->v4.olsr_msgsize))); 
	   hinf = (struct hellinfo *)((char *)hinf + ntohs(hinf->size)))
	{
	  
	  for (hadr = (union olsr_ip_addr  *)&hinf->neigh_addr; 
	       (char *)hadr < (char *)hinf + ntohs(hinf->size); 
	       hadr = (union olsr_ip_addr *)&hadr->v6.s6_addr[4])
	    {
	      nb = olsr_malloc(sizeof (struct hello_neighbor), "HELLO chgestruct");

	      COPY_IP(&nb->address, hadr);

	      /* Fetch link and status */
	      nb->link = EXTRACT_LINK(hinf->link_code);
	      nb->status = EXTRACT_STATUS(hinf->link_code);

	      nb->next = hmsg->neighbors;
	      hmsg->neighbors = nb;
	    }
	}

      
    }
  else
    {
      struct hellinfo6 *hinf6;

      /* IPv6 */
      COPY_IP(&hmsg->source_addr, &m->v6.originator);
      //printf("parsing HELLO from %s\n", olsr_ip_to_string(&hmsg->source_addr));
      hmsg->packet_seq_number = ntohs(m->v6.seqno);

      /* Get vtime */
      hmsg->vtime = me_to_double(m->v6.olsr_vtime);

      /* Get htime */
      hmsg->htime = me_to_double(m->v6.message.hello.htime);

      /* Willingness */
      hmsg->willingness = m->v6.message.hello.willingness;

      OLSR_PRINTF(3, "Got HELLO vtime: %f htime: %f\n", hmsg->vtime, hmsg->htime);


      for (hinf6 = m->v6.message.hello.hell_info; 
	   (char *)hinf6 < ((char *)m + (ntohs(m->v6.olsr_msgsize))); 
	   hinf6 = (struct hellinfo6 *)((char *)hinf6 + ntohs(hinf6->size)))
	{

	  for (hadr = (union olsr_ip_addr *)hinf6->neigh_addr; 
	       (char *)hadr < (char *)hinf6 + ntohs(hinf6->size); 
	       hadr++)
	    {
	      nb = olsr_malloc(sizeof (struct hello_neighbor), "OLSR chgestruct 2");

	      COPY_IP(&nb->address, hadr);

	      /* Fetch link and status */
	      nb->link = EXTRACT_LINK(hinf6->link_code);
	      nb->status = EXTRACT_STATUS(hinf6->link_code);

	      nb->next = hmsg->neighbors;
	      hmsg->neighbors = nb;
	    }
	}

    }

}


/**
 *Process/rebuild TC message. Converts the OLSR
 *packet to the internal tc_message format.
 *@param tmsg the tc_message struct in wich infomation
 *is to be put.
 *@param m the entire OLSR message revieved.
 *@param from a sockaddr struct describing the 1 hop sender
 *@return negative on error
 */

void
tc_chgestruct(struct tc_message *tmsg, union olsr_message *m, union olsr_ip_addr *from_addr)
{
  struct tc_mpr_addr *mprs;
  union olsr_ip_addr *tmp_addr;

  tmsg->multipoint_relay_selector_address = NULL;

  if ((!m) || (m->v4.olsr_msgtype != TC_MESSAGE))
    return;

  if(olsr_cnf->ip_version == AF_INET)
    {
      /* IPv4 */
      struct olsr_tcmsg *tc;
      struct neigh_info *mprsaddr, *maddr;

      tc = &m->v4.message.tc;
      mprsaddr = tc->neigh;

      if((tmp_addr = mid_lookup_main_addr(from_addr)) == 0)
	{
	  COPY_IP(&tmsg->source_addr, from_addr);
	}
      else
	{
	  COPY_IP(&tmsg->source_addr, tmp_addr);
	}


      /* Get vtime */
      tmsg->vtime = me_to_double(m->v4.olsr_vtime);

      OLSR_PRINTF(3, "Got TC vtime: %f\n", tmsg->vtime);

      COPY_IP(&tmsg->originator, &m->v4.originator);
      tmsg->packet_seq_number = ntohs(m->v4.seqno);
      tmsg->hop_count =  m->v4.hopcnt;
      tmsg->ansn =  ntohs(tc->ansn);

      //printf("TC from %s seqno %d\n", olsr_ip_to_string(&tmsg->originator), tmsg->packet_seq_number);

      for (maddr = mprsaddr; (char *)maddr < ((char *)m + (ntohs(m->v4.olsr_msgsize))); maddr++)
	{
	  
	  mprs = olsr_malloc(sizeof(struct tc_mpr_addr), "TC chgestruct");

	  COPY_IP(&mprs->address, &maddr->addr);
	  mprs->next = tmsg->multipoint_relay_selector_address;
	  tmsg->multipoint_relay_selector_address = mprs;
	}
    }
  else
    {
      /* IPv6 */
      struct olsr_tcmsg6 *tc6;
      struct neigh_info6 *mprsaddr6, *maddr6;

      tc6 = &m->v6.message.tc;
      mprsaddr6 = tc6->neigh;

      if((tmp_addr = mid_lookup_main_addr(from_addr)) == 0)
	{
	  COPY_IP(&tmsg->source_addr, from_addr);
	}
      else
	{
	  COPY_IP(&tmsg->source_addr, tmp_addr);
	}

      /* Check if sender is symmetric neighbor here !! */
      
      /* Get vtime */
      tmsg->vtime = me_to_double(m->v6.olsr_vtime);

      OLSR_PRINTF(3, "Got TC vtime: %f\n", tmsg->vtime);

      COPY_IP(&tmsg->originator, &m->v6.originator);
      tmsg->packet_seq_number = ntohs(m->v6.seqno);
      tmsg->hop_count =  m->v6.hopcnt;
      tmsg->ansn =  ntohs(tc6->ansn);

      for (maddr6 = mprsaddr6; (char *)maddr6 < ((char *)m + (ntohs(m->v6.olsr_msgsize))); maddr6++)
	{
	  
	  mprs = olsr_malloc(sizeof(struct tc_mpr_addr), "TC chgestruct 2");

	  COPY_IP(&mprs->address, &maddr6->addr);
	  mprs->next = tmsg->multipoint_relay_selector_address;
	  tmsg->multipoint_relay_selector_address = mprs;
	}

    }

}


syntax highlighted by Code2HTML, v. 0.9.1