/*
    NetIPForward.c, Copyright  (c) by Claudio Jeker,
    Swiss Federal Institute of Technology,
    Computer Engineering and Networks Laboratory.
 
    TOPSY -- A Teachable Operating System.
             Implementation of a tiny and simple
             micro kernel for teaching purposes.
 
    For further information, please visit http://www.tik.ee.ethz.ch/~topsy
 
    This software is provided under the terms of the GNU General Public
    Licence. A full copy of the GNU GPL is provided in the file COPYING
    found in the development root of Topsy.
*/
/*
 
    File:                  $Source: /home/ruf/cvs_Topsy/cvs/Topsy/Net/Modules/IP/NetIPForward.c,v $
    Author(s):
    Affiliation:           ETH Zuerich, TIK
    Version:               $Revision: 2922 $
    Creation Date:
    Last Date of Change:   $Date: 2007-03-19 17:48:52 +0100 (Mon, 19 Mär 2007) $  by: $Author: baderma $
 
*/
#include "Topsy.h"
#include "Syscall.h"
#include "Support.h"
#include "NetModulesNew.h"
#include "NetDevice.h"
#include "NetDebug.h"
#include "NetHAL.h"
#include "NetAttr.h"
#include "LWThreads.h"
#include "NullModule.h"


void netIPForwardInit(NetModule this)
{
  return;
}


int netIPForwardConfig(NetModule this, Message *msg)
{
  return 0;
}


void netIPForwardMain(LWPool lw, ThreadArg arg)
{
  NetModule		modDesc = (NetModule) arg;
  NetBuf			data;
  NetAttrs		meta;
  NetDevice		device;
  NetAttr attrVec[4]; /* need to be enough big to hold all needed attrs */
  u16				devNr, type;

  while (1)
  {
    netmodRecv(lw, &data, &meta);
    PACKSTART(modDesc);
    //netdbgPrintf(NETDEBUG_IP6, "netIPForwardMain: received...\n");
    if (!netattrGet(meta, NETATTR_IF_FROM, &devNr) )
    {
      PACKERROR(modDesc);
      netmodRIP(lw, data, meta, "IPForward: failed to get devNr\n");
      continue;
    }
    if (!netattrGet(meta, NETATTR_OSI_3_TYPE, &type) )
    {
      PACKERROR(modDesc);
      netmodRIP(lw, data, meta, "IPForward: failed to get type\n");
      continue;
    }
    if (! netdevGet(devNr, &device) )
    {
      PACKERROR(modDesc);
      netmodRIP(lw, data, meta, "IPForward: failed to get device\n");
      continue;
    }

    switch ( type )
    {
    case NETATTR_TYPE_IPv4:
      //netdbgPrintf(NETDEBUG_IP6, "netIPForwardMain: received an IPv4 packet.\n");
      attrVec[0].key = NETATTR_IP_LOCAL_0;
      attrVec[1].key = NETATTR_IP_LOCAL_1;
      attrVec[2].key = NETATTR_IP_LOCAL_2;
      attrVec[3].key = NETATTR_IP_LOCAL_3;
      if (!( netattrGet(meta, NETATTR_IP_LOCAL_0, &attrVec[0].data) &&
             netattrGet(meta, NETATTR_IP_LOCAL_1, &attrVec[1].data) &&
             netattrGet(meta, NETATTR_IP_LOCAL_2, &attrVec[2].data) &&
             netattrGet(meta, NETATTR_IP_LOCAL_3, &attrVec[3].data)))
      {
        PACKERROR(modDesc);
        netmodRIP(lw, data, meta,
                  "IPForward: failed to get IP Address\n");
        continue;
      }
      if ( attrVec[0].data == 255 && attrVec[1].data == 255 &&
           attrVec[2].data == 255 && attrVec[3].data == 255 )
      {
        /* local broadcast pass it on */
        break;
      }
      /* XXX this is a hack for the presentation */
      if ( attrVec[3].data == 2 )
        break; /* Topsy has always a *.*.*.2 address */

      if ( netdevIsLocal(device, attrVec, 4) )
      {
        netdbgPrintf(NETDEBUG_IP, "IPForward: got local packet\n");
      }
      else
      {
        netdbgPrintf(NETDEBUG_IP,
                     "IPForward: need to forward packet\n");
        /* we just redefine the next CHAIN to the FORWARDING Chain
         */
        if (! netattrSet(meta, NETATTR_OSI_4_TYPE,
                         NETATTR_TYPE_IPv4) )
        {
          PACKERROR(modDesc);
          netmodRIP(lw, data, meta,
                    "IPForward: failed to set attributes\n");
          continue;
        }
      }
      break;
    case NETATTR_TYPE_IPv6:
      //(jb) this will never be the case, because this module is not in the IP6UP-chain
      //forwarding is handled in the NetIP6ModuleUp Module directly
      netdbgPrintf(NETDEBUG_IP6, "netIPForwardMain: received an IPv6 packet.\n");

    default:
      PACKERROR(modDesc);
      netmodRIP(lw, data, meta, "IPForward: unknown protocol\n");
      continue;
    }

    PACKDONE(modDesc);
    netmodSend(lw, CHAINNEXT(modDesc), data, meta);
  }
}
