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