]> git.ipfire.org Git - thirdparty/bird.git/blame - proto/ospf/hello.c
Many changes in I/O and OSPF sockets and packet handling.
[thirdparty/bird.git] / proto / ospf / hello.c
CommitLineData
4364b47e
OF
1/*
2 * BIRD -- OSPF
3 *
bc4ea680 4 * (c) 1999--2004 Ondrej Filip <feela@network.cz>
4364b47e
OF
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 */
8
9#include "ospf.h"
10
c3226991
OZ
11
12#ifdef OSPFv2
13struct 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
28struct 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
4364b47e 44void
c3226991
OZ
45ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
46 struct ospf_neighbor *n, ip_addr faddr)
4364b47e 47{
8a70a13e
OZ
48 struct proto_ospf *po = ifa->oa->po;
49 struct proto *p = &po->proto;
353729f5 50 char *beg = "OSPF: Bad HELLO packet from ";
919f5411 51 unsigned int size, i, twoway, peers;
e81b440f 52 u32 tmp;
a6bc04d5
OZ
53 u32 *pnrid;
54
55 size = ntohs(ps_i->length);
56 if (size < sizeof(struct ospf_hello_packet))
57 {
353729f5 58 log(L_ERR "%s%I - too short (%u B)", beg, faddr, size);
a6bc04d5
OZ
59 return;
60 }
61
62 struct ospf_hello_packet *ps = (void *) ps_i;
4364b47e 63
48e5f32d 64 OSPF_TRACE(D_PACKETS, "HELLO packet received from %I via %s", faddr, ifa->ifname);
c3226991
OZ
65
66#ifdef OSPFv2
f9c799a0 67 ip_addr mask = ps->netmask;
099c017f 68 ipa_ntoh(mask);
353729f5
OZ
69 if ((ifa->type != OSPF_IT_VLINK) &&
70 (ifa->type != OSPF_IT_PTP) &&
71 !ipa_equal(mask, ipa_mkmask(ifa->addr->pxlen)))
72 {
73 log(L_ERR "%s%I - netmask mismatch (%I)", beg, faddr, mask);
74 return;
75 }
c3226991 76#endif
77539c44 77
c3226991
OZ
78 tmp = ntohs(ps->helloint);
79 if (tmp != ifa->helloint)
4364b47e 80 {
353729f5 81 log(L_ERR "%s%I - hello interval mismatch (%d)", beg, faddr, tmp);
4364b47e
OF
82 return;
83 }
84
c3226991
OZ
85#ifdef OSPFv2
86 tmp = ntohl(ps->deadint);
87#else /* OSPFv3 */
88 tmp = ntohs(ps->deadint);
89#endif
8e48831a 90 if (tmp != ifa->deadint)
4364b47e 91 {
353729f5 92 log(L_ERR "%s%I - dead interval mismatch (%d)", beg, faddr, tmp);
4364b47e
OF
93 return;
94 }
95
41b612c3
OZ
96 /* Check whether bits E, N match */
97 if ((ps->options ^ ifa->oa->options) & (OPT_E | OPT_N))
4364b47e 98 {
41b612c3 99 log(L_ERR "%s%I - area type mismatch (%x)", beg, faddr, ps->options);
4364b47e
OF
100 return;
101 }
102
e550a372
OF
103#ifdef OSPFv2
104 if (n && (n->rid != ntohl(ps_i->routerid)))
105 {
106 OSPF_TRACE(D_EVENTS,
107 "Neighbor %I has changed router id from %R to %R.",
108 n->ip, n->rid, ntohl(ps_i->routerid));
109 ospf_neigh_remove(n);
110 n = NULL;
111 }
112#endif
113
5e3436d2 114 if (!n)
4364b47e 115 {
919f5411 116 if ((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP))
a190e720 117 {
919f5411 118 struct nbma_node *nn = find_nbma_node(ifa, faddr);
a190e720 119
919f5411 120 if (!nn && ifa->strictnbma)
a190e720 121 {
48e5f32d 122 log(L_WARN "Ignoring new neighbor: %I on %s", faddr, ifa->ifname);
a190e720
OF
123 return;
124 }
919f5411
OZ
125
126 if (nn && (ifa->type == OSPF_IT_NBMA) &&
127 (((ps->priority == 0) && nn->eligible) ||
128 ((ps->priority > 0) && !nn->eligible)))
a190e720 129 {
48e5f32d 130 log(L_ERR "Eligibility mismatch for neighbor: %I on %s", faddr, ifa->ifname);
919f5411 131 return;
a190e720 132 }
919f5411
OZ
133
134 if (nn)
135 nn->found = 1;
a190e720 136 }
919f5411 137
48e5f32d 138 OSPF_TRACE(D_EVENTS, "New neighbor found: %I on %s", faddr, ifa->ifname);
39e517d4
OF
139
140 n = ospf_neighbor_new(ifa);
141
e550a372 142 n->rid = ntohl(ps_i->routerid);
77539c44 143 n->ip = faddr;
c3226991
OZ
144 n->dr = ntohl(ps->dr);
145 n->bdr = ntohl(ps->bdr);
77539c44 146 n->priority = ps->priority;
c3226991
OZ
147#ifdef OSPFv3
148 n->iface_id = ntohl(ps->iface_id);
149#endif
1ec52253
OZ
150
151 if (n->ifa->cf->bfd)
152 ospf_neigh_update_bfd(n, n->ifa->bfd);
4364b47e 153 }
33be3ba7
OZ
154#ifdef OSPFv3 /* NOTE: this could also be relevant for OSPFv2 on PtP ifaces */
155 else if (!ipa_equal(faddr, n->ip))
156 {
157 OSPF_TRACE(D_EVENTS, "Neighbor address changed from %I to %I", n->ip, faddr);
158 n->ip = faddr;
159 }
160#endif
161
4364b47e
OF
162 ospf_neigh_sm(n, INM_HELLOREC);
163
77539c44 164 pnrid = (u32 *) ((struct ospf_hello_packet *) (ps + 1));
4364b47e 165
bc4ea680
OF
166 peers = (size - sizeof(struct ospf_hello_packet))/ sizeof(u32);
167
77539c44 168 twoway = 0;
bc4ea680 169 for (i = 0; i < peers; i++)
4364b47e 170 {
8a70a13e 171 if (ntohl(pnrid[i]) == po->router_id)
4364b47e 172 {
31dca435 173 DBG("%s: Twoway received from %I\n", p->name, faddr);
4364b47e 174 ospf_neigh_sm(n, INM_2WAYREC);
77539c44 175 twoway = 1;
4364b47e
OF
176 break;
177 }
178 }
179
77539c44
OF
180 if (!twoway)
181 ospf_neigh_sm(n, INM_1WAYREC);
4364b47e 182
e81b440f
OZ
183 u32 olddr = n->dr;
184 u32 oldbdr = n->bdr;
185 u32 oldpriority = n->priority;
c3226991 186#ifdef OSPFv3
e81b440f 187 u32 oldiface_id = n->iface_id;
c3226991
OZ
188#endif
189
190 n->dr = ntohl(ps->dr);
191 n->bdr = ntohl(ps->bdr);
b29c620f 192 n->priority = ps->priority;
c3226991
OZ
193#ifdef OSPFv3
194 n->iface_id = ntohl(ps->iface_id);
195#endif
196
b29c620f 197
4364b47e 198 /* Check priority change */
77539c44 199 if (n->state >= NEIGHBOR_2WAY)
4364b47e 200 {
c3226991 201#ifdef OSPFv2
8a70a13e 202 u32 neigh = ipa_to_u32(n->ip);
c3226991 203#else /* OSPFv3 */
8a70a13e 204 u32 neigh = n->rid;
c3226991
OZ
205#endif
206
77539c44 207 if (n->priority != oldpriority)
a5918961 208 ospf_iface_sm(ifa, ISM_NEICH);
4364b47e 209
c3226991
OZ
210#ifdef OSPFv3
211 if (n->iface_id != oldiface_id)
212 ospf_iface_sm(ifa, ISM_NEICH);
213#endif
214
8a70a13e
OZ
215 /* Neighbor is declaring itself ad DR and there is no BDR */
216 if ((n->dr == neigh) && (n->bdr == 0)
77539c44 217 && (n->state != NEIGHBOR_FULL))
a5918961 218 ospf_iface_sm(ifa, ISM_BACKS);
4364b47e 219
b29c620f 220 /* Neighbor is declaring itself as BDR */
8a70a13e 221 if ((n->bdr == neigh) && (n->state != NEIGHBOR_FULL))
a5918961 222 ospf_iface_sm(ifa, ISM_BACKS);
b29c620f
OF
223
224 /* Neighbor is newly declaring itself as DR or BDR */
8a70a13e
OZ
225 if (((n->dr == neigh) && (n->dr != olddr))
226 || ((n->bdr == neigh) && (n->bdr != oldbdr)))
a5918961 227 ospf_iface_sm(ifa, ISM_NEICH);
b29c620f
OF
228
229 /* Neighbor is no more declaring itself as DR or BDR */
8a70a13e
OZ
230 if (((olddr == neigh) && (n->dr != olddr))
231 || ((oldbdr == neigh) && (n->bdr != oldbdr)))
a5918961 232 ospf_iface_sm(ifa, ISM_NEICH);
4364b47e 233 }
4364b47e 234
3b16080c 235 if (ifa->type == OSPF_IT_NBMA)
a190e720 236 {
77539c44 237 if ((ifa->priority == 0) && (n->priority > 0))
beeda6af 238 ospf_hello_send(n->ifa, OHS_HELLO, n);
a190e720 239 }
4364b47e
OF
240 ospf_neigh_sm(n, INM_HELLOREC);
241}
242
a190e720 243void
beeda6af 244ospf_hello_send(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn)
4364b47e 245{
4364b47e
OF
246 struct ospf_hello_packet *pkt;
247 struct ospf_packet *op;
248 struct proto *p;
98ac6176 249 struct ospf_neighbor *neigh, *n1;
4364b47e 250 u16 length;
919f5411 251 int i;
98ac6176 252 struct nbma_node *nb;
86c84d76 253
391931d4 254 if (ifa->state <= OSPF_IS_LOOP)
98ac6176
OF
255 return;
256
77539c44
OF
257 if (ifa->stub)
258 return; /* Don't send any packet on stub iface */
e3bc10fd 259
86c84d76 260 p = (struct proto *) (ifa->oa->po);
0aad2b92 261 DBG("%s: Hello/Poll timer fired on interface %s with IP %I\n",
48e5f32d 262 p->name, ifa->ifname, ifa->addr->ip);
4364b47e 263
f9c799a0 264 /* Now we should send a hello packet */
e7b76b97 265 pkt = ospf_tx_buffer(ifa);
353729f5 266 op = &pkt->ospf_packet;
4364b47e 267
f9c799a0 268 /* Now fill ospf_hello header */
3e2bd0f1 269 ospf_pkt_fill_hdr(ifa, pkt, HELLO_P);
e5b5d18c 270
c3226991 271#ifdef OSPFv2
353729f5 272 pkt->netmask = ipa_mkmask(ifa->addr->pxlen);
e5b5d18c 273 ipa_hton(pkt->netmask);
8df02847
OZ
274 if ((ifa->type == OSPF_IT_VLINK) ||
275 ((ifa->type == OSPF_IT_PTP) && !ifa->ptp_netmask))
f571473e 276 pkt->netmask = IPA_NONE;
c3226991
OZ
277#endif
278
77539c44 279 pkt->helloint = ntohs(ifa->helloint);
77539c44 280 pkt->priority = ifa->priority;
c3226991
OZ
281
282#ifdef OSPFv3
dd4da6f6 283 pkt->iface_id = htonl(ifa->iface_id);
c3226991
OZ
284
285 pkt->options3 = ifa->oa->options >> 16;
286 pkt->options2 = ifa->oa->options >> 8;
287#endif
288 pkt->options = ifa->oa->options;
289
290#ifdef OSPFv2
8e48831a 291 pkt->deadint = htonl(ifa->deadint);
c3226991
OZ
292 pkt->dr = htonl(ipa_to_u32(ifa->drip));
293 pkt->bdr = htonl(ipa_to_u32(ifa->bdrip));
294#else /* OSPFv3 */
8e48831a 295 pkt->deadint = htons(ifa->deadint);
c3226991
OZ
296 pkt->dr = htonl(ifa->drid);
297 pkt->bdr = htonl(ifa->bdrid);
298#endif
e5b5d18c
OF
299
300 /* Fill all neighbors */
77539c44 301 i = 0;
8e48831a
OZ
302
303 if (kind != OHS_SHUTDOWN)
e5b5d18c 304 {
8e48831a
OZ
305 u32 *pp = (u32 *) (((u8 *) pkt) + sizeof(struct ospf_hello_packet));
306 WALK_LIST(neigh, ifa->neigh_list)
3e2bd0f1 307 {
48e5f32d 308 if ((i+1) * sizeof(u32) + sizeof(struct ospf_hello_packet) > ospf_pkt_maxsize(ifa))
8e48831a 309 {
48e5f32d 310 log(L_WARN "%s: Too many neighbors on interface %s", p->name, ifa->ifname);
8e48831a
OZ
311 break;
312 }
313 *(pp + i) = htonl(neigh->rid);
314 i++;
3e2bd0f1 315 }
e5b5d18c
OF
316 }
317
77539c44
OF
318 length = sizeof(struct ospf_hello_packet) + i * sizeof(u32);
319 op->length = htons(length);
e5b5d18c 320
98ac6176 321 switch(ifa->type)
e5b5d18c 322 {
919f5411
OZ
323 case OSPF_IT_BCAST:
324 case OSPF_IT_PTP:
95127cbb 325 ospf_send_to_all(ifa);
919f5411
OZ
326 break;
327
328 case OSPF_IT_NBMA:
beeda6af 329 if (dirn) /* Response to received hello */
919f5411
OZ
330 {
331 ospf_send_to(ifa, dirn->ip);
98ac6176 332 break;
919f5411
OZ
333 }
334
335 int to_all = ifa->state > OSPF_IS_DROTHER;
336 int me_elig = ifa->priority > 0;
337
8e48831a 338 if (kind == OHS_POLL) /* Poll timer */
919f5411
OZ
339 {
340 WALK_LIST(nb, ifa->nbma_list)
341 if (!nb->found && (to_all || (me_elig && nb->eligible)))
342 ospf_send_to(ifa, nb->ip);
343 }
344 else /* Hello timer */
345 {
346 WALK_LIST(n1, ifa->neigh_list)
347 if (to_all || (me_elig && (n1->priority > 0)) ||
348 (n1->rid == ifa->drid) || (n1->rid == ifa->bdrid))
349 ospf_send_to(ifa, n1->ip);
350 }
351 break;
352
353 case OSPF_IT_PTMP:
354 WALK_LIST(n1, ifa->neigh_list)
355 ospf_send_to(ifa, n1->ip);
356
357 WALK_LIST(nb, ifa->nbma_list)
358 if (!nb->found)
359 ospf_send_to(ifa, nb->ip);
360
361 /* If there is no other target, we also send HELLO packet to the other end */
362 if (ipa_nonzero(ifa->addr->opposite) && !ifa->strictnbma &&
363 EMPTY_LIST(ifa->neigh_list) && EMPTY_LIST(ifa->nbma_list))
364 ospf_send_to(ifa, ifa->addr->opposite);
365 break;
366
367 case OSPF_IT_VLINK:
368 ospf_send_to(ifa, ifa->vip);
369 break;
370
371 default:
372 bug("Bug in ospf_hello_send()");
e5b5d18c 373 }
8298d780 374
48e5f32d 375 OSPF_TRACE(D_PACKETS, "HELLO packet sent via %s", ifa->ifname);
4364b47e 376}