]>
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 | ||
11 | void | |
77539c44 | 12 | ospf_hello_receive(struct ospf_hello_packet *ps, |
5e3436d2 | 13 | struct ospf_iface *ifa, struct ospf_neighbor *n, ip_addr faddr) |
4364b47e | 14 | { |
5e3436d2 | 15 | u32 *pnrid; |
77539c44 | 16 | ip_addr olddr, oldbdr; |
099c017f | 17 | ip_addr mask; |
77539c44 | 18 | char *beg = "Bad OSPF hello packet from ", *rec = " received: "; |
86c84d76 | 19 | struct proto *p = (struct proto *) ifa->oa->po; |
bc4ea680 | 20 | unsigned int size = ntohs(ps->ospf_packet.length), i, twoway, oldpriority, eligible = 0, peers; |
4364b47e | 21 | |
3b16080c OF |
22 | OSPF_TRACE(D_PACKETS, "Received hello from %I via %s%s", faddr, |
23 | (ifa->type == OSPF_IT_VLINK ? "vlink-" : ""), ifa->iface->name); | |
77539c44 | 24 | mask = ps->netmask; |
099c017f | 25 | ipa_ntoh(mask); |
31dca435 | 26 | |
5d3f5552 | 27 | if (((ifa->type != OSPF_IT_VLINK) && (ifa->type != OSPF_IT_PTP)) && |
3b16080c | 28 | ((unsigned) ipa_mklen(mask) != ifa->iface->addr->pxlen)) |
4364b47e | 29 | { |
5e3436d2 | 30 | log(L_ERR "%s%I%sbad netmask %I.", beg, faddr, rec, mask); |
4364b47e OF |
31 | return; |
32 | } | |
77539c44 OF |
33 | |
34 | if (ntohs(ps->helloint) != ifa->helloint) | |
4364b47e | 35 | { |
2e10a170 OF |
36 | log(L_WARN "%s%I%shello interval mismatch (%d).", beg, faddr, rec, |
37 | ntohs(ps->helloint)); | |
4364b47e OF |
38 | return; |
39 | } | |
40 | ||
d8c7d9e8 | 41 | if (ntohl(ps->deadint) != ifa->dead) |
4364b47e | 42 | { |
2e10a170 OF |
43 | log(L_ERR "%s%I%sdead interval mismatch (%d).", beg, faddr, rec, |
44 | ntohl(ps->deadint)); | |
4364b47e OF |
45 | return; |
46 | } | |
47 | ||
621ccdfe | 48 | if (ps->options != ifa->oa->opt.byte) |
4364b47e | 49 | { |
a5918961 | 50 | log(L_ERR "%s%I%soptions mismatch (0x%x).", beg, faddr, rec, ps->options); |
4364b47e OF |
51 | return; |
52 | } | |
53 | ||
5e3436d2 | 54 | if (!n) |
4364b47e | 55 | { |
77539c44 | 56 | if ((ifa->type == OSPF_IT_NBMA)) |
a190e720 OF |
57 | { |
58 | struct nbma_node *nn; | |
77539c44 | 59 | int found = 0; |
a190e720 | 60 | |
77539c44 | 61 | WALK_LIST(nn, ifa->nbma_list) |
a190e720 | 62 | { |
a417ad13 | 63 | if (ipa_equal(faddr, nn->ip)) |
a190e720 | 64 | { |
77539c44 | 65 | found = 1; |
a190e720 OF |
66 | break; |
67 | } | |
68 | } | |
77539c44 | 69 | if ((found == 0) && (ifa->strictnbma)) |
a190e720 | 70 | { |
77539c44 OF |
71 | log(L_WARN "Ignoring new neighbor: %I on %s.", faddr, |
72 | ifa->iface->name); | |
a190e720 OF |
73 | return; |
74 | } | |
77539c44 | 75 | if (found) |
a190e720 | 76 | { |
77539c44 OF |
77 | eligible = nn->eligible; |
78 | if (((ps->priority == 0) && eligible) | |
79 | || ((ps->priority > 0) && (eligible == 0))) | |
80 | { | |
81 | log(L_ERR "Eligibility mismatch for neighbor: %I on %s", | |
82 | faddr, ifa->iface->name); | |
a190e720 | 83 | return; |
77539c44 | 84 | } |
a190e720 OF |
85 | } |
86 | } | |
abcbfd04 | 87 | OSPF_TRACE(D_EVENTS, "New neighbor found: %I on %s.", faddr, |
77539c44 | 88 | ifa->iface->name); |
39e517d4 OF |
89 | |
90 | n = ospf_neighbor_new(ifa); | |
91 | ||
5e3436d2 | 92 | n->rid = ntohl(((struct ospf_packet *) ps)->routerid); |
77539c44 OF |
93 | n->ip = faddr; |
94 | n->dr = ps->dr; | |
099c017f | 95 | ipa_ntoh(n->dr); |
77539c44 | 96 | n->bdr = ps->bdr; |
099c017f | 97 | ipa_ntoh(n->bdr); |
77539c44 OF |
98 | n->priority = ps->priority; |
99 | n->options = ps->options; | |
4364b47e OF |
100 | } |
101 | ospf_neigh_sm(n, INM_HELLOREC); | |
102 | ||
77539c44 | 103 | pnrid = (u32 *) ((struct ospf_hello_packet *) (ps + 1)); |
4364b47e | 104 | |
bc4ea680 OF |
105 | peers = (size - sizeof(struct ospf_hello_packet))/ sizeof(u32); |
106 | ||
77539c44 | 107 | twoway = 0; |
bc4ea680 | 108 | for (i = 0; i < peers; i++) |
4364b47e | 109 | { |
77539c44 | 110 | if (ntohl(*(pnrid + i)) == p->cf->global->router_id) |
4364b47e | 111 | { |
31dca435 | 112 | DBG("%s: Twoway received from %I\n", p->name, faddr); |
4364b47e | 113 | ospf_neigh_sm(n, INM_2WAYREC); |
77539c44 | 114 | twoway = 1; |
4364b47e OF |
115 | break; |
116 | } | |
117 | } | |
118 | ||
77539c44 OF |
119 | if (!twoway) |
120 | ospf_neigh_sm(n, INM_1WAYREC); | |
4364b47e | 121 | |
b29c620f | 122 | olddr = n->dr; |
59ba3342 | 123 | n->dr = ipa_ntoh(ps->dr); |
b29c620f | 124 | oldbdr = n->bdr; |
59ba3342 | 125 | n->bdr = ipa_ntoh(ps->bdr); |
b29c620f OF |
126 | oldpriority = n->priority; |
127 | n->priority = ps->priority; | |
128 | ||
4364b47e | 129 | /* Check priority change */ |
77539c44 | 130 | if (n->state >= NEIGHBOR_2WAY) |
4364b47e | 131 | { |
77539c44 | 132 | if (n->priority != oldpriority) |
a5918961 | 133 | ospf_iface_sm(ifa, ISM_NEICH); |
4364b47e | 134 | |
b29c620f | 135 | /* Router is declaring itself ad DR and there is no BDR */ |
a417ad13 | 136 | if (ipa_equal(n->ip, n->dr) && (ipa_to_u32(n->bdr) == 0) |
77539c44 | 137 | && (n->state != NEIGHBOR_FULL)) |
a5918961 | 138 | ospf_iface_sm(ifa, ISM_BACKS); |
4364b47e | 139 | |
b29c620f | 140 | /* Neighbor is declaring itself as BDR */ |
a417ad13 | 141 | if (ipa_equal(n->ip, n->bdr) && (n->state != NEIGHBOR_FULL)) |
a5918961 | 142 | ospf_iface_sm(ifa, ISM_BACKS); |
b29c620f OF |
143 | |
144 | /* Neighbor is newly declaring itself as DR or BDR */ | |
a417ad13 OF |
145 | if ((ipa_equal(n->ip, n->dr) && (!ipa_equal(n->dr, olddr))) |
146 | || (ipa_equal(n->ip, n->bdr) && (!ipa_equal(n->bdr, oldbdr)))) | |
a5918961 | 147 | ospf_iface_sm(ifa, ISM_NEICH); |
b29c620f OF |
148 | |
149 | /* Neighbor is no more declaring itself as DR or BDR */ | |
a417ad13 OF |
150 | if ((ipa_equal(n->ip, olddr) && (!ipa_equal(n->dr, olddr))) |
151 | || (ipa_equal(n->ip, oldbdr) && (!ipa_equal(n->bdr, oldbdr)))) | |
a5918961 | 152 | ospf_iface_sm(ifa, ISM_NEICH); |
4364b47e | 153 | } |
4364b47e | 154 | |
3b16080c | 155 | if (ifa->type == OSPF_IT_NBMA) |
a190e720 | 156 | { |
77539c44 OF |
157 | if ((ifa->priority == 0) && (n->priority > 0)) |
158 | ospf_hello_send(NULL, 0, n); | |
a190e720 | 159 | } |
4364b47e OF |
160 | ospf_neigh_sm(n, INM_HELLOREC); |
161 | } | |
162 | ||
a190e720 | 163 | void |
77539c44 | 164 | ospf_hello_send(timer * timer, int poll, struct ospf_neighbor *dirn) |
4364b47e OF |
165 | { |
166 | struct ospf_iface *ifa; | |
167 | struct ospf_hello_packet *pkt; | |
168 | struct ospf_packet *op; | |
169 | struct proto *p; | |
98ac6176 | 170 | struct ospf_neighbor *neigh, *n1; |
4364b47e OF |
171 | u16 length; |
172 | u32 *pp; | |
98ac6176 OF |
173 | int i, send; |
174 | struct nbma_node *nb; | |
86c84d76 | 175 | |
77539c44 OF |
176 | if (timer == NULL) |
177 | ifa = dirn->ifa; | |
178 | else | |
179 | ifa = (struct ospf_iface *) timer->data; | |
a190e720 | 180 | |
98ac6176 OF |
181 | if (ifa->state == OSPF_IS_DOWN) |
182 | return; | |
183 | ||
77539c44 OF |
184 | if (ifa->stub) |
185 | return; /* Don't send any packet on stub iface */ | |
e3bc10fd | 186 | |
86c84d76 | 187 | p = (struct proto *) (ifa->oa->po); |
a190e720 | 188 | DBG("%s: Hello/Poll timer fired on interface %s.\n", |
77539c44 | 189 | p->name, ifa->iface->name); |
4364b47e OF |
190 | /* Now we should send a hello packet */ |
191 | /* First a common packet header */ | |
98ac6176 | 192 | if ((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_VLINK)) |
4364b47e | 193 | { |
98ac6176 | 194 | pkt = (struct ospf_hello_packet *) (ifa->ip_sk->tbuf); |
e5b5d18c | 195 | } |
77539c44 | 196 | else |
e5b5d18c | 197 | { |
98ac6176 | 198 | pkt = (struct ospf_hello_packet *) (ifa->hello_sk->tbuf); |
e5b5d18c | 199 | } |
4364b47e | 200 | |
e5b5d18c | 201 | /* Now fill ospf_hello header */ |
77539c44 | 202 | op = (struct ospf_packet *) pkt; |
4364b47e | 203 | |
3e2bd0f1 | 204 | ospf_pkt_fill_hdr(ifa, pkt, HELLO_P); |
e5b5d18c | 205 | |
77539c44 | 206 | pkt->netmask = ipa_mkmask(ifa->iface->addr->pxlen); |
e5b5d18c | 207 | ipa_hton(pkt->netmask); |
3b16080c | 208 | if (ifa->type == OSPF_IT_VLINK) pkt->netmask = IPA_NONE; |
77539c44 | 209 | pkt->helloint = ntohs(ifa->helloint); |
621ccdfe | 210 | pkt->options = ifa->oa->opt.byte; |
77539c44 | 211 | pkt->priority = ifa->priority; |
d8c7d9e8 | 212 | pkt->deadint = htonl(ifa->dead); |
77539c44 | 213 | pkt->dr = ifa->drip; |
099c017f | 214 | ipa_hton(pkt->dr); |
77539c44 | 215 | pkt->bdr = ifa->bdrip; |
099c017f | 216 | ipa_hton(pkt->bdr); |
e5b5d18c OF |
217 | |
218 | /* Fill all neighbors */ | |
77539c44 OF |
219 | i = 0; |
220 | pp = (u32 *) (((u8 *) pkt) + sizeof(struct ospf_hello_packet)); | |
221 | WALK_LIST(neigh, ifa->neigh_list) | |
e5b5d18c | 222 | { |
3e2bd0f1 OF |
223 | if ((i+1) * sizeof(u32) + sizeof(struct ospf_hello_packet) > ospf_pkt_maxsize(ifa)) |
224 | { | |
225 | OSPF_TRACE(D_PACKETS, "Too many neighbors on the interface!"); | |
226 | break; | |
227 | } | |
77539c44 | 228 | *(pp + i) = htonl(neigh->rid); |
e5b5d18c OF |
229 | i++; |
230 | } | |
231 | ||
77539c44 OF |
232 | length = sizeof(struct ospf_hello_packet) + i * sizeof(u32); |
233 | op->length = htons(length); | |
e5b5d18c | 234 | |
98ac6176 | 235 | switch(ifa->type) |
e5b5d18c | 236 | { |
98ac6176 OF |
237 | case OSPF_IT_NBMA: |
238 | if (timer == NULL) /* Response to received hello */ | |
e5b5d18c | 239 | { |
3e2bd0f1 | 240 | ospf_send_to(ifa->ip_sk, dirn->ip, ifa); |
e5b5d18c | 241 | } |
98ac6176 | 242 | else |
a190e720 | 243 | { |
98ac6176 OF |
244 | int toall = 0; |
245 | int meeli = 0; | |
246 | if (ifa->state > OSPF_IS_DROTHER) | |
247 | toall = 1; | |
248 | if (ifa->priority > 0) | |
249 | meeli = 1; | |
250 | ||
251 | WALK_LIST(nb, ifa->nbma_list) | |
252 | { | |
253 | send = 1; | |
254 | WALK_LIST(n1, ifa->neigh_list) | |
255 | { | |
a417ad13 | 256 | if (ipa_equal(nb->ip, n1->ip)) |
98ac6176 OF |
257 | { |
258 | send = 0; | |
259 | break; | |
260 | } | |
261 | } | |
262 | if ((poll == 1) && (send)) | |
263 | { | |
264 | if (toall || (meeli && nb->eligible)) | |
3e2bd0f1 | 265 | ospf_send_to(ifa->ip_sk, nb->ip, ifa); |
98ac6176 OF |
266 | } |
267 | } | |
268 | if (poll == 0) | |
269 | { | |
270 | WALK_LIST(n1, ifa->neigh_list) | |
271 | { | |
272 | if (toall || (n1->rid == ifa->drid) || (n1->rid == ifa->bdrid) || | |
273 | (meeli && (n1->priority > 0))) | |
3e2bd0f1 | 274 | ospf_send_to(ifa->ip_sk, n1->ip, ifa); |
98ac6176 OF |
275 | } |
276 | } | |
a190e720 | 277 | } |
98ac6176 OF |
278 | break; |
279 | case OSPF_IT_VLINK: | |
3e2bd0f1 | 280 | ospf_send_to(ifa->ip_sk, ifa->vip, ifa); |
98ac6176 OF |
281 | break; |
282 | default: | |
3e2bd0f1 | 283 | ospf_send_to(ifa->hello_sk, IPA_NONE, ifa); |
e5b5d18c | 284 | } |
3b16080c OF |
285 | OSPF_TRACE(D_PACKETS, "Hello sent via %s%s", |
286 | (ifa->type == OSPF_IT_VLINK ? "vlink-" : ""), ifa->iface->name); | |
4364b47e | 287 | } |