/*
 * listens to network Routing Information Protocol traffic to find a list of
 * routers/gateways on this subnet
 * - an example of the sock_recv() functions
 * - by default, udp_open() only stores the last read UDP packet for a port
 * - use sock_recv() if you expect fast UDP replies, such as from a variety
 *   of sources, it stores multiple packets in a queue
 */

#include <stdio.h>
#include <rtos.h>
#include <net.h>

#define ROUTED_PORT 520
#define BIG_BUF_SIZE 8192

/* The following structures define RIP, routing information protocol */
typedef struct {
    BYTE cmd;
    BYTE ver;
    WORD mbz;
} rip_head;

typedef struct {
    WORD addressfamily;
    WORD mbz;
    DWORD addr;
    DWORD mbz2;
    DWORD mbz3;
    DWORD metric;
} rip_data;


void routed_thread( DWORD dummy )
{
    udp_Socket *u;
    char *bigbuf;
    char dgram[ 1024 ];
    char buffer[ 32 ];
    int templen;
    int i, count;
    DWORD hisip;
    WORD hisport;
    rip_data *rd;

    if ( ( bigbuf = kcalloc( BIG_BUF_SIZE, 1 )) == NULL )
        rt_halt("out of memory allocating buffer");

    /* allocate structure */
    if ( ( u = kcalloc( sizeof( tcp_Socket ), 1 )) == NULL )
        rt_halt("out of memory allocating UDP structure ");

    /* set up socket */
    if ( !udp_open( u, ROUTED_PORT, 0xffffffff, 0xffff, NULL ))
        rt_halt("error openning udp socket\r\n");

    /* indicate to use the big buffer to queue datagrams */
    if ( sock_recv_init( u, bigbuf, BIG_BUF_SIZE ) == -1 )
        rt_halt("error assigning buffer space\r\n");

    do {
        tcp_tick( NULL );   /* process network stuff */

        /* get the latest datagram */
        while ( templen = sock_recv_from( u, &hisip, &hisport, dgram,
                    sizeof(dgram),0)) {
            inet_ntoa(buffer, intel(hisip));
            cprintf("Got packet of %u bytes from %s\r\n", templen, buffer);

            /* determine number of elements by packet size */
            count = (templen - sizeof( rip_head )) / sizeof( rip_data );

            /* cycle through each */
            for ( i = 0 ; i < count ; ++i ) {
                rd = (rip_data*)
                        ( dgram + sizeof( rip_head ) + (i * sizeof( rip_data  )));

                cprintf("   advertising : %s ...\r\n", inet_ntoa( buffer, intel(rd->addr)));
            }
        }

        rt_sleep(10);
    } while ( 1 );
}


int main( int argc, char **argv )
{

    kdebug = 1;

    rt_init(100);
    sock_init();            /* initialize network */
    rt_timerfreq( 100 );

    cputs("starting...waiting for incoming RIP/UDP packets\r\n");
    cputs("often it will be several seconds before you receive any\r\n");
    cputs("Press the space bar to exit\r\n");

    rt_newthread( routed_thread, 0, 4096, 0, "routed_thread" );

    do {
        /* nothing */
        rt_yield();
    } while ( 1 );
}

