]>
Commit | Line | Data |
---|---|---|
4364b47e OF |
1 | /* |
2 | * BIRD -- OSPF | |
3 | * | |
bc4ea680 | 4 | * (c) 1999--2004 Ondrej Filip <feela@network.cz> |
70945cb6 OZ |
5 | * (c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org> |
6 | * (c) 2009--2014 CZ.NIC z.s.p.o. | |
4364b47e OF |
7 | * |
8 | * Can be freely distributed and used under the terms of the GNU GPL. | |
9 | */ | |
10 | ||
11 | #include "ospf.h" | |
12 | ||
c3226991 | 13 | |
70945cb6 | 14 | struct ospf_hello2_packet |
c3226991 | 15 | { |
70945cb6 OZ |
16 | struct ospf_packet hdr; |
17 | union ospf_auth auth; | |
18 | ||
19 | u32 netmask; | |
c3226991 OZ |
20 | u16 helloint; |
21 | u8 options; | |
22 | u8 priority; | |
23 | u32 deadint; | |
24 | u32 dr; | |
25 | u32 bdr; | |
c3226991 | 26 | |
70945cb6 OZ |
27 | u32 neighbors[]; |
28 | }; | |
c3226991 | 29 | |
70945cb6 | 30 | struct ospf_hello3_packet |
c3226991 | 31 | { |
70945cb6 OZ |
32 | struct ospf_packet hdr; |
33 | ||
c3226991 OZ |
34 | u32 iface_id; |
35 | u8 priority; | |
36 | u8 options3; | |
37 | u8 options2; | |
38 | u8 options; | |
39 | u16 helloint; | |
40 | u16 deadint; | |
41 | u32 dr; | |
42 | u32 bdr; | |
c3226991 | 43 | |
70945cb6 OZ |
44 | u32 neighbors[]; |
45 | }; | |
b29c620f | 46 | |
4364b47e | 47 | |
a190e720 | 48 | void |
70945cb6 | 49 | ospf_send_hello(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn) |
4364b47e | 50 | { |
70945cb6 OZ |
51 | struct ospf_proto *p = ifa->oa->po; |
52 | struct ospf_packet *pkt; | |
98ac6176 | 53 | struct ospf_neighbor *neigh, *n1; |
98ac6176 | 54 | struct nbma_node *nb; |
70945cb6 OZ |
55 | u32 *neighbors; |
56 | uint length; | |
57 | int i, max; | |
86c84d76 | 58 | |
391931d4 | 59 | if (ifa->state <= OSPF_IS_LOOP) |
98ac6176 OF |
60 | return; |
61 | ||
77539c44 | 62 | if (ifa->stub) |
70945cb6 | 63 | return; |
e3bc10fd | 64 | |
4364b47e | 65 | |
e7b76b97 | 66 | pkt = ospf_tx_buffer(ifa); |
3e2bd0f1 | 67 | ospf_pkt_fill_hdr(ifa, pkt, HELLO_P); |
e5b5d18c | 68 | |
70945cb6 OZ |
69 | if (ospf_is_v2(p)) |
70 | { | |
71 | struct ospf_hello2_packet *ps = (void *) pkt; | |
72 | ||
73 | if ((ifa->type == OSPF_IT_VLINK) || | |
74 | ((ifa->type == OSPF_IT_PTP) && !ifa->ptp_netmask)) | |
75 | ps->netmask = 0; | |
76 | else | |
77 | ps->netmask = htonl(u32_mkmask(ifa->addr->pxlen)); | |
78 | ||
79 | ps->helloint = ntohs(ifa->helloint); | |
80 | ps->options = ifa->oa->options; | |
81 | ps->priority = ifa->priority; | |
82 | ps->deadint = htonl(ifa->deadint); | |
83 | ps->dr = htonl(ipa_to_u32(ifa->drip)); | |
84 | ps->bdr = htonl(ipa_to_u32(ifa->bdrip)); | |
85 | ||
86 | length = sizeof(struct ospf_hello2_packet); | |
87 | neighbors = ps->neighbors; | |
88 | } | |
89 | else | |
90 | { | |
91 | struct ospf_hello3_packet *ps = (void *) pkt; | |
92 | ||
93 | ps->iface_id = htonl(ifa->iface_id); | |
94 | ps->priority = ifa->priority; | |
95 | ps->options3 = ifa->oa->options >> 16; | |
96 | ps->options2 = ifa->oa->options >> 8; | |
97 | ps->options = ifa->oa->options; | |
98 | ps->helloint = ntohs(ifa->helloint); | |
99 | ps->deadint = htons(ifa->deadint); | |
100 | ps->dr = htonl(ifa->drid); | |
101 | ps->bdr = htonl(ifa->bdrid); | |
102 | ||
103 | length = sizeof(struct ospf_hello3_packet); | |
104 | neighbors = ps->neighbors; | |
105 | } | |
e5b5d18c | 106 | |
77539c44 | 107 | i = 0; |
70945cb6 | 108 | max = (ospf_pkt_maxsize(ifa) - length) / sizeof(u32); |
8e48831a | 109 | |
70945cb6 | 110 | /* Fill all neighbors */ |
8e48831a | 111 | if (kind != OHS_SHUTDOWN) |
e5b5d18c | 112 | { |
8e48831a | 113 | WALK_LIST(neigh, ifa->neigh_list) |
3e2bd0f1 | 114 | { |
70945cb6 | 115 | if (i == max) |
8e48831a | 116 | { |
f8fefde3 | 117 | log(L_WARN "%s: Too many neighbors on %s", p->p.name, ifa->ifname); |
8e48831a OZ |
118 | break; |
119 | } | |
70945cb6 | 120 | neighbors[i] = htonl(neigh->rid); |
8e48831a | 121 | i++; |
3e2bd0f1 | 122 | } |
e5b5d18c OF |
123 | } |
124 | ||
70945cb6 OZ |
125 | length += i * sizeof(u32); |
126 | pkt->length = htons(length); | |
127 | ||
128 | OSPF_TRACE(D_PACKETS, "HELLO packet sent via %s", ifa->ifname); | |
e5b5d18c | 129 | |
98ac6176 | 130 | switch(ifa->type) |
e5b5d18c | 131 | { |
919f5411 OZ |
132 | case OSPF_IT_BCAST: |
133 | case OSPF_IT_PTP: | |
95127cbb | 134 | ospf_send_to_all(ifa); |
919f5411 OZ |
135 | break; |
136 | ||
137 | case OSPF_IT_NBMA: | |
beeda6af | 138 | if (dirn) /* Response to received hello */ |
919f5411 OZ |
139 | { |
140 | ospf_send_to(ifa, dirn->ip); | |
98ac6176 | 141 | break; |
919f5411 OZ |
142 | } |
143 | ||
144 | int to_all = ifa->state > OSPF_IS_DROTHER; | |
145 | int me_elig = ifa->priority > 0; | |
742029eb | 146 | |
8e48831a | 147 | if (kind == OHS_POLL) /* Poll timer */ |
919f5411 OZ |
148 | { |
149 | WALK_LIST(nb, ifa->nbma_list) | |
150 | if (!nb->found && (to_all || (me_elig && nb->eligible))) | |
151 | ospf_send_to(ifa, nb->ip); | |
152 | } | |
153 | else /* Hello timer */ | |
154 | { | |
155 | WALK_LIST(n1, ifa->neigh_list) | |
156 | if (to_all || (me_elig && (n1->priority > 0)) || | |
157 | (n1->rid == ifa->drid) || (n1->rid == ifa->bdrid)) | |
158 | ospf_send_to(ifa, n1->ip); | |
159 | } | |
160 | break; | |
161 | ||
162 | case OSPF_IT_PTMP: | |
163 | WALK_LIST(n1, ifa->neigh_list) | |
164 | ospf_send_to(ifa, n1->ip); | |
165 | ||
166 | WALK_LIST(nb, ifa->nbma_list) | |
167 | if (!nb->found) | |
168 | ospf_send_to(ifa, nb->ip); | |
169 | ||
170 | /* If there is no other target, we also send HELLO packet to the other end */ | |
171 | if (ipa_nonzero(ifa->addr->opposite) && !ifa->strictnbma && | |
172 | EMPTY_LIST(ifa->neigh_list) && EMPTY_LIST(ifa->nbma_list)) | |
173 | ospf_send_to(ifa, ifa->addr->opposite); | |
174 | break; | |
175 | ||
176 | case OSPF_IT_VLINK: | |
177 | ospf_send_to(ifa, ifa->vip); | |
178 | break; | |
179 | ||
180 | default: | |
70945cb6 | 181 | bug("Bug in ospf_send_hello()"); |
e5b5d18c | 182 | } |
70945cb6 | 183 | } |
8298d780 | 184 | |
70945cb6 OZ |
185 | |
186 | void | |
187 | ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa, | |
188 | struct ospf_neighbor *n, ip_addr faddr) | |
189 | { | |
190 | struct ospf_proto *p = ifa->oa->po; | |
f8fefde3 | 191 | const char *err_dsc = NULL; |
70945cb6 OZ |
192 | u32 rcv_iface_id, rcv_helloint, rcv_deadint, rcv_dr, rcv_bdr; |
193 | u8 rcv_options, rcv_priority; | |
194 | u32 *neighbors; | |
195 | u32 neigh_count; | |
f8fefde3 | 196 | uint plen, i, err_val = 0; |
70945cb6 OZ |
197 | |
198 | /* RFC 2328 10.5 */ | |
199 | ||
f8fefde3 OZ |
200 | /* |
201 | * We may not yet havethe associate neighbor, so we use Router ID from the | |
202 | * packet instead of one from the neighbor structure for log messages. | |
203 | */ | |
204 | u32 rcv_rid = ntohl(pkt->routerid); | |
205 | OSPF_TRACE(D_PACKETS, "HELLO packet received from nbr %R on %s", rcv_rid, ifa->ifname); | |
70945cb6 OZ |
206 | |
207 | plen = ntohs(pkt->length); | |
208 | ||
209 | if (ospf_is_v2(p)) | |
210 | { | |
211 | struct ospf_hello2_packet *ps = (void *) pkt; | |
212 | ||
213 | if (plen < sizeof(struct ospf_hello2_packet)) | |
f8fefde3 | 214 | DROP("too short", plen); |
70945cb6 OZ |
215 | |
216 | rcv_iface_id = 0; | |
217 | rcv_helloint = ntohs(ps->helloint); | |
218 | rcv_deadint = ntohl(ps->deadint); | |
219 | rcv_dr = ntohl(ps->dr); | |
220 | rcv_bdr = ntohl(ps->bdr); | |
221 | rcv_options = ps->options; | |
222 | rcv_priority = ps->priority; | |
223 | ||
224 | int pxlen = u32_masklen(ntohl(ps->netmask)); | |
225 | if ((ifa->type != OSPF_IT_VLINK) && | |
226 | (ifa->type != OSPF_IT_PTP) && | |
227 | (pxlen != ifa->addr->pxlen)) | |
f8fefde3 | 228 | DROP("prefix length mismatch", pxlen); |
70945cb6 OZ |
229 | |
230 | neighbors = ps->neighbors; | |
231 | neigh_count = (plen - sizeof(struct ospf_hello2_packet)) / sizeof(u32); | |
232 | } | |
233 | else /* OSPFv3 */ | |
234 | { | |
235 | struct ospf_hello3_packet *ps = (void *) pkt; | |
236 | ||
237 | if (plen < sizeof(struct ospf_hello3_packet)) | |
f8fefde3 | 238 | DROP("too short", plen); |
70945cb6 OZ |
239 | |
240 | rcv_iface_id = ntohl(ps->iface_id); | |
241 | rcv_helloint = ntohs(ps->helloint); | |
242 | rcv_deadint = ntohs(ps->deadint); | |
243 | rcv_dr = ntohl(ps->dr); | |
244 | rcv_bdr = ntohl(ps->bdr); | |
245 | rcv_options = ps->options; | |
246 | rcv_priority = ps->priority; | |
247 | ||
248 | neighbors = ps->neighbors; | |
249 | neigh_count = (plen - sizeof(struct ospf_hello3_packet)) / sizeof(u32); | |
250 | } | |
251 | ||
252 | if (rcv_helloint != ifa->helloint) | |
f8fefde3 | 253 | DROP("hello interval mismatch", rcv_helloint); |
70945cb6 OZ |
254 | |
255 | if (rcv_deadint != ifa->deadint) | |
f8fefde3 | 256 | DROP("dead interval mismatch", rcv_deadint); |
70945cb6 OZ |
257 | |
258 | /* Check whether bits E, N match */ | |
259 | if ((rcv_options ^ ifa->oa->options) & (OPT_E | OPT_N)) | |
f8fefde3 | 260 | DROP("area type mismatch", rcv_options); |
70945cb6 OZ |
261 | |
262 | /* Check consistency of existing neighbor entry */ | |
263 | if (n) | |
264 | { | |
a7a7372a | 265 | uint t = ifa->type; |
70945cb6 OZ |
266 | if (ospf_is_v2(p) && ((t == OSPF_IT_BCAST) || (t == OSPF_IT_NBMA) || (t == OSPF_IT_PTMP))) |
267 | { | |
268 | /* Neighbor identified by IP address; Router ID may change */ | |
f8fefde3 | 269 | if (n->rid != rcv_rid) |
70945cb6 | 270 | { |
f8fefde3 OZ |
271 | OSPF_TRACE(D_EVENTS, "Neighbor %R on %s changed Router ID to %R", |
272 | n->rid, ifa->ifname, rcv_rid); | |
273 | ospf_neigh_sm(n, INM_KILLNBR); | |
70945cb6 OZ |
274 | n = NULL; |
275 | } | |
276 | } | |
277 | else /* OSPFv3 or OSPFv2/PtP */ | |
278 | { | |
279 | /* Neighbor identified by Router ID; IP address may change */ | |
280 | if (!ipa_equal(faddr, n->ip)) | |
281 | { | |
f8fefde3 OZ |
282 | OSPF_TRACE(D_EVENTS, "Neighbor %R on %s changed IP address to %I", |
283 | n->rid, ifa->ifname, n->ip, faddr); | |
70945cb6 OZ |
284 | n->ip = faddr; |
285 | } | |
286 | } | |
287 | } | |
288 | ||
289 | if (!n) | |
290 | { | |
291 | if ((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP)) | |
292 | { | |
293 | struct nbma_node *nn = find_nbma_node(ifa, faddr); | |
294 | ||
295 | if (!nn && ifa->strictnbma) | |
f8fefde3 | 296 | DROP1("new neighbor denied"); |
70945cb6 OZ |
297 | |
298 | if (nn && (ifa->type == OSPF_IT_NBMA) && | |
299 | (((rcv_priority == 0) && nn->eligible) || | |
300 | ((rcv_priority > 0) && !nn->eligible))) | |
f8fefde3 | 301 | DROP("eligibility mismatch", rcv_priority); |
70945cb6 OZ |
302 | |
303 | if (nn) | |
304 | nn->found = 1; | |
305 | } | |
306 | ||
f8fefde3 OZ |
307 | // XXXX format |
308 | // "ospf1: New neighbor found: 192.168.1.1/fe80:1234:1234:1234:1234 on eth0"; | |
309 | // "ospf1: New neighbor found: 192.168.1.1 on eth0 at fe80:1234:1234:1234:1234"; | |
310 | // "ospf1: Neighbor 192.168.1.1 on eth0 found, IP adress fe80:1234:1234:1234:1234"; | |
70945cb6 OZ |
311 | OSPF_TRACE(D_EVENTS, "New neighbor found: %I on %s", faddr, ifa->ifname); |
312 | ||
313 | n = ospf_neighbor_new(ifa); | |
314 | ||
f8fefde3 | 315 | n->rid = rcv_rid; |
70945cb6 OZ |
316 | n->ip = faddr; |
317 | n->dr = rcv_dr; | |
318 | n->bdr = rcv_bdr; | |
319 | n->priority = rcv_priority; | |
320 | n->iface_id = rcv_iface_id; | |
321 | ||
322 | if (n->ifa->cf->bfd) | |
323 | ospf_neigh_update_bfd(n, n->ifa->bfd); | |
324 | } | |
325 | ||
326 | u32 n_id = ospf_is_v2(p) ? ipa_to_u32(n->ip) : n->rid; | |
327 | ||
328 | u32 old_dr = n->dr; | |
329 | u32 old_bdr = n->bdr; | |
330 | u32 old_priority = n->priority; | |
331 | u32 old_iface_id = n->iface_id; | |
332 | ||
333 | n->dr = rcv_dr; | |
334 | n->bdr = rcv_bdr; | |
335 | n->priority = rcv_priority; | |
336 | n->iface_id = rcv_iface_id; | |
337 | ||
338 | ||
339 | /* Update inactivity timer */ | |
340 | ospf_neigh_sm(n, INM_HELLOREC); | |
341 | ||
342 | /* RFC 2328 9.5.1 - non-eligible routers reply to hello on NBMA nets */ | |
343 | if (ifa->type == OSPF_IT_NBMA) | |
344 | if ((ifa->priority == 0) && (n->priority > 0)) | |
345 | ospf_send_hello(n->ifa, OHS_HELLO, n); | |
742029eb | 346 | |
70945cb6 OZ |
347 | |
348 | /* Examine list of neighbors */ | |
349 | for (i = 0; i < neigh_count; i++) | |
350 | if (neighbors[i] == htonl(p->router_id)) | |
351 | goto found_self; | |
352 | ||
353 | ospf_neigh_sm(n, INM_1WAYREC); | |
354 | return; | |
355 | ||
f8fefde3 | 356 | found_self: |
70945cb6 OZ |
357 | ospf_neigh_sm(n, INM_2WAYREC); |
358 | ||
359 | ||
360 | if (n->iface_id != old_iface_id) | |
361 | { | |
362 | /* If neighbor is DR, also update cached DR interface ID */ | |
363 | if (ifa->drid == n->rid) | |
364 | ifa->dr_iface_id = n->iface_id; | |
365 | ||
366 | /* RFC 5340 4.4.3 Event 4 - change of neighbor's interface ID */ | |
367 | ospf_notify_rt_lsa(ifa->oa); | |
368 | ||
369 | /* Missed in RFC 5340 4.4.3 Event 4 - (Px-)Net-LSA uses iface_id to ref Link-LSAs */ | |
370 | ospf_notify_net_lsa(ifa); | |
371 | } | |
372 | ||
373 | if (ifa->state == OSPF_IS_WAITING) | |
374 | { | |
375 | /* Neighbor is declaring itself DR (and there is no BDR) or as BDR */ | |
376 | if (((n->dr == n_id) && (n->bdr == 0)) || (n->bdr == n_id)) | |
377 | ospf_iface_sm(ifa, ISM_BACKS); | |
378 | } | |
379 | else if (ifa->state >= OSPF_IS_DROTHER) | |
380 | { | |
381 | /* Neighbor changed priority or started/stopped declaring itself as DR/BDR */ | |
382 | if ((n->priority != old_priority) || | |
383 | ((n->dr == n_id) && (old_dr != n_id)) || | |
384 | ((n->dr != n_id) && (old_dr == n_id)) || | |
385 | ((n->bdr == n_id) && (old_bdr != n_id)) || | |
386 | ((n->bdr != n_id) && (old_bdr == n_id))) | |
387 | ospf_iface_sm(ifa, ISM_NEICH); | |
388 | } | |
f8fefde3 OZ |
389 | |
390 | return; | |
391 | ||
392 | drop: | |
393 | LOG_PKT("Bad HELLO packet from nbr %R on %s - %s (%u)", | |
394 | rcv_rid, ifa->ifname, err_dsc, err_val); | |
4364b47e | 395 | } |