Statistics
| Branch: | Revision:

iof-bird-daemon / proto / ospf / hello.c @ 8df02847

History | View | Annotate | Download (8.11 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 = "OSPF: Bad HELLO packet from ";
51
  unsigned int size, i, twoway, 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
      (ifa->type != OSPF_IT_PTP) &&
72
      !ipa_equal(mask, ipa_mkmask(ifa->addr->pxlen)))
73
  {
74
    log(L_ERR "%s%I - netmask mismatch (%I)", beg, faddr, mask);
75
    return;
76
  }
77
#endif
78

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

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

    
97
  /* Check whether bits E, N match */
98
  if ((ps->options ^ ifa->oa->options) & (OPT_E | OPT_N))
99
  {
100
    log(L_ERR "%s%I - area type mismatch (%x)", beg, faddr, ps->options);
101
    return;
102
  }
103

    
104
  if (!n)
105
  {
106
    if ((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP))
107
    {
108
      struct nbma_node *nn = find_nbma_node(ifa, faddr);
109

    
110
      if (!nn && ifa->strictnbma)
111
      {
112
        log(L_WARN "Ignoring new neighbor: %I on %s", faddr,
113
            ifa->iface->name);
114
        return;
115
      }
116

    
117
      if (nn && (ifa->type == OSPF_IT_NBMA) &&
118
          (((ps->priority == 0) && nn->eligible) ||
119
           ((ps->priority > 0) && !nn->eligible)))
120
      {
121
        log(L_ERR "Eligibility mismatch for neighbor: %I on %s",
122
            faddr, ifa->iface->name);
123
        return;
124
      }
125

    
126
      if (nn)
127
        nn->found = 1;
128
    }
129

    
130
    OSPF_TRACE(D_EVENTS, "New neighbor found: %I on %s", faddr,
131
               ifa->iface->name);
132

    
133
    n = ospf_neighbor_new(ifa);
134

    
135
    n->rid = ntohl(((struct ospf_packet *) ps)->routerid);
136
    n->ip = faddr;
137
    n->dr = ntohl(ps->dr);
138
    n->bdr = ntohl(ps->bdr);
139
    n->priority = ps->priority;
140
#ifdef OSPFv3
141
    n->iface_id = ntohl(ps->iface_id);
142
#endif
143
  }
144
  ospf_neigh_sm(n, INM_HELLOREC);
145

    
146
  pnrid = (u32 *) ((struct ospf_hello_packet *) (ps + 1));
147

    
148
  peers = (size - sizeof(struct ospf_hello_packet))/ sizeof(u32);
149

    
150
  twoway = 0;
151
  for (i = 0; i < peers; i++)
152
  {
153
    if (ntohl(pnrid[i]) == po->router_id)
154
    {
155
      DBG("%s: Twoway received from %I\n", p->name, faddr);
156
      ospf_neigh_sm(n, INM_2WAYREC);
157
      twoway = 1;
158
      break;
159
    }
160
  }
161

    
162
  if (!twoway)
163
    ospf_neigh_sm(n, INM_1WAYREC);
164

    
165
  u32 olddr = n->dr;
166
  u32 oldbdr = n->bdr;
167
  u32 oldpriority = n->priority;
168
#ifdef OSPFv3
169
  u32 oldiface_id = n->iface_id;
170
#endif
171

    
172
  n->dr = ntohl(ps->dr);
173
  n->bdr = ntohl(ps->bdr);
174
  n->priority = ps->priority;
175
#ifdef OSPFv3
176
  n->iface_id = ntohl(ps->iface_id);
177
#endif
178

    
179

    
180
  /* Check priority change */
181
  if (n->state >= NEIGHBOR_2WAY)
182
  {
183
#ifdef OSPFv2
184
    u32 neigh = ipa_to_u32(n->ip);
185
#else /* OSPFv3 */
186
    u32 neigh = n->rid;
187
#endif
188

    
189
    if (n->priority != oldpriority)
190
      ospf_iface_sm(ifa, ISM_NEICH);
191

    
192
#ifdef OSPFv3
193
    if (n->iface_id != oldiface_id)
194
      ospf_iface_sm(ifa, ISM_NEICH);
195
#endif
196

    
197
    /* Neighbor is declaring itself ad DR and there is no BDR */
198
    if ((n->dr == neigh) && (n->bdr == 0)
199
        && (n->state != NEIGHBOR_FULL))
200
      ospf_iface_sm(ifa, ISM_BACKS);
201

    
202
    /* Neighbor is declaring itself as BDR */
203
    if ((n->bdr == neigh) && (n->state != NEIGHBOR_FULL))
204
      ospf_iface_sm(ifa, ISM_BACKS);
205

    
206
    /* Neighbor is newly declaring itself as DR or BDR */
207
    if (((n->dr == neigh) && (n->dr != olddr))
208
        || ((n->bdr == neigh) && (n->bdr != oldbdr)))
209
      ospf_iface_sm(ifa, ISM_NEICH);
210

    
211
    /* Neighbor is no more declaring itself as DR or BDR */
212
    if (((olddr == neigh) && (n->dr != olddr))
213
        || ((oldbdr == neigh) && (n->bdr != oldbdr)))
214
      ospf_iface_sm(ifa, ISM_NEICH);
215
  }
216

    
217
  if (ifa->type == OSPF_IT_NBMA)
218
  {
219
    if ((ifa->priority == 0) && (n->priority > 0))
220
      ospf_hello_send(n->ifa, OHS_HELLO, n);
221
  }
222
  ospf_neigh_sm(n, INM_HELLOREC);
223
}
224

    
225
void
226
ospf_hello_send(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn)
227
{
228
  struct ospf_hello_packet *pkt;
229
  struct ospf_packet *op;
230
  struct proto *p;
231
  struct ospf_neighbor *neigh, *n1;
232
  u16 length;
233
  int i;
234
  struct nbma_node *nb;
235

    
236
  if (ifa->state <= OSPF_IS_LOOP)
237
    return;
238

    
239
  if (ifa->stub)
240
    return;                        /* Don't send any packet on stub iface */
241

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

    
246
  /* Now we should send a hello packet */
247
  pkt = ospf_tx_buffer(ifa);
248
  op = &pkt->ospf_packet;
249

    
250
  /* Now fill ospf_hello header */
251
  ospf_pkt_fill_hdr(ifa, pkt, HELLO_P);
252

    
253
#ifdef OSPFv2
254
  pkt->netmask = ipa_mkmask(ifa->addr->pxlen);
255
  ipa_hton(pkt->netmask);
256
  if ((ifa->type == OSPF_IT_VLINK) ||
257
      ((ifa->type == OSPF_IT_PTP) && !ifa->ptp_netmask))
258
    pkt->netmask = IPA_NONE;
259
#endif
260

    
261
  pkt->helloint = ntohs(ifa->helloint);
262
  pkt->priority = ifa->priority;
263

    
264
#ifdef OSPFv3
265
  pkt->iface_id = htonl(ifa->iface_id);
266

    
267
  pkt->options3 = ifa->oa->options >> 16;
268
  pkt->options2 = ifa->oa->options >> 8;
269
#endif
270
  pkt->options = ifa->oa->options;
271

    
272
#ifdef OSPFv2
273
  pkt->deadint = htonl(ifa->deadint);
274
  pkt->dr = htonl(ipa_to_u32(ifa->drip));
275
  pkt->bdr = htonl(ipa_to_u32(ifa->bdrip));
276
#else /* OSPFv3 */
277
  pkt->deadint = htons(ifa->deadint);
278
  pkt->dr = htonl(ifa->drid);
279
  pkt->bdr = htonl(ifa->bdrid);
280
#endif
281

    
282
  /* Fill all neighbors */
283
  i = 0;
284

    
285
  if (kind != OHS_SHUTDOWN)
286
  {
287
    u32 *pp = (u32 *) (((u8 *) pkt) + sizeof(struct ospf_hello_packet));
288
    WALK_LIST(neigh, ifa->neigh_list)
289
    {
290
      if ((i+1) * sizeof(u32) + sizeof(struct ospf_hello_packet) > ospf_pkt_bufsize(ifa))
291
      {
292
        log(L_WARN "%s: Too many neighbors on interface %s", p->name, ifa->iface->name);
293
        break;
294
      }
295
      *(pp + i) = htonl(neigh->rid);
296
      i++;
297
    }
298
  }
299

    
300
  length = sizeof(struct ospf_hello_packet) + i * sizeof(u32);
301
  op->length = htons(length);
302

    
303
  switch(ifa->type)
304
  {
305
  case OSPF_IT_BCAST:
306
  case OSPF_IT_PTP:
307
    ospf_send_to_all(ifa);
308
    break;
309

    
310
  case OSPF_IT_NBMA:
311
    if (dirn)                /* Response to received hello */
312
    {
313
      ospf_send_to(ifa, dirn->ip);
314
      break;
315
    }
316

    
317
    int to_all = ifa->state > OSPF_IS_DROTHER;
318
    int me_elig = ifa->priority > 0;
319
 
320
    if (kind == OHS_POLL)        /* Poll timer */
321
    {
322
      WALK_LIST(nb, ifa->nbma_list)
323
        if (!nb->found && (to_all || (me_elig && nb->eligible)))
324
          ospf_send_to(ifa, nb->ip);
325
    }
326
    else                        /* Hello timer */
327
    {
328
      WALK_LIST(n1, ifa->neigh_list)
329
        if (to_all || (me_elig && (n1->priority > 0)) ||
330
            (n1->rid == ifa->drid) || (n1->rid == ifa->bdrid))
331
          ospf_send_to(ifa, n1->ip);
332
    }
333
    break;
334

    
335
  case OSPF_IT_PTMP:
336
    WALK_LIST(n1, ifa->neigh_list)
337
      ospf_send_to(ifa, n1->ip);
338

    
339
    WALK_LIST(nb, ifa->nbma_list)
340
      if (!nb->found)
341
        ospf_send_to(ifa, nb->ip);
342

    
343
    /* If there is no other target, we also send HELLO packet to the other end */
344
    if (ipa_nonzero(ifa->addr->opposite) && !ifa->strictnbma &&
345
        EMPTY_LIST(ifa->neigh_list) && EMPTY_LIST(ifa->nbma_list))
346
      ospf_send_to(ifa, ifa->addr->opposite);
347
    break;
348

    
349
  case OSPF_IT_VLINK:
350
    ospf_send_to(ifa, ifa->vip);
351
    break;
352

    
353
  default:
354
    bug("Bug in ospf_hello_send()");
355
  }
356

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