packet.c 4.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*
 *	BIRD -- OSPF
 *
 *	(c) 1999 Ondrej Filip <feela@network.cz>
 *
 *	Can be freely distributed and used under the terms of the GNU GPL.
 */

#include "ospf.h"

void
fill_ospf_pkt_hdr(struct ospf_iface *ifa, void *buf, u8 h_type)
{
  struct ospf_packet *pkt;
  struct proto *p;
  
  p=(struct proto *)(ifa->proto);

  pkt=(struct ospf_packet *)buf;

  pkt->version=OSPF_VERSION;

  pkt->type=h_type;

  pkt->routerid=htonl(p->cf->global->router_id);
26
  pkt->areaid=htonl(ifa->an);
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
  pkt->autype=htons(ifa->autype);
  pkt->checksum=0;
}

void
ospf_tx_authenticate(struct ospf_iface *ifa, struct ospf_packet *pkt)
{
  /* FIXME */
  return;
}

void
ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt)
{

  ospf_tx_authenticate(ifa, pkt);

  /* Count checksum */
  pkt->checksum=ipsum_calculate(pkt,sizeof(struct ospf_packet)-8,
    (pkt+1),ntohs(pkt->length)-sizeof(struct ospf_packet),NULL);
}

int
ospf_rx_hook(sock *sk, int size)
{
#ifndef IPV6
  struct ospf_packet *ps;
  struct ospf_iface *ifa;
  struct proto *p;
  int i;
  u8 *pu8;


  ifa=(struct ospf_iface *)(sk->data);

  p=(struct proto *)(ifa->proto);
  DBG("%s: RX_Hook called on interface %s.\n",p->name, sk->iface->name);

  ps = (struct ospf_packet *) ipv4_skip_header(sk->rbuf, &size);
  if(ps==NULL)
  {
    log("%s: Bad OSPF packet received: bad IP header", p->name);
    log("%s: Discarding",p->name);
    return(1);
  }
  
  if((unsigned)size < sizeof(struct ospf_packet))
  {
    log("%s: Bad OSPF packet received: too short (%u bytes)", p->name, size);
    log("%s: Discarding",p->name);
    return(1);
  }

  if(ntohs(ps->length) != size)
  {
    log("%s: Bad OSPF packet received: size field does not match", p->name);
    log("%s: Discarding",p->name);
    return(1);
  }

  if(ps->version!=OSPF_VERSION)
  {
    log("%s: Bad OSPF packet received: version %u", p->name, ps->version);
    log("%s: Discarding",p->name);
    return(1);
  }

  if(!ipsum_verify(ps, 16,(void *)ps+sizeof(struct ospf_packet),
    ntohs(ps->length)-sizeof(struct ospf_packet), NULL))
  {
    log("%s: Bad OSPF packet received: bad checksum", p->name);
    log("%s: Discarding",p->name);
    return(1);
  }

  /* FIXME: Do authetification */

104
  if(ps->areaid!=ifa->an)
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
  {
    log("%s: Bad OSPF packet received: other area %ld", p->name, ps->areaid);
    log("%s: Discarding",p->name);
    return(1);
  }

  if(ntohl(ps->routerid)==p->cf->global->router_id)
  {
    log("%s: Bad OSPF packet received: received my own IP!.", p->name);
    log("%s: Discarding",p->name);
    return(1);
  }

  if(ntohl(ps->routerid)==0)
  {
    log("%s: Bad OSPF packet received: Id 0.0.0.0 is not allowed.", p->name);
    log("%s: Discarding",p->name);
    return(1);
  }
  
  /* Dump packet */
  pu8=(u8 *)(sk->rbuf+5*4);
  for(i=0;i<ntohs(ps->length);i+=4)
    DBG("%s: received %u,%u,%u,%u\n",p->name, pu8[i+0], pu8[i+1], pu8[i+2],
		    pu8[i+3]);
130
  DBG("%s: received size: %u\n",p->name,size);
131 132 133 134 135 136 137 138 139 140 141 142 143

  switch(ps->type)
  {
    case HELLO:
      DBG("%s: Hello received.\n", p->name);
      ospf_hello_rx((struct ospf_hello_packet *)ps, p, ifa, size, sk->faddr);
      break;
    case DBDES:
      DBG("%s: Database description received.\n", p->name);
      ospf_dbdes_rx((struct ospf_dbdes_packet *)ps, p, ifa, size);
      break;
    case LSREQ:
      DBG("%s: Link state request received.\n", p->name);
Ondřej Filip's avatar
Ondřej Filip committed
144
      ospf_lsreq_rx((struct ospf_lsreq_packet *)ps, p, ifa, size);
145 146 147
      break;
    case LSUPD:
      DBG("%s: Link state update received.\n", p->name);
148
      ospf_lsupd_rx((struct ospf_lsupd_packet *)ps, p, ifa, size);
149 150 151
      break;
    case LSACK:
      DBG("%s: Link state ack received.\n", p->name);
Ondřej Filip's avatar
Ondřej Filip committed
152
      ospf_lsack_rx((struct ospf_lsack_packet *)ps, p, ifa, size);
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
      break;
    default:
      log("%s: Bad packet received: wrong type %u", p->name, ps->type);
      log("%s: Discarding",p->name);
      return(1);
  };
  DBG("\n");
#else
#error RX_Hook does not work for IPv6 now.
#endif
  return(1);
}

void
ospf_tx_hook(sock *sk)
{
  struct ospf_iface *ifa;
  struct proto *p;

  ifa=(struct ospf_iface *)(sk->data);

  p=(struct proto *)(ifa->proto);
  DBG("%s: TX_Hook called on interface %s\n", p->name,sk->iface->name);
}

void
ospf_err_hook(sock *sk, int err)
{
  struct ospf_iface *ifa;
  struct proto *p;

  ifa=(struct ospf_iface *)(sk->data);

  p=(struct proto *)(ifa->proto);
  DBG("%s: Err_Hook called on interface %s\n", p->name,sk->iface->name);
}

190 191 192 193 194 195 196 197 198
void
sk_send_to_agt(sock *sk, u16 len, struct ospf_iface *ifa, u8 state)
{
  struct ospf_neighbor *n;

  WALK_LIST(NODE n,ifa->neigh_list)
    if(n->state>=state)
      sk_send_to(sk, len, n->ip, OSPF_PROTO);
}