]>
Commit | Line | Data |
---|---|---|
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 | |
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 | ||
4364b47e | 44 | void |
c3226991 OZ |
45 | ospf_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 | 232 | void |
c3226991 | 233 | ospf_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 | } |