packet.c 6 KB
Newer Older
1 2 3
/*
 *	BIRD -- OSPF
 *
4
 *	(c) 1999 - 2003 Ondrej Filip <feela@network.cz>
5 6 7 8 9 10 11
 *
 *	Can be freely distributed and used under the terms of the GNU GPL.
 */

#include "ospf.h"

void
12
fill_ospf_pkt_hdr (struct ospf_iface *ifa, void *buf, u8 h_type)
13 14 15 16
{
  struct ospf_packet *pkt;
  struct proto *p;

17
  p = (struct proto *) (ifa->proto);
18

19
  pkt = (struct ospf_packet *) buf;
20

21
  pkt->version = OSPF_VERSION;
22

23 24 25 26 27 28
  pkt->type = h_type;

  pkt->routerid = htonl (p->cf->global->router_id);
  pkt->areaid = htonl (ifa->an);
  pkt->autype = htons (ifa->autype);
  pkt->checksum = 0;
29 30 31
}

void
32
ospf_tx_authenticate (struct ospf_iface *ifa, struct ospf_packet *pkt)
33
{
34
  int i;
35 36
  pkt->autype = htons (ifa->autype);
  memcpy (pkt->authetication, ifa->aukey, 8);
37 38 39
  return;
}

40
int
41
ospf_rx_authenticate (struct ospf_iface *ifa, struct ospf_packet *pkt)
42 43
{
  int i;
44 45 46 47 48
  if (pkt->autype != htons (ifa->autype))
    return 0;
  if (ifa->autype == AU_NONE)
    return 1;
  if (ifa->autype == AU_SIMPLE)
49
    {
50 51 52 53 54 55
      for (i = 0; i < 8; i++)
	{
	  if (pkt->authetication[i] != ifa->aukey[i])
	    return 0;
	}
      return 1;
56 57 58 59
    }
  return 0;
}

60
void
61
ospf_pkt_finalize (struct ospf_iface *ifa, struct ospf_packet *pkt)
62 63
{

64
  ospf_tx_authenticate (ifa, pkt);
65 66

  /* Count checksum */
67 68 69 70
  pkt->checksum = ipsum_calculate (pkt, sizeof (struct ospf_packet) - 8,
				   (pkt + 1),
				   ntohs (pkt->length) -
				   sizeof (struct ospf_packet), NULL);
71 72
}

Ondřej Filip's avatar
Ondřej Filip committed
73 74
/**
 * ospf_rx_hook
75
 * @sk: socket we received the packet. Its ignored.
Ondřej Filip's avatar
Ondřej Filip committed
76 77
 * @size: size of the packet
 *
78 79
 * This is the entry point for messages from neighbors. Many checks (like
 * authentication, checksums, size) are done before the packet is passed to
Ondřej Filip's avatar
Ondřej Filip committed
80 81
 * non generic functions.
 */
82
int
83
ospf_rx_hook (sock *sk, int size)
84 85 86
{
#ifndef IPV6
  struct ospf_packet *ps;
87 88
  struct ospf_iface *ifa = (struct ospf_iface *) (sk->data);
  struct proto *p = (struct proto *) (ifa->proto);
89 90 91
  int i;
  u8 *pu8;

92 93 94 95 96 97 98 99 100 101 102 103 104 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 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
  if (ifa->stub)
    return (1);

  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) || (size != (4 * (size / 4))))
    {
      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);
    }

  if (!ospf_rx_authenticate (ifa, ps))
    {
      log ("%s: Bad OSPF packet received: bad password", p->name);
      return (1);
    }

  if (ntohl (ps->areaid) != ifa->an)
    {
      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 router ID!",
	   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);
    }

Ondřej Filip's avatar
Ondřej Filip committed
166
  /* Dump packet 
167 168 169 170 171 172 173 174 175
     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]);
     DBG("%s: received size: %u\n",p->name,size);
   */

  switch (ps->type)
    {
Ondřej Filip's avatar
Ondřej Filip committed
176
    case HELLO_P:
177
      DBG ("%s: Hello received.\n", p->name);
178
      ospf_hello_receive((struct ospf_hello_packet *) ps, ifa, size,
179
		     sk->faddr);
180
      break;
Ondřej Filip's avatar
Ondřej Filip committed
181
    case DBDES_P:
182
      DBG ("%s: Database description received.\n", p->name);
183
      ospf_dbdes_receive ((struct ospf_dbdes_packet *) ps, ifa, size);
184
      break;
Ondřej Filip's avatar
Ondřej Filip committed
185
    case LSREQ_P:
186
      DBG ("%s: Link state request received.\n", p->name);
187
      ospf_lsreq_receive((struct ospf_lsreq_packet *) ps, ifa, size);
188
      break;
Ondřej Filip's avatar
Ondřej Filip committed
189
    case LSUPD_P:
190 191
      DBG ("%s: Link state update received.\n", p->name);
      ospf_lsupd_rx ((struct ospf_lsupd_packet *) ps, p, ifa, size);
192
      break;
Ondřej Filip's avatar
Ondřej Filip committed
193
    case LSACK_P:
194
      DBG ("%s: Link state ack received.\n", p->name);
195
      ospf_lsack_receive((struct ospf_lsack_packet *) ps, ifa, size);
196 197
      break;
    default:
198 199 200 201
      log ("%s: Bad packet received: wrong type %u", p->name, ps->type);
      log ("%s: Discarding\n", p->name);
      return (1);
    };
202 203 204
#else
#error RX_Hook does not work for IPv6 now.
#endif
205
  return (1);
206 207 208
}

void
209
ospf_tx_hook (sock * sk)
210 211 212 213
{
  struct ospf_iface *ifa;
  struct proto *p;

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

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

void
221
ospf_err_hook (sock * sk, int err)
222 223 224 225
{
  struct ospf_iface *ifa;
  struct proto *p;

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

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

232
void
233
sk_send_to_agt (sock * sk, u16 len, struct ospf_iface *ifa, u8 state)
234 235 236
{
  struct ospf_neighbor *n;

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

void
242
sk_send_to_bdr (sock * sk, u16 len, struct ospf_iface *ifa)
243 244 245
{
  struct ospf_neighbor *n;

246 247 248 249
  if (ipa_compare (ifa->drip, ipa_from_u32 (0)) != 0)
    sk_send_to (sk, len, ifa->drip, OSPF_PROTO);
  if (ipa_compare (ifa->bdrip, ipa_from_u32 (0)) != 0)
    sk_send_to (sk, len, ifa->bdrip, OSPF_PROTO);
250
}