hello.c 8.06 KB
Newer Older
1 2 3
/*
 *	BIRD -- OSPF
 *
Ondřej Filip's avatar
Ondřej Filip committed
4
 *	(c) 1999--2004 Ondrej Filip <feela@network.cz>
5 6 7 8 9 10
 *
 *	Can be freely distributed and used under the terms of the GNU GPL.
 */

#include "ospf.h"

11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43

#ifdef OSPFv2
struct ospf_hello_packet
{
  struct ospf_packet ospf_packet;
  ip_addr netmask;
  u16 helloint;
  u8 options;
  u8 priority;
  u32 deadint;
  u32 dr;
  u32 bdr;
};
#endif


#ifdef OSPFv3
struct ospf_hello_packet
{
  struct ospf_packet ospf_packet;
  u32 iface_id;
  u8 priority;
  u8 options3;
  u8 options2;
  u8 options;
  u16 helloint;
  u16 deadint;
  u32 dr;
  u32 bdr;
};
#endif


44
void
45 46
ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
		   struct ospf_neighbor *n, ip_addr faddr)
47
{
48 49
  struct proto_ospf *po = ifa->oa->po;
  struct proto *p = &po->proto;
50
  char *beg = "OSPF: Bad HELLO packet from ";
51 52
  unsigned int size, i, twoway, eligible, peers;
  u32 tmp;
53 54 55 56 57
  u32 *pnrid;

  size = ntohs(ps_i->length);
  if (size < sizeof(struct ospf_hello_packet))
  {
58
    log(L_ERR "%s%I - too short (%u B)", beg, faddr, size);
59 60 61 62
    return;
  }

  struct ospf_hello_packet *ps = (void *) ps_i;
63

64
  OSPF_TRACE(D_PACKETS, "HELLO packet received from %I via %s%s", faddr,
65
      (ifa->type == OSPF_IT_VLINK ? "vlink-" : ""), ifa->iface->name);
66 67

#ifdef OSPFv2
68
  ip_addr mask = ps->netmask;
Ondřej Filip's avatar
Ondřej Filip committed
69
  ipa_ntoh(mask);
70 71 72 73 74 75 76
  if ((ifa->type != OSPF_IT_VLINK) &&
      (ifa->type != OSPF_IT_PTP) &&
      !ipa_equal(mask, ipa_mkmask(ifa->addr->pxlen)))
  {
    log(L_ERR "%s%I - netmask mismatch (%I)", beg, faddr, mask);
    return;
  }
77
#endif
78

79 80
  tmp = ntohs(ps->helloint);
  if (tmp != ifa->helloint)
81
  {
82
    log(L_ERR "%s%I - hello interval mismatch (%d)", beg, faddr, tmp);
83 84 85
    return;
  }

86 87 88 89 90 91
#ifdef OSPFv2
  tmp = ntohl(ps->deadint);
#else /* OSPFv3 */
  tmp = ntohs(ps->deadint);
#endif
  if (tmp != ifa->dead)
92
  {
93
    log(L_ERR "%s%I - dead interval mismatch (%d)", beg, faddr, tmp);
94 95 96
    return;
  }

97
  tmp = !(ps->options & OPT_E);
98
  if (tmp != !!ifa->oa->stub)
99
  {
100
    log(L_ERR "%s%I - stub area flag mismatch (%d)", beg, faddr, tmp);
101 102 103
    return;
  }

104
  if (!n)
105
  {
106
    if ((ifa->type == OSPF_IT_NBMA))
107 108
    {
      struct nbma_node *nn;
109
      int found = 0;
110

111
      WALK_LIST(nn, ifa->nbma_list)
112
      {
113
	if (ipa_equal(faddr, nn->ip))
114
	{
115
	  found = 1;
116 117 118
	  break;
	}
      }
119
      if ((found == 0) && (ifa->strictnbma))
120
      {
121
	log(L_WARN "Ignoring new neighbor: %I on %s", faddr,
122
	    ifa->iface->name);
123 124
	return;
      }
125
      if (found)
126
      {
127 128 129 130 131 132
	eligible = nn->eligible;
	if (((ps->priority == 0) && eligible)
	    || ((ps->priority > 0) && (eligible == 0)))
	{
	  log(L_ERR "Eligibility mismatch for neighbor: %I on %s",
	      faddr, ifa->iface->name);
133
	  return;
134
	}
135 136
      }
    }
137
    OSPF_TRACE(D_EVENTS, "New neighbor found: %I on %s", faddr,
138
	       ifa->iface->name);
139 140 141

    n = ospf_neighbor_new(ifa);

142
    n->rid = ntohl(((struct ospf_packet *) ps)->routerid);
143
    n->ip = faddr;
144 145
    n->dr = ntohl(ps->dr);
    n->bdr = ntohl(ps->bdr);
146
    n->priority = ps->priority;
147 148 149
#ifdef OSPFv3
    n->iface_id = ntohl(ps->iface_id);
#endif
150 151 152
  }
  ospf_neigh_sm(n, INM_HELLOREC);

153
  pnrid = (u32 *) ((struct ospf_hello_packet *) (ps + 1));
154

Ondřej Filip's avatar
Ondřej Filip committed
155 156
  peers = (size - sizeof(struct ospf_hello_packet))/ sizeof(u32);

157
  twoway = 0;
Ondřej Filip's avatar
Ondřej Filip committed
158
  for (i = 0; i < peers; i++)
159
  {
160
    if (ntohl(pnrid[i]) == po->router_id)
161
    {
Ondřej Filip's avatar
Ondřej Filip committed
162
      DBG("%s: Twoway received from %I\n", p->name, faddr);
163
      ospf_neigh_sm(n, INM_2WAYREC);
164
      twoway = 1;
165 166 167 168
      break;
    }
  }

169 170
  if (!twoway)
    ospf_neigh_sm(n, INM_1WAYREC);
171

172 173 174
  u32 olddr = n->dr;
  u32 oldbdr = n->bdr;
  u32 oldpriority = n->priority;
175
#ifdef OSPFv3
176
  u32 oldiface_id = n->iface_id;
177 178 179 180
#endif

  n->dr = ntohl(ps->dr);
  n->bdr = ntohl(ps->bdr);
181
  n->priority = ps->priority;
182 183 184 185
#ifdef OSPFv3
  n->iface_id = ntohl(ps->iface_id);
#endif

186

187
  /* Check priority change */
188
  if (n->state >= NEIGHBOR_2WAY)
189
  {
190
#ifdef OSPFv2
191
    u32 neigh = ipa_to_u32(n->ip);
192
#else /* OSPFv3 */
193
    u32 neigh = n->rid;
194 195
#endif

196
    if (n->priority != oldpriority)
Ondřej Filip's avatar
Ondřej Filip committed
197
      ospf_iface_sm(ifa, ISM_NEICH);
198

199 200 201 202 203
#ifdef OSPFv3
    if (n->iface_id != oldiface_id)
      ospf_iface_sm(ifa, ISM_NEICH);
#endif

204 205
    /* Neighbor is declaring itself ad DR and there is no BDR */
    if ((n->dr == neigh) && (n->bdr == 0)
206
	&& (n->state != NEIGHBOR_FULL))
Ondřej Filip's avatar
Ondřej Filip committed
207
      ospf_iface_sm(ifa, ISM_BACKS);
208

209
    /* Neighbor is declaring itself as BDR */
210
    if ((n->bdr == neigh) && (n->state != NEIGHBOR_FULL))
Ondřej Filip's avatar
Ondřej Filip committed
211
      ospf_iface_sm(ifa, ISM_BACKS);
212 213

    /* Neighbor is newly declaring itself as DR or BDR */
214 215
    if (((n->dr == neigh) && (n->dr != olddr))
	|| ((n->bdr == neigh) && (n->bdr != oldbdr)))
Ondřej Filip's avatar
Ondřej Filip committed
216
      ospf_iface_sm(ifa, ISM_NEICH);
217 218

    /* Neighbor is no more declaring itself as DR or BDR */
219 220
    if (((olddr == neigh) && (n->dr != olddr))
	|| ((oldbdr == neigh) && (n->bdr != oldbdr)))
Ondřej Filip's avatar
Ondřej Filip committed
221
      ospf_iface_sm(ifa, ISM_NEICH);
222 223
  }

224
  if (ifa->type == OSPF_IT_NBMA)
225
  {
226 227
    if ((ifa->priority == 0) && (n->priority > 0))
      ospf_hello_send(NULL, 0, n);
228
  }
229 230 231
  ospf_neigh_sm(n, INM_HELLOREC);
}

232
void
233
ospf_hello_send(timer *timer, int poll, struct ospf_neighbor *dirn)
234 235 236 237 238
{
  struct ospf_iface *ifa;
  struct ospf_hello_packet *pkt;
  struct ospf_packet *op;
  struct proto *p;
Ondřej Filip's avatar
Ondřej Filip committed
239
  struct ospf_neighbor *neigh, *n1;
240 241
  u16 length;
  u32 *pp;
Ondřej Filip's avatar
Ondřej Filip committed
242 243
  int i, send;
  struct nbma_node *nb;
244

245 246 247 248
  if (timer == NULL)
    ifa = dirn->ifa;
  else
    ifa = (struct ospf_iface *) timer->data;
249

250
  if (ifa->state <= OSPF_IS_LOOP)
Ondřej Filip's avatar
Ondřej Filip committed
251 252
    return;

253 254
  if (ifa->stub)
    return;			/* Don't send any packet on stub iface */
255

256
  p = (struct proto *) (ifa->oa->po);
257 258
  DBG("%s: Hello/Poll timer fired on interface %s with IP %I\n",
      p->name, ifa->iface->name, ifa->addr->ip);
259

260
  /* Now we should send a hello packet */
261
  pkt = ospf_tx_buffer(ifa);
262
  op = &pkt->ospf_packet;
263

264
  /* Now fill ospf_hello header */
265
  ospf_pkt_fill_hdr(ifa, pkt, HELLO_P);
Ondřej Filip's avatar
Ondřej Filip committed
266

267
#ifdef OSPFv2
268
  pkt->netmask = ipa_mkmask(ifa->addr->pxlen);
Ondřej Filip's avatar
Ondřej Filip committed
269
  ipa_hton(pkt->netmask);
270 271
  if ((ifa->type == OSPF_IT_VLINK) || (ifa->type == OSPF_IT_PTP))
    pkt->netmask = IPA_NONE;
272 273
#endif

274 275
  pkt->helloint = ntohs(ifa->helloint);
  pkt->priority = ifa->priority;
276 277 278 279 280 281 282 283 284 285

#ifdef OSPFv3
  pkt->iface_id = htonl(ifa->iface->index);

  pkt->options3 = ifa->oa->options >> 16;
  pkt->options2 = ifa->oa->options >> 8;
#endif
  pkt->options = ifa->oa->options;

#ifdef OSPFv2
286
  pkt->deadint = htonl(ifa->dead);
287 288 289 290 291 292 293
  pkt->dr = htonl(ipa_to_u32(ifa->drip));
  pkt->bdr = htonl(ipa_to_u32(ifa->bdrip));
#else /* OSPFv3 */
  pkt->deadint = htons(ifa->dead);
  pkt->dr = htonl(ifa->drid);
  pkt->bdr = htonl(ifa->bdrid);
#endif
Ondřej Filip's avatar
Ondřej Filip committed
294 295

  /* Fill all neighbors */
296 297 298
  i = 0;
  pp = (u32 *) (((u8 *) pkt) + sizeof(struct ospf_hello_packet));
  WALK_LIST(neigh, ifa->neigh_list)
Ondřej Filip's avatar
Ondřej Filip committed
299
  {
300
    if ((i+1) * sizeof(u32) + sizeof(struct ospf_hello_packet) > ospf_pkt_bufsize(ifa))
301 302 303 304
    {
      OSPF_TRACE(D_PACKETS, "Too many neighbors on the interface!");
      break;
    }
305
    *(pp + i) = htonl(neigh->rid);
Ondřej Filip's avatar
Ondřej Filip committed
306 307 308
    i++;
  }

309 310
  length = sizeof(struct ospf_hello_packet) + i * sizeof(u32);
  op->length = htons(length);
Ondřej Filip's avatar
Ondřej Filip committed
311

Ondřej Filip's avatar
Ondřej Filip committed
312
  switch(ifa->type)
Ondřej Filip's avatar
Ondřej Filip committed
313
  {
Ondřej Filip's avatar
Ondřej Filip committed
314 315
    case OSPF_IT_NBMA:
      if (timer == NULL)		/* Response to received hello */
Ondřej Filip's avatar
Ondřej Filip committed
316
      {
317
        ospf_send_to(ifa, dirn->ip);
Ondřej Filip's avatar
Ondřej Filip committed
318
      }
Ondřej Filip's avatar
Ondřej Filip committed
319
      else
320
      {
Ondřej Filip's avatar
Ondřej Filip committed
321 322 323 324 325 326 327 328 329 330 331 332
        int toall = 0;
        int meeli = 0;
        if (ifa->state > OSPF_IS_DROTHER)
          toall = 1;
        if (ifa->priority > 0)
          meeli = 1;
 
        WALK_LIST(nb, ifa->nbma_list)
        {
          send = 1;
          WALK_LIST(n1, ifa->neigh_list)
          {
333
            if (ipa_equal(nb->ip, n1->ip))
Ondřej Filip's avatar
Ondřej Filip committed
334 335 336 337 338 339 340 341
            {
              send = 0;
              break;
            }
          }
          if ((poll == 1) && (send))
          {
            if (toall || (meeli && nb->eligible))
342
              ospf_send_to(ifa, nb->ip);
Ondřej Filip's avatar
Ondřej Filip committed
343 344 345 346 347 348 349 350
          }
        }
        if (poll == 0)
        {
          WALK_LIST(n1, ifa->neigh_list)
          {
            if (toall || (n1->rid == ifa->drid) || (n1->rid == ifa->bdrid) ||
                (meeli && (n1->priority > 0)))
351
              ospf_send_to(ifa, n1->ip);
Ondřej Filip's avatar
Ondřej Filip committed
352 353
          }
        }
354
      }
Ondřej Filip's avatar
Ondřej Filip committed
355 356
      break;
    case OSPF_IT_VLINK:
357
      ospf_send_to(ifa, ifa->vip);
Ondřej Filip's avatar
Ondřej Filip committed
358 359
      break;
    default:
360
      ospf_send_to(ifa, AllSPFRouters);
Ondřej Filip's avatar
Ondřej Filip committed
361
  }
362 363 364

  OSPF_TRACE(D_PACKETS, "HELLO packet sent via %s%s",
	     (ifa->type == OSPF_IT_VLINK ? "vlink-" : ""), ifa->iface->name);
365
}