Statistics
| Branch: | Revision:

iof-bird-daemon / proto / ospf / hello.c @ e81b440f

History | View | Annotate | Download (8.81 KB)

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

    
9
#include "ospf.h"
10

    
11

    
12
#ifdef OSPFv2
13
struct ospf_hello_packet
14
{
15
  struct ospf_packet ospf_packet;
16
  ip_addr netmask;
17
  u16 helloint;
18
  u8 options;
19
  u8 priority;
20
  u32 deadint;
21
  u32 dr;
22
  u32 bdr;
23
};
24
#endif
25

    
26

    
27
#ifdef OSPFv3
28
struct ospf_hello_packet
29
{
30
  struct ospf_packet ospf_packet;
31
  u32 iface_id;
32
  u8 priority;
33
  u8 options3;
34
  u8 options2;
35
  u8 options;
36
  u16 helloint;
37
  u16 deadint;
38
  u32 dr;
39
  u32 bdr;
40
};
41
#endif
42

    
43

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

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

    
62
  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;
69
  ipa_ntoh(mask);
70
  if (ifa->type != OSPF_IT_VLINK)
71
    {
72
      char *msg = L_WARN "Received HELLO packet %s (%I) is inconsistent "
73
        "with the primary address of interface %s.";
74

    
75
      if ((ifa->type != OSPF_IT_PTP) &&
76
          !ipa_equal(mask, ipa_mkmask(ifa->iface->addr->pxlen)))
77
        {
78
          if (!n) log(msg, "netmask", mask, ifa->iface->name);
79
          return;
80
        }
81

    
82
      /* This check is not specified in RFC 2328, but it is needed
83
       * to handle the case when there is more IP networks on one
84
       * physical network (which is not handled in RFC 2328).
85
       * We allow OSPF on primary IP address only and ignore HELLO packets
86
       * with secondary addresses (which are sent for example by Quagga.
87
       */
88
      if ((ifa->iface->addr->flags & IA_UNNUMBERED) ?
89
          !ipa_equal(faddr, ifa->iface->addr->opposite) :
90
          !ipa_equal(ipa_and(faddr,mask), ifa->iface->addr->prefix))
91
        {
92
          if (!n) log(msg, "address", faddr, ifa->iface->name);
93
          return;
94
        }
95
    }
96
#endif
97

    
98
  tmp = ntohs(ps->helloint);
99
  if (tmp != ifa->helloint)
100
  {
101
    log(L_ERR "%s%I%shello interval mismatch (%d).", beg, faddr, rec, tmp);
102
    return;
103
  }
104

    
105
#ifdef OSPFv2
106
  tmp = ntohl(ps->deadint);
107
#else /* OSPFv3 */
108
  tmp = ntohs(ps->deadint);
109
#endif
110
  if (tmp != ifa->dead)
111
  {
112
    log(L_ERR "%s%I%sdead interval mismatch (%d).", beg, faddr, rec, tmp);
113
    return;
114
  }
115

    
116
  tmp = !(ps->options & OPT_E);
117
  if (tmp != ifa->oa->stub)
118
  {
119
    log(L_ERR "%s%I%sstub area flag mismatch (%d).", beg, faddr, rec, tmp);
120
    return;
121
  }
122

    
123
  if (!n)
124
  {
125
    if ((ifa->type == OSPF_IT_NBMA))
126
    {
127
      struct nbma_node *nn;
128
      int found = 0;
129

    
130
      WALK_LIST(nn, ifa->nbma_list)
131
      {
132
        if (ipa_equal(faddr, nn->ip))
133
        {
134
          found = 1;
135
          break;
136
        }
137
      }
138
      if ((found == 0) && (ifa->strictnbma))
139
      {
140
        log(L_WARN "Ignoring new neighbor: %I on %s.", faddr,
141
            ifa->iface->name);
142
        return;
143
      }
144
      if (found)
145
      {
146
        eligible = nn->eligible;
147
        if (((ps->priority == 0) && eligible)
148
            || ((ps->priority > 0) && (eligible == 0)))
149
        {
150
          log(L_ERR "Eligibility mismatch for neighbor: %I on %s",
151
              faddr, ifa->iface->name);
152
          return;
153
        }
154
      }
155
    }
156
    OSPF_TRACE(D_EVENTS, "New neighbor found: %I on %s.", faddr,
157
               ifa->iface->name);
158

    
159
    n = ospf_neighbor_new(ifa);
160

    
161
    n->rid = ntohl(((struct ospf_packet *) ps)->routerid);
162
    n->ip = faddr;
163
    n->dr = ntohl(ps->dr);
164
    n->bdr = ntohl(ps->bdr);
165
    n->priority = ps->priority;
166
#ifdef OSPFv3
167
    n->iface_id = ntohl(ps->iface_id);
168
#endif
169
  }
170
  ospf_neigh_sm(n, INM_HELLOREC);
171

    
172
  pnrid = (u32 *) ((struct ospf_hello_packet *) (ps + 1));
173

    
174
  peers = (size - sizeof(struct ospf_hello_packet))/ sizeof(u32);
175

    
176
  twoway = 0;
177
  for (i = 0; i < peers; i++)
178
  {
179
    if (ntohl(pnrid[i]) == po->router_id)
180
    {
181
      DBG("%s: Twoway received from %I\n", p->name, faddr);
182
      ospf_neigh_sm(n, INM_2WAYREC);
183
      twoway = 1;
184
      break;
185
    }
186
  }
187

    
188
  if (!twoway)
189
    ospf_neigh_sm(n, INM_1WAYREC);
190

    
191
  u32 olddr = n->dr;
192
  u32 oldbdr = n->bdr;
193
  u32 oldpriority = n->priority;
194
#ifdef OSPFv3
195
  u32 oldiface_id = n->iface_id;
196
#endif
197

    
198
  n->dr = ntohl(ps->dr);
199
  n->bdr = ntohl(ps->bdr);
200
  n->priority = ps->priority;
201
#ifdef OSPFv3
202
  n->iface_id = ntohl(ps->iface_id);
203
#endif
204

    
205

    
206
  /* Check priority change */
207
  if (n->state >= NEIGHBOR_2WAY)
208
  {
209
#ifdef OSPFv2
210
    u32 neigh = ipa_to_u32(n->ip);
211
#else /* OSPFv3 */
212
    u32 neigh = n->rid;
213
#endif
214

    
215
    if (n->priority != oldpriority)
216
      ospf_iface_sm(ifa, ISM_NEICH);
217

    
218
#ifdef OSPFv3
219
    if (n->iface_id != oldiface_id)
220
      ospf_iface_sm(ifa, ISM_NEICH);
221
#endif
222

    
223
    /* Neighbor is declaring itself ad DR and there is no BDR */
224
    if ((n->dr == neigh) && (n->bdr == 0)
225
        && (n->state != NEIGHBOR_FULL))
226
      ospf_iface_sm(ifa, ISM_BACKS);
227

    
228
    /* Neighbor is declaring itself as BDR */
229
    if ((n->bdr == neigh) && (n->state != NEIGHBOR_FULL))
230
      ospf_iface_sm(ifa, ISM_BACKS);
231

    
232
    /* Neighbor is newly declaring itself as DR or BDR */
233
    if (((n->dr == neigh) && (n->dr != olddr))
234
        || ((n->bdr == neigh) && (n->bdr != oldbdr)))
235
      ospf_iface_sm(ifa, ISM_NEICH);
236

    
237
    /* Neighbor is no more declaring itself as DR or BDR */
238
    if (((olddr == neigh) && (n->dr != olddr))
239
        || ((oldbdr == neigh) && (n->bdr != oldbdr)))
240
      ospf_iface_sm(ifa, ISM_NEICH);
241
  }
242

    
243
  if (ifa->type == OSPF_IT_NBMA)
244
  {
245
    if ((ifa->priority == 0) && (n->priority > 0))
246
      ospf_hello_send(NULL, 0, n);
247
  }
248
  ospf_neigh_sm(n, INM_HELLOREC);
249
}
250

    
251
void
252
ospf_hello_send(timer *timer, int poll, struct ospf_neighbor *dirn)
253
{
254
  struct ospf_iface *ifa;
255
  struct ospf_hello_packet *pkt;
256
  struct ospf_packet *op;
257
  struct proto *p;
258
  struct ospf_neighbor *neigh, *n1;
259
  u16 length;
260
  u32 *pp;
261
  int i, send;
262
  struct nbma_node *nb;
263

    
264
  if (timer == NULL)
265
    ifa = dirn->ifa;
266
  else
267
    ifa = (struct ospf_iface *) timer->data;
268

    
269
  if (ifa->state == OSPF_IS_DOWN)
270
    return;
271

    
272
  if (ifa->stub)
273
    return;                        /* Don't send any packet on stub iface */
274

    
275
  p = (struct proto *) (ifa->oa->po);
276
  DBG("%s: Hello/Poll timer fired on interface %s.\n",
277
      p->name, ifa->iface->name);
278

    
279
  /* Now we should send a hello packet */
280
  pkt = (struct ospf_hello_packet *) (ifa->sk->tbuf);
281
  op = (struct ospf_packet *) pkt;
282

    
283
  /* Now fill ospf_hello header */
284
  ospf_pkt_fill_hdr(ifa, pkt, HELLO_P);
285

    
286
#ifdef OSPFv2
287
  pkt->netmask = ipa_mkmask(ifa->iface->addr->pxlen);
288
  ipa_hton(pkt->netmask);
289
  if ((ifa->type == OSPF_IT_VLINK) || (ifa->type == OSPF_IT_PTP))
290
    pkt->netmask = IPA_NONE;
291
#endif
292

    
293
  pkt->helloint = ntohs(ifa->helloint);
294
  pkt->priority = ifa->priority;
295

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

    
299
  pkt->options3 = ifa->oa->options >> 16;
300
  pkt->options2 = ifa->oa->options >> 8;
301
#endif
302
  pkt->options = ifa->oa->options;
303

    
304
#ifdef OSPFv2
305
  pkt->deadint = htonl(ifa->dead);
306
  pkt->dr = htonl(ipa_to_u32(ifa->drip));
307
  pkt->bdr = htonl(ipa_to_u32(ifa->bdrip));
308
#else /* OSPFv3 */
309
  pkt->deadint = htons(ifa->dead);
310
  pkt->dr = htonl(ifa->drid);
311
  pkt->bdr = htonl(ifa->bdrid);
312
#endif
313

    
314
  /* Fill all neighbors */
315
  i = 0;
316
  pp = (u32 *) (((u8 *) pkt) + sizeof(struct ospf_hello_packet));
317
  WALK_LIST(neigh, ifa->neigh_list)
318
  {
319
    if ((i+1) * sizeof(u32) + sizeof(struct ospf_hello_packet) > ospf_pkt_maxsize(ifa))
320
    {
321
      OSPF_TRACE(D_PACKETS, "Too many neighbors on the interface!");
322
      break;
323
    }
324
    *(pp + i) = htonl(neigh->rid);
325
    i++;
326
  }
327

    
328
  length = sizeof(struct ospf_hello_packet) + i * sizeof(u32);
329
  op->length = htons(length);
330

    
331
  switch(ifa->type)
332
  {
333
    case OSPF_IT_NBMA:
334
      if (timer == NULL)                /* Response to received hello */
335
      {
336
        ospf_send_to(ifa, dirn->ip);
337
      }
338
      else
339
      {
340
        int toall = 0;
341
        int meeli = 0;
342
        if (ifa->state > OSPF_IS_DROTHER)
343
          toall = 1;
344
        if (ifa->priority > 0)
345
          meeli = 1;
346
 
347
        WALK_LIST(nb, ifa->nbma_list)
348
        {
349
          send = 1;
350
          WALK_LIST(n1, ifa->neigh_list)
351
          {
352
            if (ipa_equal(nb->ip, n1->ip))
353
            {
354
              send = 0;
355
              break;
356
            }
357
          }
358
          if ((poll == 1) && (send))
359
          {
360
            if (toall || (meeli && nb->eligible))
361
              ospf_send_to(ifa, nb->ip);
362
          }
363
        }
364
        if (poll == 0)
365
        {
366
          WALK_LIST(n1, ifa->neigh_list)
367
          {
368
            if (toall || (n1->rid == ifa->drid) || (n1->rid == ifa->bdrid) ||
369
                (meeli && (n1->priority > 0)))
370
              ospf_send_to(ifa, n1->ip);
371
          }
372
        }
373
      }
374
      break;
375
    case OSPF_IT_VLINK:
376
      ospf_send_to(ifa, ifa->vip);
377
      break;
378
    default:
379
      ospf_send_to(ifa, AllSPFRouters);
380
  }
381

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