UniK olsrd custom packet implementation HOWTO

Version 0.1
for olsrd 0.4.0
by Andreas Tønnesen
AS OF 0.4.1 THIS HOWTO WILL BE OBSOLETE DUE TO THE NEW PLUG-IN SYSTEM.
I WILL WRITE A NEW HOWTO WHEN 0.4.1 IS RELEASED.

Abstract

The Optimized LinkState Routing protocol(RFC3626) is a table-driven pro-active routing protocol for mobile multi-hop ad-hoc networks(MANETs). OLSR uses a optimalization called Multipoint Relaying to flood packets throughout the network.
All control traffic in OLSR is transmitted by broadcast(or multicast) on port 698 using the User Datagram Protocol(UDP).

OLSR provides a default forwarding algorithm that allows for forwarding of OLSR messages of unknown types. A user may want to use the optimized flooding technique in OLSR to flood certain information, routing related or not, to all nodes that knows how to handle this message.
This document does not try to explain the MPR functioning of the OLSR protocol. If you are not familiar with the MPR scheme you should read up on it!

This document gives hints on how to implement custom packet types to the UniK OLSR implementation.


The information in this document is only valid for UniK OLSR daemon version 0.4.0

Introduction

The UniK OLSR daemon

The UniK OLSR daemon is a implementation of the OLSR protocol for GNU/Linux systems by Andreas Tønnesen. The implementation was based on a OLSR draft 3 compliant implementation by INRIA however most of the INRIA code has either been replaced or heavily modified.

UniK olsrd is in some ascpects, implemented with adding of custom packet-types in mind - giving a developer some flexibility.
UniK OLSRd has a homepage at www.olsr.org. Form this page the latest source code can be downloaded.

Throughout this HOWTO it is assumed that the reader has access to the source-code and is familiar with the C programming language.

Cross-referenced and commented code created with doxygen is available at the UniK olsrd website.

Comments

This document describes how to extend the olsrd sourcecode. I am planning to implement support in the daemon for module-loding at runtime. This way extentions can be written as modules(dynamically linked libraries) which provides a more modular and clean design.

The OLSR deamon structure

OLSR is a table driven routing protocol - so everything is basically about maintaining tables describing the current state of the network.
The implementation is made up of a variety of information repositories that can be queried for various information. The basic layout of olsrd can be depicted as:

         +--------+    +--------------+     +-----------+
         | PACKET |    | INFORMATION  |     |   EVENT   |
INPUT -> | PARSER | -> | REPOSITORIES | <-> | SCHEDULER | -> OUTPUT
         |        |    |              |     |           |
         +--------+    +--------------+     +-----------+
                              |                    |
                              ----------------------
                                         |
                                         V
                                   ROUTE UPDATES

Lets take a closer look at the components:

So when adding a custom packet type and possibly a custom information repository to olsrd one must roughly go trough the following steps: Some of these steps might be omitted depending on whether or not you need to keep a information repository withing the daemon.

The Power status case

We'll consider a simple example case throughout the rest of this HOWTO.
We are interested in a solution where the powerstatus of nodes in the MANET can be registered. This solution should not affect node that has not enabled this functioning. So we'll assume having access to a MANET where a subset of nodes are power-status enabled.

A node is to periodically flood the network with a custom packet containing the following information: So what we need to implement is: Issues like a way of polling powerinfo about the local node will not be covered in this HOWTO.(If you are interested in how to do this - check out the proc file-system).

We decide that this message is to be transmitted every 10 seconds and that the information should be considered valid for 30 seconds.

This example-case is in no way intended to be a real-life solution! We'll consider it as a example for the sake of the example! NO IPv6 considerations will be taken either!

UniK olsrd functions and datatypes

We'll start out with a look at the various olsrd specific functions and datatypes you should use in your code.

olsrd IP addresses

To be able to handle both 32-bit IPv4 addresses and 128-bit IPv6 addresses olsrd uses a union defined in olsr_protocol.h as:
union olsr_ip_addr
{
  olsr_u32_t v4;
  struct in6_addr v6;
};
This datatype should be used whenever dealing with IP addresses in olsrd. The variable ipsize(defined in defs.h and set in main.c) contains the size of the addresses used. So whenever copying or comparing IP addresses in olsrd you should do:
/* compare */
memcmp(first_addr, second_addr, ipsize);
/* copy */
memcpy(first_addr, second_addr, ipsize);
Where first_addr and second_addr are pointers to a olsr_ip_addr struct.

olsrd hashing

Olsrd provides some hashing functions that will create a 4 bit hash (represented as a 32 bit datatype) from a union olsr_ip_address. The function is defined in hashing.h as:
olsr_u32_t
olsr_hashing(union olsr_ip_addr *);
It returns a 32 bit value but only the lower 4 bits are actually used. The maximal hash-value is defined in the symbol HASHSIZE. It is currently 16.

olsr_ip_to_string

This function is defined in net.h:
char *
olsr_ip_to_string(union olsr_ip_addr *);
This function converts a IP address of type union olsr_ip_addr to a human readable string. Very useful for debugging output.

OBS: it returns a pointer to a statically allocated buffer - and is not reentrant! If you are to print two ip addresses you MUST do it in two seperate instructions(eg. not in the same printf(3) call)!

olsrd_printf

Defined in olsr.h
int
olsr_printf(int, char *, ...);
The olsr printfwrapper must be used for all output to stdout from olsrd. This typically means that you should use olsr_printf whenever you would have used the printf(3) function from libc.

olsr_printf is similar to printf(3) except from the fact that it takes an integer as the first argument. This integer defines the debuglevel of the message. Olsrd uses 10 debuglevels where 0 means no debug(olsrd runs in the background), 1 means minimal debugoutput and the debugoutput increases with the debuglevel.
So of you are to output essential information to stdout that you consider important you might use debug level 1:
olsr_printf(1, "An error occured %d %s\n", index, olsr_ip_to_string(&address));
This message will be sent to stdout when running olsrd with debug level 1 or above.

Syslogging

Olsrd runs with a opened syslog entry that you should use for critical output. The output sent to the syslog will end up in a system log dependant on your system. You should use LOG_ERR to log error messages.
See "man syslog"

olsr_malloc

This is a wrapper for the malloc(3) syscall. It is defined in olsr.h:
void *
olsr_malloc(size_t, const char *);
You should always use this function when allocating memory in the cases where one would normally do malloc(3)!
It works like malloc(3) except that is does error checing and possibly ouputs information to both sdtout(debuglevel 1) and the syslog(LOG_ERR).
olsr_malloc takes a string representing the caller as its second argument. This strng will be included in error output.

Mantissa exponent functions

The vtime and htime fields of a OLSR message is to be calculated using a exponent/mantissa scheme described in the RFC. These calculations can be done using two functions defined in mantissa.h:
olsr_u8_t
double_to_me(double);

double
me_to_double(olsr_u8_t);
The first one converts a double to a mantissa/exponent value(8 bits). The second one does the opposite.

olsrd timers

Most entries in all tables in olsrd keep a value representing for how long this entry is to be considered valid. The datatype used is struct timeval(defined in sys/time.h) and olsrd offers some functions for working on timvals.

First of all the scheduler maintains a timeval variable that always contains the "current time". You can access this variable when you need a current timestamp.

For working on timevals olsr.h defines the two functions:
int
olsr_timed_out(struct timeval *);

void
olsr_init_timer(olsr_u32_t, struct timeval *);

void
olsr_get_timestamp(olsr_u32_t, struct timeval *);
olsr_timed_out checks if the time-data contained in a struct timeval is in the future. It returns positive if the timeval you passed is not in the future(that means it is "timed out").
olsr_init_timer - fills a provided structure of type timeval with data representing the amount of milliseconds provided in the first argument. OBS note that this function does NOT create a timestamp for the future.
olsr_get_timestamp - fills a provided timeval structure with a timstamp of current time + the number of milliseconds provided by the first argument.

Defining a message

OLSR message types

OLSR uses a 8 bit integer to identify packet types which gives 256 possible different packet types totally. Types 0-127 are reserved by OLSR while 128-255 are available for custom packet types. OLSR uses a default forwarding algorithm on unknown packet-types(and possibly on known packet-types as well), which makes nodes transmitting custom packets not breaking compabillity - and nodes not configured to process these packets forward them according to the MPR scheme.

Default forwarding of unknown messagetypes using MPR flooding makes the design of custom messages containing various information to be diffused into the network rather easy.

Designing a custom message

OLSR packages and messages

All OLSR traffic is transmitted in OLSR packets. They all use the same generic OLSR header. A OLSR packet can contain several OLSR messages.
The basic for of the OLSR packet is:
       0                   1                   2                   3
       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |         Packet Length         |    Packet Sequence Number     |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |  Message Type |     Vtime     |         Message Size          |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                      Originator Address                       |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |  Time To Live |   Hop Count   |    Message Sequence Number    |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                               |
      :                            MESSAGE                            :
      |                                                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |  Message Type |     Vtime     |         Message Size          |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                      Originator Address                       |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |  Time To Live |   Hop Count   |    Message Sequence Number    |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                               |
      :                            MESSAGE                            :
      |                                                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      :                                                               :
               (etc.)
OLSR defines 4 types of packages as of yet:
A OLSR message has the following form
HEADER+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |  Message Type |     Vtime     |         Message Size          |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                      Originator Address                       |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |  Time To Live |   Hop Count   |    Message Sequence Number    |
BODY  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                               |
      :                            MESSAGE                            :
      |                                                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Header fields: The body part is defined by the designer.

In UniK olsrd this datastructure(the OLSR message) for IPv4 is defined in the headerfile olsr_protocol.h as:
struct olsrmsg
{
  olsr_u8_t     olsr_msgtype;
  olsr_u8_t     olsr_vtime;
  olsr_u16_t    olsr_msgsize;
  olsr_u32_t    originator;
  olsr_u8_t     ttl;
  olsr_u8_t     hopcnt;
  olsr_u16_t    seqno;

  union 
  {
    struct hellomsg hello;
    struct tcmsg    tc;
    struct hnamsg   hna;
    struct midmsg   mid;
  } message;

};
The various datatypes used here are also defined in olsr_protocol.h. The olsr_protocol.h headerfile should be studied as it contains all OLSR standard packet definitions

Looking at the olsrmsg struct we recognize the fields from the packetformat we looked at earlier. The actual message body is contained in the message union. If you are not familiar with the union keyword you should consult a C programming manual.

The powerinfo message

What we need to do first is to design the format of the message body of out powerstatus message. We go for the following:
BODY  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |  Powersource  |   percentage  |      Remaining Usage Time     |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The fields are: To make this as easy as possible we'll just add our datatypes to the olsr_protocol.h header file. In real-life you should possibly create you own headerfile as your custom messages are not part of the OLSR protocol which the olsr_protocol headerfile is to define.

First we add our messagetype to the headerfile. We decide that the powerstatus message is of type 128. So we update the following section from the olsr_protocol headerfile:
/*
 *Message Types
 */

#define HELLO_MESSAGE         1
#define TC_MESSAGE            2
#define MID_MESSAGE           3
#define HNA_MESSAGE           4
#define MAX_MESSAGE           4
to:
/*
 *Message Types
 */

#define HELLO_MESSAGE         1
#define TC_MESSAGE            2
#define MID_MESSAGE           3
#define HNA_MESSAGE           4
#define POWERSTATUS_MESSAGE   128
#define MAX_MESSAGE           128
We also add some constants:
#define POWER_AC              0
#define POWER_BATTERY         1
Then we add the struct describing the message body of the powerstatus message. We add the following to the "OLSR packet definitions" section in the headerfile:
/*
 * Powerstatus message
 */

struct powermsg
{
  olsr_u8_t   source_type;
  olsr_u8_t   percentage;
  olsr_u16_t  time_left;
};
Then we need to add the message in the body of the olsrmessage definition:
struct olsrmsg
{
  olsr_u8_t     olsr_msgtype;
  olsr_u8_t     olsr_vtime;
  olsr_u16_t    olsr_msgsize;
  olsr_u32_t    originator;
  olsr_u8_t     ttl;
  olsr_u8_t     hopcnt;
  olsr_u16_t    seqno;

  union 
  {
    struct hellomsg hello;
    struct tcmsg    tc;
    struct hnamsg   hna;
    struct midmsg   mid;
    struct powermsg pms; /* Our new power message */
  } message;
};
And that's all there is to it! We have now added the definition of our custom message type. And since all files accessing the olsrmsg datatype already must include the olsr_protocol headerfile - we do not need to add any #includes anywhere in the source code files.

Creating a information repository

olsrd database structures

We are interested in being able to store the received information about other nodes powerstatus in a database. This database should only contain entries that are considered valid according to the vtime field of the received messages.

Throughout most of olsrd hashed, double-linked ring-lists with static root entries are used. Lets have a look at what that means:

A typical olsr database structure can be schetced as:

        +----------------------------------------+
        |                                        |
        V                                        V
  list[0](root) <-> element1 <-> element2 <-> element3
   |   
   |    +----------------------------------------+
   |    |                                        |
   |    V                                        V
  list[1](root) <-> element1 <-> element2 <-> element3
   |   
   |    +----------------------------------------+
   |    |                                        |
   |    V                                        V
  list[2](root) <-> element1 <-> element2 <-> element3
   |   
   .
   .
   .
   |           +----------------------------------------+
   |           |                                        |
   |           V                                        V
  list[HASHSIZE](root) <-> element1 <-> element2 <-> element3
    
We can see that to find a entry we must first find the hash to be able to access the correct list-array element. Than we need to traverse that list.

Ok - first of all we'll create two files called powerstatus_set.c and powerstatus_set.h. In the headerfile we define the list entries needed and in the c file we implement the functions needed.

Lets start with the headerfile:

#include "olsr_hashing.h" /* for HASHSIZE */

/* The list entry datatype */
struct powerstatus_entry
{
  /* Data */
  union olsr_ip_address    main_address;
  olsr_u8_t                source_type;
  olsr_u8_t                percentage;
  olsr_u16_t               time_left;
  struct timeval           valid_time;
  /* List pointers */
  struct powerstatus_entry *prev;
  struct powerstatus_entry *next;
};

/* The repository */

struct powerstatus_entry power_set[HASHSIZE];

/* Functions */

/*
 * These are only the functions used in this example
 * you need more functionality to actually implement this
 */

/* Initialization function */
void
olsr_init_powerstatus_set();

/* Timeout function */
void
olsr_time_out_powerstatus_set();

Before starting to use the hashed list one MUST initialize the pointers. In powerstatus_set.c add:
void
olsr_init_powerstatus_set()
{
  int index;

  for(index=0;index<HASHSIZE;index++)
    {
      power_set[index].next = &power_set[index];
      power_set[index].prev = &power_set[index];
    }
What is done here is setting all the root entries to point to them selves - both ways. Thus the lists only contain the root element.

THIS INITIALIZATION FUNCTION SHOULD BE CALLED FROM THE main FUNCTION IN main.c

Working on the lists

To insert a entry into a list you can do:
/* You have some pointer to a struct powerset_entry 
   called new_entry */

int hash;

/* Get the hash */
hash = olsr_hashing(&new_entry->main_address);

/* Insert the entry into the correct hashlist */

power_set[hash].next->prev = new_entry;
new_entry->next = power_set[hash].next;
power_set[hash].next = new_entry;
new_entry->prev = &power_set[hash];
OBS!! Notice that the root element(power_set[hash]) is NOT a pointer so this has to be dereferenced!

To remove an entry you can do:
/* You have some pointer to a struct powerset_entry
   called del_entry */

/* Dequeue */
del_entry->next->prev = del_entry->prev;
del_entry->prev->next = del_entry->next;

/* Delete */
free(del_entry);

Registering a timeout function with the scheduler

You should create a function that traverses you lists and removed timed out entries. To be registered with the scheduler this function must be of type void taking no parameters.

When registering a timeout function with the scheduler the function is executed every sched_pollrate seconds. By default this is set to be every 0.1 seconds.
If you need a more precise value you can set it in the olsrd configfile (/etc/olsrd.conf) or simply hard-code it into olsrd.

To register a function:
void
olsr_time_out_powerstatus_set();
with the scheduler, you must do:
#include "scheduler.h"

....

olsr_register_timeout_function(&olsr_time_out_powerstatus_set);

This should preferably be done in the init function of your data repository:
void
olsr_init_powerstatus_set()
{
  int index;

  olsr_register_timeout_function(&olsr_time_out_powerstatus_set);

  for(index=0;index<HASHSIZE;index++)
    {
      power_set[index].next = &power_set[index];
      power_set[index].prev = &power_set[index];
    }

Notes

At this stage it is assumed that you have created proper functions for initializing, adding, deleting, searching and timing out your information repository.

Now we are ready to move on!

Parsing messages

Overwiev

We now need to create functionality to parse a received powerstatus message. We need to:

Implementing a parser function

In the file process_package.c all package parsing functions can be found. You can create your own function here.
For the OLSR messages in uolsrd this functioning consists of two functions pr. messagetype one that converts the bytearray containing the data into a packet object of the desired type (see the *_chgstruct functions) and one that does all nessecary work based on the converted packet object.
You stand free to adopt this approach but the function that receives the data from the parser must be of type void and take a parameter of type union olsr_message *. This parameter is a pointer to the received data.

Since our packetformat is very simple we do not implement a chgstruct function but rather do all processing in one function:

void
olsr_process_received_power(union olsr_message *m)
{

/* Update the power_set based on this info here */

}

Checking for duplicates

The first thing to do when parsing a message will in most cases be to check if we have treated this message before. OLSR uses a duplicate table to be able to do this.
To check the duplicate table(and update it) the function olsr_check_dup_table_proc can be used. This function returns negative if this message has been processed before:

void
olsr_process_received_power(union olsr_message *m)
{

/* If this message has been processed before - we should still
 * check if it should be forwarded
 */
  if(!olsr_check_dup_table_proc(originator, seqno, msgtype)
      goto forward;


/* Update the power_set based on this info here */

 forward:
/* Forward here */

}

You need to extract these values(originator, seqno, msgtype) from the message and pass them to the duplicate check function.

Forwarding

The function parsing the message is also responsible for forwarding it as not all parse functions may choose to use the default forwarding algorithm.

But since we have no special needs we will utilize the default forwarding. This is available to us trough the function olsr_forward_message:
void
olsr_process_received_power(union olsr_message *m)
{

/* If this message has been processed before - we should still
 * check if it should be forwarded
 */
  if(!olsr_check_dup_table_proc(originator, seqno, msgtype)
      goto forward;


/* Update the power_set based on this info here */

 forward:
  olsr_forward_message(m, originator, seqno, msgtype);

  return;
}
The forwarding function will do all nessecary checks for duplicates and register this message to avoid processing it again.

Registering the function with the parser

To register out parse function with the parse multiplexer we can use the function olsr_parser_add_function. All parse functions are registered in the olsr_init_package_process function in the process_package.c file. We must add out own function here including function type:
void
olsr_init_package_process()
{

  olsr_parser_add_function(&olsr_process_received_hello, HELLO_MESSAGE);
  olsr_parser_add_function(&olsr_process_received_tc, TC_MESSAGE);
  olsr_parser_add_function(&olsr_process_received_mid, MID_MESSAGE);
  olsr_parser_add_function(&olsr_process_received_hna, HNA_MESSAGE);
  olsr_parser_add_function(&olsr_process_received_paa, PAA_FORWARD_MESSAGE);
  /* our new function */
  olsr_parser_add_function(&olsr_process_received_power, POWER_MESSAGE);
}
Now our parsing function will be passed all received messages of type POWER_MESSAGE!
And that's all there is to it :-)

Generating messages

Now we need to create functionality to generate powerstatus messages on a regular basis.

Register a sequence number

Sequence numbers are maintained on a pr interface basis in olsrd. To add a sequence number for our powerstatus messaging we update the file interface.h:
/*
 * sequence numbers for interface
 */
struct olsr_seqnums
{
  short     mid_seqnum;
  short     hello_seqnum;
  short     tc_seqnum;
  short     hna_seqnum;
  short     paa_seqnum;
  short     olsr_seqnum;
  /* Our new sequence number */
  short     power_seqnum;
};
We also update the initialization of the sequence-numbers in main.c:
      /*
       *Initialize sequence-numbers
       *for each interface
       */
      ifp->seqnums.mid_seqnum = 1;
      ifp->seqnums.hello_seqnum = 1; 
      ifp->seqnums.tc_seqnum = 1;
      ifp->seqnums.hna_seqnum = 1;
      ifp->seqnums.paa_seqnum = 1;
      ifp->seqnums.olsr_seqnum = 1;
      /* our new entry */
      ifp->seqnums.power_sequnm = 1;
This ensures that all powerstatus sequnms are set to 1(for every interface) at startup.

The outputbuffer and outputsize

UniK olsrd uses a global buffer for data that is to be sent. This buffer can be accessed trough the union olsr_packet *msg pointer declared in main.h.
The size of the data in this buffer must be set in the global variable outputsize. The size set here(in bytes) is the amount of bytes that will be transmitted from this node!

Creating a message build function

The file build_msg.c contains all current packet building functions. Note that some messagetypes uses other functions combined with these to generate more complex packages.

Packets will essentially be different when using different IP address versions, so we need to create one function for version 4 and one for version 6. But to keep the transparency we create one general function that based on the IPversion used calls the correct function.
So - first we add:
int
power_build(struct interface *ifn)
{
  switch(ipversion)
    {
    case(AF_INET):
      return power_build4(ifn);
      break;
    case(AF_INET6):
      return power_build6(ifn);
      break;
    default:
      return -1;
    }
  return -1;
}
Now we need to create the IPversion dependent functions. We add the following to build_msg.c:
int
power_build4(struct interface *ifn)
{
  int i;
  union olsr_message *m;
  struct powermsg *pmsg;
  
  /* Get a pointer to the message header */
  m = msg->v4.olsr_msg
  /* Get a pointer to the body */
  pmsg = m->message.pms;

  /* Set initial hopcount and time to live */
  m->v4.hopcnt = 0;
  m->v4.ttl = MAX_TTL;

  /* Seqno */
  m->v4.seqno = htons(ifn->seqnums.power_seqnum);
      
  /* Set main address */
  memcpy(&m->v4.originator, &main_addr, ipsize);

  /* Set message type */
  m->v4.olsr_msgtype = POWER_MESSAGE;
  /* Set size - fixed in this example - 16 bytes */
  m->v4.olsr_msgsize = htons(16);

  /* 
   * we set the vtalidity time to 30
   * This value must be in mantissa/exponent format
   * as explained in the RFC
   */
  m->v4.olsr_vtime = double_to_me(30);

  /* Total size including OLSR header! */
  outputsize = 20;
  msg->v4.olsr_packlen = htons(20);


  /* FILL MESSAGE WITH POWERINFO */

  /* These functions are assumed to be implemented */

  pmsg->source_type = htons(get_powersource());
  pmsg->percentage = htons(get_power_percentage());
  pmsg->time_left = htons(get_power_ttl());

  return 0;
}
You should make sure you understand what is going on here!

Basically what happens is that pointers to the message header and body are acquired from the outputbuffer. Then the packet-header, message-header and message-body is filled with info.
The actual sending is NOT done here!

Creating a generation function

The file generate_msg.c contains all current packet generation functions.

These functions does not actually build the messages - that is described in the previous section.
A function that is to register itself as a packet generator with the scheduler must be of the type void and take no parameters. In generate_msg.c we add:
void
generate_power()
{

  struct interface *ifn;

  /* looping trough interfaces */
  for (ifn = ifnet; ifn ; ifn = ifn->int_next) 
    {
      power_build(ifn);
      net_output(ifn);

      /* increment the seqno for this interface */
      ifn->seqnums.power_seqnum++;
    }

return;
}
This function loops trough all interfaces that OLSR is running on. For every interface it calls the power_build function that fills the outputbuffer with a powerstatus message and sets the outputsize.
Then the function net_output is invoked.

The net_output function transmits the message in the outputbuffer on the interface specified. The reason this is done on a pr interface basis it that some messages might need to send different data on different interfaces.

Registering the generation function with the scheduler

Now all we need to do is to register our generation function with the scheduler. This is done using the olsr_register_scheduler_event function.
This function takes three parameters (void (*event_function)(), float interval, float initial, olsr_u8_t *trigger): The registration should be added to the init_msg_generator in generate_msg.c:
void
init_msg_generator()
{
  olsr_register_scheduler_event(&generate_hello, hello_int, 0, NULL);
  olsr_register_scheduler_event(&generate_hello_nw, hello_int_nw, 0, NULL);
  olsr_register_scheduler_event(&generate_tc, tc_int, tc_int, &changes);
  if(nbinterf > 1)
    olsr_register_scheduler_event(&generate_mid, mid_int, mid_int/2, NULL);
  if(send_hna)
    olsr_register_scheduler_event(&generate_hna, hna_int, hna_int/2, NULL);
  /* Our new event */
  olsr_register_scheduler_event(&generate_power, power_int, 0, NULL);
 
}

Thats it!!!

Notes

Summary


(C)Andreas Tønnesen 2004