]> git.ipfire.org Git - thirdparty/bird.git/blame - proto/ospf/hello.c
Temporary OSPF commit - socket changes.
[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 ";
a6bc04d5 51 unsigned int size, i, twoway, oldpriority, eligible, peers;
c3226991 52 u32 olddr, oldbdr, oldiface_id, 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
8298d780 64 OSPF_TRACE(D_PACKETS, "HELLO packet received from %I via %s%s", faddr,
3b16080c 65 (ifa->type == OSPF_IT_VLINK ? "vlink-" : ""), ifa->iface->name);
c3226991
OZ
66
67#ifdef OSPFv2
f9c799a0 68 ip_addr mask = ps->netmask;
099c017f 69 ipa_ntoh(mask);
353729f5
OZ
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 }
c3226991 77#endif
77539c44 78
c3226991
OZ
79 tmp = ntohs(ps->helloint);
80 if (tmp != ifa->helloint)
4364b47e 81 {
353729f5 82 log(L_ERR "%s%I - hello interval mismatch (%d)", beg, faddr, tmp);
4364b47e
OF
83 return;
84 }
85
c3226991
OZ
86#ifdef OSPFv2
87 tmp = ntohl(ps->deadint);
88#else /* OSPFv3 */
89 tmp = ntohs(ps->deadint);
90#endif
91 if (tmp != ifa->dead)
4364b47e 92 {
353729f5 93 log(L_ERR "%s%I - dead interval mismatch (%d)", beg, faddr, tmp);
4364b47e
OF
94 return;
95 }
96
c3226991
OZ
97 tmp = !(ps->options & OPT_E);
98 if (tmp != ifa->oa->stub)
4364b47e 99 {
353729f5 100 log(L_ERR "%s%I - stub area flag mismatch (%d)", beg, faddr, tmp);
4364b47e
OF
101 return;
102 }
103
5e3436d2 104 if (!n)
4364b47e 105 {
77539c44 106 if ((ifa->type == OSPF_IT_NBMA))
a190e720
OF
107 {
108 struct nbma_node *nn;
77539c44 109 int found = 0;
a190e720 110
77539c44 111 WALK_LIST(nn, ifa->nbma_list)
a190e720 112 {
a417ad13 113 if (ipa_equal(faddr, nn->ip))
a190e720 114 {
77539c44 115 found = 1;
a190e720
OF
116 break;
117 }
118 }
77539c44 119 if ((found == 0) && (ifa->strictnbma))
a190e720 120 {
353729f5 121 log(L_WARN "Ignoring new neighbor: %I on %s", faddr,
77539c44 122 ifa->iface->name);
a190e720
OF
123 return;
124 }
77539c44 125 if (found)
a190e720 126 {
77539c44
OF
127 eligible = nn->eligible;
128 if (((ps->priority == 0) && eligible)
129 || ((ps->priority > 0) && (eligible == 0)))
130 {
131 log(L_ERR "Eligibility mismatch for neighbor: %I on %s",
132 faddr, ifa->iface->name);
a190e720 133 return;
77539c44 134 }
a190e720
OF
135 }
136 }
353729f5 137 OSPF_TRACE(D_EVENTS, "New neighbor found: %I on %s", faddr,
77539c44 138 ifa->iface->name);
39e517d4
OF
139
140 n = ospf_neighbor_new(ifa);
141
5e3436d2 142 n->rid = ntohl(((struct ospf_packet *) ps)->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
4364b47e
OF
150 }
151 ospf_neigh_sm(n, INM_HELLOREC);
152
77539c44 153 pnrid = (u32 *) ((struct ospf_hello_packet *) (ps + 1));
4364b47e 154
bc4ea680
OF
155 peers = (size - sizeof(struct ospf_hello_packet))/ sizeof(u32);
156
77539c44 157 twoway = 0;
bc4ea680 158 for (i = 0; i < peers; i++)
4364b47e 159 {
8a70a13e 160 if (ntohl(pnrid[i]) == po->router_id)
4364b47e 161 {
31dca435 162 DBG("%s: Twoway received from %I\n", p->name, faddr);
4364b47e 163 ospf_neigh_sm(n, INM_2WAYREC);
77539c44 164 twoway = 1;
4364b47e
OF
165 break;
166 }
167 }
168
77539c44
OF
169 if (!twoway)
170 ospf_neigh_sm(n, INM_1WAYREC);
4364b47e 171
b29c620f 172 olddr = n->dr;
b29c620f 173 oldbdr = n->bdr;
b29c620f 174 oldpriority = n->priority;
c3226991
OZ
175#ifdef OSPFv3
176 oldiface_id = n->iface_id;
177#endif
178
179 n->dr = ntohl(ps->dr);
180 n->bdr = ntohl(ps->bdr);
b29c620f 181 n->priority = ps->priority;
c3226991
OZ
182#ifdef OSPFv3
183 n->iface_id = ntohl(ps->iface_id);
184#endif
185
b29c620f 186
4364b47e 187 /* Check priority change */
77539c44 188 if (n->state >= NEIGHBOR_2WAY)
4364b47e 189 {
c3226991 190#ifdef OSPFv2
8a70a13e 191 u32 neigh = ipa_to_u32(n->ip);
c3226991 192#else /* OSPFv3 */
8a70a13e 193 u32 neigh = n->rid;
c3226991
OZ
194#endif
195
77539c44 196 if (n->priority != oldpriority)
a5918961 197 ospf_iface_sm(ifa, ISM_NEICH);
4364b47e 198
c3226991
OZ
199#ifdef OSPFv3
200 if (n->iface_id != oldiface_id)
201 ospf_iface_sm(ifa, ISM_NEICH);
202#endif
203
8a70a13e
OZ
204 /* Neighbor is declaring itself ad DR and there is no BDR */
205 if ((n->dr == neigh) && (n->bdr == 0)
77539c44 206 && (n->state != NEIGHBOR_FULL))
a5918961 207 ospf_iface_sm(ifa, ISM_BACKS);
4364b47e 208
b29c620f 209 /* Neighbor is declaring itself as BDR */
8a70a13e 210 if ((n->bdr == neigh) && (n->state != NEIGHBOR_FULL))
a5918961 211 ospf_iface_sm(ifa, ISM_BACKS);
b29c620f
OF
212
213 /* Neighbor is newly declaring itself as DR or BDR */
8a70a13e
OZ
214 if (((n->dr == neigh) && (n->dr != olddr))
215 || ((n->bdr == neigh) && (n->bdr != oldbdr)))
a5918961 216 ospf_iface_sm(ifa, ISM_NEICH);
b29c620f
OF
217
218 /* Neighbor is no more declaring itself as DR or BDR */
8a70a13e
OZ
219 if (((olddr == neigh) && (n->dr != olddr))
220 || ((oldbdr == neigh) && (n->bdr != oldbdr)))
a5918961 221 ospf_iface_sm(ifa, ISM_NEICH);
4364b47e 222 }
4364b47e 223
3b16080c 224 if (ifa->type == OSPF_IT_NBMA)
a190e720 225 {
77539c44
OF
226 if ((ifa->priority == 0) && (n->priority > 0))
227 ospf_hello_send(NULL, 0, n);
a190e720 228 }
4364b47e
OF
229 ospf_neigh_sm(n, INM_HELLOREC);
230}
231
a190e720 232void
c3226991 233ospf_hello_send(timer *timer, int poll, struct ospf_neighbor *dirn)
4364b47e
OF
234{
235 struct ospf_iface *ifa;
236 struct ospf_hello_packet *pkt;
237 struct ospf_packet *op;
238 struct proto *p;
98ac6176 239 struct ospf_neighbor *neigh, *n1;
4364b47e
OF
240 u16 length;
241 u32 *pp;
98ac6176
OF
242 int i, send;
243 struct nbma_node *nb;
86c84d76 244
77539c44
OF
245 if (timer == NULL)
246 ifa = dirn->ifa;
247 else
248 ifa = (struct ospf_iface *) timer->data;
a190e720 249
98ac6176
OF
250 if (ifa->state == OSPF_IS_DOWN)
251 return;
252
77539c44
OF
253 if (ifa->stub)
254 return; /* Don't send any packet on stub iface */
e3bc10fd 255
86c84d76 256 p = (struct proto *) (ifa->oa->po);
a190e720 257 DBG("%s: Hello/Poll timer fired on interface %s.\n",
77539c44 258 p->name, ifa->iface->name);
4364b47e 259
f9c799a0 260 /* Now we should send a hello packet */
353729f5
OZ
261 pkt = ospf_tx_buffer();
262 op = &pkt->ospf_packet;
4364b47e 263
f9c799a0 264 /* Now fill ospf_hello header */
3e2bd0f1 265 ospf_pkt_fill_hdr(ifa, pkt, HELLO_P);
e5b5d18c 266
c3226991 267#ifdef OSPFv2
353729f5 268 pkt->netmask = ipa_mkmask(ifa->addr->pxlen);
e5b5d18c 269 ipa_hton(pkt->netmask);
f571473e
OZ
270 if ((ifa->type == OSPF_IT_VLINK) || (ifa->type == OSPF_IT_PTP))
271 pkt->netmask = IPA_NONE;
c3226991
OZ
272#endif
273
77539c44 274 pkt->helloint = ntohs(ifa->helloint);
77539c44 275 pkt->priority = ifa->priority;
c3226991
OZ
276
277#ifdef OSPFv3
278 pkt->iface_id = htonl(ifa->iface->index);
279
280 pkt->options3 = ifa->oa->options >> 16;
281 pkt->options2 = ifa->oa->options >> 8;
282#endif
283 pkt->options = ifa->oa->options;
284
285#ifdef OSPFv2
d8c7d9e8 286 pkt->deadint = htonl(ifa->dead);
c3226991
OZ
287 pkt->dr = htonl(ipa_to_u32(ifa->drip));
288 pkt->bdr = htonl(ipa_to_u32(ifa->bdrip));
289#else /* OSPFv3 */
290 pkt->deadint = htons(ifa->dead);
291 pkt->dr = htonl(ifa->drid);
292 pkt->bdr = htonl(ifa->bdrid);
293#endif
e5b5d18c
OF
294
295 /* Fill all neighbors */
77539c44
OF
296 i = 0;
297 pp = (u32 *) (((u8 *) pkt) + sizeof(struct ospf_hello_packet));
298 WALK_LIST(neigh, ifa->neigh_list)
e5b5d18c 299 {
3e2bd0f1
OF
300 if ((i+1) * sizeof(u32) + sizeof(struct ospf_hello_packet) > ospf_pkt_maxsize(ifa))
301 {
302 OSPF_TRACE(D_PACKETS, "Too many neighbors on the interface!");
303 break;
304 }
77539c44 305 *(pp + i) = htonl(neigh->rid);
e5b5d18c
OF
306 i++;
307 }
308
77539c44
OF
309 length = sizeof(struct ospf_hello_packet) + i * sizeof(u32);
310 op->length = htons(length);
e5b5d18c 311
98ac6176 312 switch(ifa->type)
e5b5d18c 313 {
98ac6176
OF
314 case OSPF_IT_NBMA:
315 if (timer == NULL) /* Response to received hello */
e5b5d18c 316 {
f9c799a0 317 ospf_send_to(ifa, dirn->ip);
e5b5d18c 318 }
98ac6176 319 else
a190e720 320 {
98ac6176
OF
321 int toall = 0;
322 int meeli = 0;
323 if (ifa->state > OSPF_IS_DROTHER)
324 toall = 1;
325 if (ifa->priority > 0)
326 meeli = 1;
327
328 WALK_LIST(nb, ifa->nbma_list)
329 {
330 send = 1;
331 WALK_LIST(n1, ifa->neigh_list)
332 {
a417ad13 333 if (ipa_equal(nb->ip, n1->ip))
98ac6176
OF
334 {
335 send = 0;
336 break;
337 }
338 }
339 if ((poll == 1) && (send))
340 {
341 if (toall || (meeli && nb->eligible))
f9c799a0 342 ospf_send_to(ifa, nb->ip);
98ac6176
OF
343 }
344 }
345 if (poll == 0)
346 {
347 WALK_LIST(n1, ifa->neigh_list)
348 {
349 if (toall || (n1->rid == ifa->drid) || (n1->rid == ifa->bdrid) ||
350 (meeli && (n1->priority > 0)))
f9c799a0 351 ospf_send_to(ifa, n1->ip);
98ac6176
OF
352 }
353 }
a190e720 354 }
98ac6176
OF
355 break;
356 case OSPF_IT_VLINK:
f9c799a0 357 ospf_send_to(ifa, ifa->vip);
98ac6176
OF
358 break;
359 default:
f9c799a0 360 ospf_send_to(ifa, AllSPFRouters);
e5b5d18c 361 }
8298d780
OZ
362
363 OSPF_TRACE(D_PACKETS, "HELLO packet sent via %s%s",
364 (ifa->type == OSPF_IT_VLINK ? "vlink-" : ""), ifa->iface->name);
4364b47e 365}