]> git.ipfire.org Git - thirdparty/bird.git/blob - proto/ospf/hello.c
70fb6548ee57063bcf365c4cca4c228c4c85e420
[thirdparty/bird.git] / proto / ospf / hello.c
1 /*
2 * BIRD -- OSPF
3 *
4 * (c) 1999--2004 Ondrej Filip <feela@network.cz>
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 */
8
9 #include "ospf.h"
10
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
44 void
45 ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
46 struct ospf_neighbor *n, ip_addr faddr)
47 {
48 struct proto_ospf *po = ifa->oa->po;
49 struct proto *p = &po->proto;
50 char *beg = "OSPF: Bad HELLO packet from ";
51 unsigned int size, i, twoway, eligible, peers;
52 u32 tmp;
53 u32 *pnrid;
54
55 size = ntohs(ps_i->length);
56 if (size < sizeof(struct ospf_hello_packet))
57 {
58 log(L_ERR "%s%I - too short (%u B)", beg, faddr, size);
59 return;
60 }
61
62 struct ospf_hello_packet *ps = (void *) ps_i;
63
64 OSPF_TRACE(D_PACKETS, "HELLO packet received from %I via %s%s", faddr,
65 (ifa->type == OSPF_IT_VLINK ? "vlink-" : ""), ifa->iface->name);
66
67 #ifdef OSPFv2
68 ip_addr mask = ps->netmask;
69 ipa_ntoh(mask);
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 }
77 #endif
78
79 tmp = ntohs(ps->helloint);
80 if (tmp != ifa->helloint)
81 {
82 log(L_ERR "%s%I - hello interval mismatch (%d)", beg, faddr, tmp);
83 return;
84 }
85
86 #ifdef OSPFv2
87 tmp = ntohl(ps->deadint);
88 #else /* OSPFv3 */
89 tmp = ntohs(ps->deadint);
90 #endif
91 if (tmp != ifa->dead)
92 {
93 log(L_ERR "%s%I - dead interval mismatch (%d)", beg, faddr, tmp);
94 return;
95 }
96
97 tmp = !(ps->options & OPT_E);
98 if (tmp != !!ifa->oa->stub)
99 {
100 log(L_ERR "%s%I - stub area flag mismatch (%d)", beg, faddr, tmp);
101 return;
102 }
103
104 if (!n)
105 {
106 if ((ifa->type == OSPF_IT_NBMA))
107 {
108 struct nbma_node *nn;
109 int found = 0;
110
111 WALK_LIST(nn, ifa->nbma_list)
112 {
113 if (ipa_equal(faddr, nn->ip))
114 {
115 found = 1;
116 break;
117 }
118 }
119 if ((found == 0) && (ifa->strictnbma))
120 {
121 log(L_WARN "Ignoring new neighbor: %I on %s", faddr,
122 ifa->iface->name);
123 return;
124 }
125 if (found)
126 {
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);
133 return;
134 }
135 }
136 }
137 OSPF_TRACE(D_EVENTS, "New neighbor found: %I on %s", faddr,
138 ifa->iface->name);
139
140 n = ospf_neighbor_new(ifa);
141
142 n->rid = ntohl(((struct ospf_packet *) ps)->routerid);
143 n->ip = faddr;
144 n->dr = ntohl(ps->dr);
145 n->bdr = ntohl(ps->bdr);
146 n->priority = ps->priority;
147 #ifdef OSPFv3
148 n->iface_id = ntohl(ps->iface_id);
149 #endif
150 }
151 ospf_neigh_sm(n, INM_HELLOREC);
152
153 pnrid = (u32 *) ((struct ospf_hello_packet *) (ps + 1));
154
155 peers = (size - sizeof(struct ospf_hello_packet))/ sizeof(u32);
156
157 twoway = 0;
158 for (i = 0; i < peers; i++)
159 {
160 if (ntohl(pnrid[i]) == po->router_id)
161 {
162 DBG("%s: Twoway received from %I\n", p->name, faddr);
163 ospf_neigh_sm(n, INM_2WAYREC);
164 twoway = 1;
165 break;
166 }
167 }
168
169 if (!twoway)
170 ospf_neigh_sm(n, INM_1WAYREC);
171
172 u32 olddr = n->dr;
173 u32 oldbdr = n->bdr;
174 u32 oldpriority = n->priority;
175 #ifdef OSPFv3
176 u32 oldiface_id = n->iface_id;
177 #endif
178
179 n->dr = ntohl(ps->dr);
180 n->bdr = ntohl(ps->bdr);
181 n->priority = ps->priority;
182 #ifdef OSPFv3
183 n->iface_id = ntohl(ps->iface_id);
184 #endif
185
186
187 /* Check priority change */
188 if (n->state >= NEIGHBOR_2WAY)
189 {
190 #ifdef OSPFv2
191 u32 neigh = ipa_to_u32(n->ip);
192 #else /* OSPFv3 */
193 u32 neigh = n->rid;
194 #endif
195
196 if (n->priority != oldpriority)
197 ospf_iface_sm(ifa, ISM_NEICH);
198
199 #ifdef OSPFv3
200 if (n->iface_id != oldiface_id)
201 ospf_iface_sm(ifa, ISM_NEICH);
202 #endif
203
204 /* Neighbor is declaring itself ad DR and there is no BDR */
205 if ((n->dr == neigh) && (n->bdr == 0)
206 && (n->state != NEIGHBOR_FULL))
207 ospf_iface_sm(ifa, ISM_BACKS);
208
209 /* Neighbor is declaring itself as BDR */
210 if ((n->bdr == neigh) && (n->state != NEIGHBOR_FULL))
211 ospf_iface_sm(ifa, ISM_BACKS);
212
213 /* Neighbor is newly declaring itself as DR or BDR */
214 if (((n->dr == neigh) && (n->dr != olddr))
215 || ((n->bdr == neigh) && (n->bdr != oldbdr)))
216 ospf_iface_sm(ifa, ISM_NEICH);
217
218 /* Neighbor is no more declaring itself as DR or BDR */
219 if (((olddr == neigh) && (n->dr != olddr))
220 || ((oldbdr == neigh) && (n->bdr != oldbdr)))
221 ospf_iface_sm(ifa, ISM_NEICH);
222 }
223
224 if (ifa->type == OSPF_IT_NBMA)
225 {
226 if ((ifa->priority == 0) && (n->priority > 0))
227 ospf_hello_send(NULL, 0, n);
228 }
229 ospf_neigh_sm(n, INM_HELLOREC);
230 }
231
232 void
233 ospf_hello_send(timer *timer, int poll, struct ospf_neighbor *dirn)
234 {
235 struct ospf_iface *ifa;
236 struct ospf_hello_packet *pkt;
237 struct ospf_packet *op;
238 struct proto *p;
239 struct ospf_neighbor *neigh, *n1;
240 u16 length;
241 u32 *pp;
242 int i, send;
243 struct nbma_node *nb;
244
245 if (timer == NULL)
246 ifa = dirn->ifa;
247 else
248 ifa = (struct ospf_iface *) timer->data;
249
250 if (ifa->state == OSPF_IS_DOWN)
251 return;
252
253 if (ifa->stub)
254 return; /* Don't send any packet on stub iface */
255
256 p = (struct proto *) (ifa->oa->po);
257 DBG("%s: Hello/Poll timer fired on interface %s with IP %I\n",
258 p->name, ifa->iface->name, ifa->addr->ip);
259
260 /* Now we should send a hello packet */
261 pkt = ospf_tx_buffer(ifa);
262 op = &pkt->ospf_packet;
263
264 /* Now fill ospf_hello header */
265 ospf_pkt_fill_hdr(ifa, pkt, HELLO_P);
266
267 #ifdef OSPFv2
268 pkt->netmask = ipa_mkmask(ifa->addr->pxlen);
269 ipa_hton(pkt->netmask);
270 if ((ifa->type == OSPF_IT_VLINK) || (ifa->type == OSPF_IT_PTP))
271 pkt->netmask = IPA_NONE;
272 #endif
273
274 pkt->helloint = ntohs(ifa->helloint);
275 pkt->priority = ifa->priority;
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
286 pkt->deadint = htonl(ifa->dead);
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
294
295 /* Fill all neighbors */
296 i = 0;
297 pp = (u32 *) (((u8 *) pkt) + sizeof(struct ospf_hello_packet));
298 WALK_LIST(neigh, ifa->neigh_list)
299 {
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 }
305 *(pp + i) = htonl(neigh->rid);
306 i++;
307 }
308
309 length = sizeof(struct ospf_hello_packet) + i * sizeof(u32);
310 op->length = htons(length);
311
312 switch(ifa->type)
313 {
314 case OSPF_IT_NBMA:
315 if (timer == NULL) /* Response to received hello */
316 {
317 ospf_send_to(ifa, dirn->ip);
318 }
319 else
320 {
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 {
333 if (ipa_equal(nb->ip, n1->ip))
334 {
335 send = 0;
336 break;
337 }
338 }
339 if ((poll == 1) && (send))
340 {
341 if (toall || (meeli && nb->eligible))
342 ospf_send_to(ifa, nb->ip);
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)))
351 ospf_send_to(ifa, n1->ip);
352 }
353 }
354 }
355 break;
356 case OSPF_IT_VLINK:
357 ospf_send_to(ifa, ifa->vip);
358 break;
359 default:
360 ospf_send_to(ifa, AllSPFRouters);
361 }
362
363 OSPF_TRACE(D_PACKETS, "HELLO packet sent via %s%s",
364 (ifa->type == OSPF_IT_VLINK ? "vlink-" : ""), ifa->iface->name);
365 }