]>
Commit | Line | Data |
---|---|---|
c01e3741 MM |
1 | /* |
2 | * BIRD -- BGP Packet Processing | |
3 | * | |
4 | * (c) 2000 Martin Mares <mj@ucw.cz> | |
5 | * | |
6 | * Can be freely distributed and used under the terms of the GNU GPL. | |
7 | */ | |
8 | ||
85368cd4 | 9 | #undef LOCAL_DEBUG |
72a6ef11 | 10 | |
c01e3741 MM |
11 | #include "nest/bird.h" |
12 | #include "nest/iface.h" | |
13 | #include "nest/protocol.h" | |
14 | #include "nest/route.h" | |
11cb6202 | 15 | #include "nest/attrs.h" |
c01e3741 | 16 | #include "conf/conf.h" |
72a6ef11 MM |
17 | #include "lib/unaligned.h" |
18 | #include "lib/socket.h" | |
c01e3741 | 19 | |
11b32d91 OZ |
20 | #include "nest/cli.h" |
21 | ||
c01e3741 | 22 | #include "bgp.h" |
72a6ef11 | 23 | |
cb530392 OZ |
24 | static struct rate_limit rl_rcv_update, rl_snd_update; |
25 | ||
72a6ef11 MM |
26 | static byte * |
27 | bgp_create_notification(struct bgp_conn *conn, byte *buf) | |
28 | { | |
85368cd4 MM |
29 | struct bgp_proto *p = conn->bgp; |
30 | ||
31 | BGP_TRACE(D_PACKETS, "Sending NOTIFICATION(code=%d.%d)", conn->notify_code, conn->notify_subcode); | |
72a6ef11 MM |
32 | buf[0] = conn->notify_code; |
33 | buf[1] = conn->notify_subcode; | |
efcece2d MM |
34 | memcpy(buf+2, conn->notify_data, conn->notify_size); |
35 | return buf + 2 + conn->notify_size; | |
72a6ef11 MM |
36 | } |
37 | ||
11cb6202 OZ |
38 | #ifdef IPV6 |
39 | static byte * | |
40 | bgp_put_cap_ipv6(struct bgp_conn *conn UNUSED, byte *buf) | |
41 | { | |
42 | *buf++ = 1; /* Capability 1: Multiprotocol extensions */ | |
43 | *buf++ = 4; /* Capability data length */ | |
44 | *buf++ = 0; /* We support AF IPv6 */ | |
45 | *buf++ = BGP_AF_IPV6; | |
46 | *buf++ = 0; /* RFU */ | |
47 | *buf++ = 1; /* and SAFI 1 */ | |
48 | return buf; | |
49 | } | |
50 | #endif | |
51 | ||
52 | static byte * | |
53 | bgp_put_cap_as4(struct bgp_conn *conn, byte *buf) | |
54 | { | |
55 | *buf++ = 65; /* Capability 65: Support for 4-octet AS number */ | |
56 | *buf++ = 4; /* Capability data length */ | |
57 | put_u32(buf, conn->bgp->local_as); | |
58 | return buf + 4; | |
59 | } | |
60 | ||
72a6ef11 MM |
61 | static byte * |
62 | bgp_create_open(struct bgp_conn *conn, byte *buf) | |
63 | { | |
85368cd4 | 64 | struct bgp_proto *p = conn->bgp; |
11cb6202 OZ |
65 | byte *cap; |
66 | int cap_len; | |
85368cd4 MM |
67 | |
68 | BGP_TRACE(D_PACKETS, "Sending OPEN(ver=%d,as=%d,hold=%d,id=%08x)", | |
69 | BGP_VERSION, p->local_as, p->cf->hold_time, p->local_id); | |
72a6ef11 | 70 | buf[0] = BGP_VERSION; |
11cb6202 | 71 | put_u16(buf+1, (p->local_as < 0xFFFF) ? p->local_as : AS_TRANS); |
85368cd4 MM |
72 | put_u16(buf+3, p->cf->hold_time); |
73 | put_u32(buf+5, p->local_id); | |
165a6227 OZ |
74 | |
75 | if (conn->start_state == BSS_CONNECT_NOCAP) | |
76 | { | |
77 | BGP_TRACE(D_PACKETS, "Skipping capabilities"); | |
78 | buf[9] = 0; | |
79 | return buf + 10; | |
80 | } | |
81 | ||
11cb6202 OZ |
82 | /* Skipped 3 B for length field and Capabilities parameter header */ |
83 | cap = buf + 12; | |
84 | ||
85 | #ifdef IPV6 | |
86 | cap = bgp_put_cap_ipv6(conn, cap); | |
8c92bf6a | 87 | #endif |
165a6227 | 88 | if (conn->want_as4_support) |
11cb6202 OZ |
89 | cap = bgp_put_cap_as4(conn, cap); |
90 | ||
91 | cap_len = cap - buf - 12; | |
92 | if (cap_len > 0) | |
93 | { | |
94 | buf[9] = cap_len + 2; /* Optional params len */ | |
95 | buf[10] = 2; /* Option: Capability list */ | |
96 | buf[11] = cap_len; /* Option length */ | |
97 | return cap; | |
98 | } | |
99 | else | |
100 | { | |
101 | buf[9] = 0; /* No optional parameters */ | |
102 | return buf + 10; | |
103 | } | |
72a6ef11 MM |
104 | } |
105 | ||
f421cfdd MM |
106 | static unsigned int |
107 | bgp_encode_prefixes(struct bgp_proto *p, byte *w, struct bgp_bucket *buck, unsigned int remains) | |
108 | { | |
109 | byte *start = w; | |
110 | ip_addr a; | |
111 | int bytes; | |
112 | ||
113 | while (!EMPTY_LIST(buck->prefixes) && remains >= 5) | |
114 | { | |
115 | struct bgp_prefix *px = SKIP_BACK(struct bgp_prefix, bucket_node, HEAD(buck->prefixes)); | |
116 | DBG("\tDequeued route %I/%d\n", px->n.prefix, px->n.pxlen); | |
117 | *w++ = px->n.pxlen; | |
118 | bytes = (px->n.pxlen + 7) / 8; | |
119 | a = px->n.prefix; | |
120 | ipa_hton(a); | |
121 | memcpy(w, &a, bytes); | |
122 | w += bytes; | |
0c3588bf | 123 | remains -= bytes + 1; |
f421cfdd MM |
124 | rem_node(&px->bucket_node); |
125 | fib_delete(&p->prefix_fib, px); | |
126 | } | |
127 | return w - start; | |
128 | } | |
129 | ||
1c1da87b MM |
130 | #ifndef IPV6 /* IPv4 version */ |
131 | ||
72a6ef11 MM |
132 | static byte * |
133 | bgp_create_update(struct bgp_conn *conn, byte *buf) | |
134 | { | |
85368cd4 | 135 | struct bgp_proto *p = conn->bgp; |
f421cfdd MM |
136 | struct bgp_bucket *buck; |
137 | int remains = BGP_MAX_PACKET_LENGTH - BGP_HEADER_LENGTH - 4; | |
cf3d6470 | 138 | byte *w; |
f421cfdd MM |
139 | int wd_size = 0; |
140 | int r_size = 0; | |
cf3d6470 | 141 | int a_size = 0; |
f421cfdd | 142 | |
f421cfdd | 143 | w = buf+2; |
85368cd4 | 144 | if ((buck = p->withdraw_bucket) && !EMPTY_LIST(buck->prefixes)) |
f421cfdd MM |
145 | { |
146 | DBG("Withdrawn routes:\n"); | |
85368cd4 | 147 | wd_size = bgp_encode_prefixes(p, w, buck, remains); |
f421cfdd MM |
148 | w += wd_size; |
149 | remains -= wd_size; | |
150 | } | |
151 | put_u16(buf, wd_size); | |
3fdbafb6 | 152 | |
f421cfdd MM |
153 | if (remains >= 2048) |
154 | { | |
85368cd4 | 155 | while ((buck = (struct bgp_bucket *) HEAD(p->bucket_queue))->send_node.next) |
f421cfdd MM |
156 | { |
157 | if (EMPTY_LIST(buck->prefixes)) | |
158 | { | |
159 | DBG("Deleting empty bucket %p\n", buck); | |
160 | rem_node(&buck->send_node); | |
85368cd4 | 161 | bgp_free_bucket(p, buck); |
f421cfdd MM |
162 | continue; |
163 | } | |
164 | DBG("Processing bucket %p\n", buck); | |
11cb6202 | 165 | a_size = bgp_encode_attrs(p, w+2, buck->eattrs, 1024); |
cf3d6470 MM |
166 | put_u16(w, a_size); |
167 | w += a_size + 2; | |
168 | r_size = bgp_encode_prefixes(p, w, buck, remains - a_size); | |
f421cfdd MM |
169 | w += r_size; |
170 | break; | |
171 | } | |
172 | } | |
507eea4c | 173 | if (!a_size) /* Attributes not already encoded */ |
f421cfdd MM |
174 | { |
175 | put_u16(w, 0); | |
176 | w += 2; | |
177 | } | |
d2a7c0e9 MM |
178 | if (wd_size || r_size) |
179 | { | |
cb530392 | 180 | BGP_TRACE_RL(&rl_snd_update, D_PACKETS, "Sending UPDATE"); |
d2a7c0e9 MM |
181 | return w; |
182 | } | |
183 | else | |
184 | return NULL; | |
72a6ef11 MM |
185 | } |
186 | ||
1c1da87b MM |
187 | #else /* IPv6 version */ |
188 | ||
189 | static byte * | |
190 | bgp_create_update(struct bgp_conn *conn, byte *buf) | |
191 | { | |
cf3d6470 MM |
192 | struct bgp_proto *p = conn->bgp; |
193 | struct bgp_bucket *buck; | |
194 | int size, is_ll; | |
195 | int remains = BGP_MAX_PACKET_LENGTH - BGP_HEADER_LENGTH - 4; | |
196 | byte *w, *tmp, *tstart; | |
197 | ip_addr ip, ip_ll; | |
198 | ea_list *ea; | |
199 | eattr *nh; | |
200 | neighbor *n; | |
201 | ||
cf3d6470 MM |
202 | put_u16(buf, 0); |
203 | w = buf+4; | |
204 | ||
205 | if ((buck = p->withdraw_bucket) && !EMPTY_LIST(buck->prefixes)) | |
206 | { | |
207 | DBG("Withdrawn routes:\n"); | |
4847a894 | 208 | tmp = bgp_attach_attr_wa(&ea, bgp_linpool, BA_MP_UNREACH_NLRI, remains-8); |
cf3d6470 MM |
209 | *tmp++ = 0; |
210 | *tmp++ = BGP_AF_IPV6; | |
211 | *tmp++ = 1; | |
212 | ea->attrs[0].u.ptr->length = bgp_encode_prefixes(p, tmp, buck, remains-11); | |
11cb6202 | 213 | size = bgp_encode_attrs(p, w, ea, remains); |
cf3d6470 MM |
214 | w += size; |
215 | remains -= size; | |
216 | } | |
217 | ||
218 | if (remains >= 2048) | |
219 | { | |
220 | while ((buck = (struct bgp_bucket *) HEAD(p->bucket_queue))->send_node.next) | |
221 | { | |
222 | if (EMPTY_LIST(buck->prefixes)) | |
223 | { | |
224 | DBG("Deleting empty bucket %p\n", buck); | |
225 | rem_node(&buck->send_node); | |
226 | bgp_free_bucket(p, buck); | |
227 | continue; | |
228 | } | |
229 | DBG("Processing bucket %p\n", buck); | |
11cb6202 | 230 | size = bgp_encode_attrs(p, w, buck->eattrs, 1024); |
cf3d6470 MM |
231 | w += size; |
232 | remains -= size; | |
4847a894 | 233 | tstart = tmp = bgp_attach_attr_wa(&ea, bgp_linpool, BA_MP_REACH_NLRI, remains-8); |
cf3d6470 MM |
234 | *tmp++ = 0; |
235 | *tmp++ = BGP_AF_IPV6; | |
236 | *tmp++ = 1; | |
237 | nh = ea_find(buck->eattrs, EA_CODE(EAP_BGP, BA_NEXT_HOP)); | |
238 | ASSERT(nh); | |
239 | ip = *(ip_addr *) nh->u.ptr->data; | |
11d4474c | 240 | is_ll = 0; |
cf3d6470 | 241 | if (ipa_equal(ip, p->local_addr)) |
11d4474c MM |
242 | { |
243 | is_ll = 1; | |
244 | ip_ll = p->local_link; | |
245 | } | |
cf3d6470 MM |
246 | else |
247 | { | |
248 | n = neigh_find(&p->p, &ip, 0); | |
249 | if (n && n->iface == p->neigh->iface) | |
11d4474c MM |
250 | { |
251 | /* FIXME: We are assuming the global scope addresses use the lower 64 bits | |
252 | * as an interface identifier which hasn't necessarily to be true. | |
253 | */ | |
254 | is_ll = 1; | |
255 | ip_ll = ipa_or(ipa_build(0xfe800000,0,0,0), ipa_and(ip, ipa_build(0,0,~0,~0))); | |
256 | } | |
cf3d6470 MM |
257 | } |
258 | if (is_ll) | |
259 | { | |
260 | *tmp++ = 32; | |
cf3d6470 MM |
261 | ipa_hton(ip); |
262 | memcpy(tmp, &ip, 16); | |
263 | ipa_hton(ip_ll); | |
264 | memcpy(tmp+16, &ip_ll, 16); | |
265 | tmp += 32; | |
266 | } | |
267 | else | |
268 | { | |
269 | *tmp++ = 16; | |
270 | ipa_hton(ip); | |
271 | memcpy(tmp, &ip, 16); | |
272 | tmp += 16; | |
273 | } | |
274 | *tmp++ = 0; /* No SNPA information */ | |
275 | tmp += bgp_encode_prefixes(p, tmp, buck, remains - (8+3+32+1)); | |
276 | ea->attrs[0].u.ptr->length = tmp - tstart; | |
11cb6202 | 277 | w += bgp_encode_attrs(p, w, ea, remains); |
cf3d6470 MM |
278 | break; |
279 | } | |
280 | } | |
281 | ||
282 | size = w - (buf+4); | |
283 | put_u16(buf+2, size); | |
284 | lp_flush(bgp_linpool); | |
d2a7c0e9 MM |
285 | if (size) |
286 | { | |
cb530392 | 287 | BGP_TRACE_RL(&rl_snd_update, D_PACKETS, "Sending UPDATE"); |
d2a7c0e9 MM |
288 | return w; |
289 | } | |
290 | else | |
291 | return NULL; | |
1c1da87b MM |
292 | } |
293 | ||
294 | #endif | |
295 | ||
72a6ef11 MM |
296 | static void |
297 | bgp_create_header(byte *buf, unsigned int len, unsigned int type) | |
298 | { | |
299 | memset(buf, 0xff, 16); /* Marker */ | |
300 | put_u16(buf+16, len); | |
301 | buf[18] = type; | |
302 | } | |
303 | ||
54e55169 MM |
304 | /** |
305 | * bgp_fire_tx - transmit packets | |
306 | * @conn: connection | |
307 | * | |
308 | * Whenever the transmit buffers of the underlying TCP connection | |
309 | * are free and we have any packets queued for sending, the socket functions | |
310 | * call bgp_fire_tx() which takes care of selecting the highest priority packet | |
311 | * queued (Notification > Keepalive > Open > Update), assembling its header | |
312 | * and body and sending it to the connection. | |
313 | */ | |
3fdbafb6 | 314 | static int |
72a6ef11 MM |
315 | bgp_fire_tx(struct bgp_conn *conn) |
316 | { | |
85368cd4 | 317 | struct bgp_proto *p = conn->bgp; |
72a6ef11 MM |
318 | unsigned int s = conn->packets_to_send; |
319 | sock *sk = conn->sk; | |
0c3588bf | 320 | byte *buf, *pkt, *end; |
72a6ef11 MM |
321 | int type; |
322 | ||
0c3588bf MM |
323 | if (!sk) |
324 | { | |
325 | conn->packets_to_send = 0; | |
326 | return 0; | |
327 | } | |
328 | buf = sk->tbuf; | |
329 | pkt = buf + BGP_HEADER_LENGTH; | |
330 | ||
72a6ef11 MM |
331 | if (s & (1 << PKT_SCHEDULE_CLOSE)) |
332 | { | |
11b32d91 OZ |
333 | /* We can finally close connection and enter idle state */ |
334 | bgp_conn_enter_idle_state(conn); | |
3fdbafb6 | 335 | return 0; |
72a6ef11 MM |
336 | } |
337 | if (s & (1 << PKT_NOTIFICATION)) | |
338 | { | |
339 | s = 1 << PKT_SCHEDULE_CLOSE; | |
340 | type = PKT_NOTIFICATION; | |
341 | end = bgp_create_notification(conn, pkt); | |
342 | } | |
343 | else if (s & (1 << PKT_KEEPALIVE)) | |
344 | { | |
345 | s &= ~(1 << PKT_KEEPALIVE); | |
346 | type = PKT_KEEPALIVE; | |
347 | end = pkt; /* Keepalives carry no data */ | |
85368cd4 | 348 | BGP_TRACE(D_PACKETS, "Sending KEEPALIVE"); |
3fdbafb6 | 349 | bgp_start_timer(conn->keepalive_timer, conn->keepalive_time); |
72a6ef11 MM |
350 | } |
351 | else if (s & (1 << PKT_OPEN)) | |
352 | { | |
353 | s &= ~(1 << PKT_OPEN); | |
354 | type = PKT_OPEN; | |
355 | end = bgp_create_open(conn, pkt); | |
356 | } | |
357 | else if (s & (1 << PKT_UPDATE)) | |
358 | { | |
359 | end = bgp_create_update(conn, pkt); | |
360 | type = PKT_UPDATE; | |
361 | if (!end) | |
362 | { | |
363 | conn->packets_to_send = 0; | |
3fdbafb6 | 364 | return 0; |
72a6ef11 MM |
365 | } |
366 | } | |
367 | else | |
3fdbafb6 | 368 | return 0; |
72a6ef11 MM |
369 | conn->packets_to_send = s; |
370 | bgp_create_header(buf, end - buf, type); | |
3fdbafb6 | 371 | return sk_send(sk, end - buf); |
72a6ef11 MM |
372 | } |
373 | ||
54e55169 MM |
374 | /** |
375 | * bgp_schedule_packet - schedule a packet for transmission | |
376 | * @conn: connection | |
377 | * @type: packet type | |
378 | * | |
379 | * Schedule a packet of type @type to be sent as soon as possible. | |
380 | */ | |
72a6ef11 MM |
381 | void |
382 | bgp_schedule_packet(struct bgp_conn *conn, int type) | |
383 | { | |
384 | DBG("BGP: Scheduling packet type %d\n", type); | |
385 | conn->packets_to_send |= 1 << type; | |
0c3588bf | 386 | if (conn->sk && conn->sk->tpos == conn->sk->tbuf) |
11b32d91 OZ |
387 | ev_schedule(conn->tx_ev); |
388 | } | |
389 | ||
390 | void | |
391 | bgp_kick_tx(void *vconn) | |
392 | { | |
393 | struct bgp_conn *conn = vconn; | |
394 | ||
395 | DBG("BGP: kicking TX\n"); | |
396 | while (bgp_fire_tx(conn)) | |
397 | ; | |
72a6ef11 MM |
398 | } |
399 | ||
400 | void | |
401 | bgp_tx(sock *sk) | |
402 | { | |
403 | struct bgp_conn *conn = sk->data; | |
404 | ||
405 | DBG("BGP: TX hook\n"); | |
3fdbafb6 MM |
406 | while (bgp_fire_tx(conn)) |
407 | ; | |
408 | } | |
409 | ||
11cb6202 OZ |
410 | /* Capatibility negotiation as per RFC 2842 */ |
411 | ||
412 | void | |
413 | bgp_parse_capabilities(struct bgp_conn *conn, byte *opt, int len) | |
414 | { | |
415 | struct bgp_proto *p = conn->bgp; | |
416 | int cl; | |
417 | u32 as; | |
418 | ||
419 | while (len > 0) | |
420 | { | |
421 | if (len < 2 || len < 2 + opt[1]) | |
422 | goto err; | |
423 | ||
424 | cl = opt[1]; | |
425 | ||
426 | switch (opt[0]) | |
427 | { | |
428 | case 65: | |
429 | if (cl != 4) | |
430 | goto err; | |
165a6227 OZ |
431 | conn->peer_as4_support = 1; |
432 | if (conn->want_as4_support) | |
11cb6202 OZ |
433 | conn->advertised_as = get_u32(opt + 2); |
434 | break; | |
435 | ||
436 | /* We can safely ignore all other capabilities */ | |
437 | } | |
438 | len -= 2 + cl; | |
439 | opt += 2 + cl; | |
440 | } | |
441 | return; | |
442 | ||
443 | err: | |
444 | bgp_error(conn, 2, 0, NULL, 0); | |
445 | return; | |
446 | } | |
447 | ||
a47a0108 MM |
448 | static int |
449 | bgp_parse_options(struct bgp_conn *conn, byte *opt, int len) | |
450 | { | |
11cb6202 OZ |
451 | int ol; |
452 | ||
a47a0108 MM |
453 | while (len > 0) |
454 | { | |
455 | if (len < 2 || len < 2 + opt[1]) | |
efcece2d | 456 | { bgp_error(conn, 2, 0, NULL, 0); return 0; } |
a47a0108 MM |
457 | #ifdef LOCAL_DEBUG |
458 | { | |
459 | int i; | |
460 | DBG("\tOption %02x:", opt[0]); | |
461 | for(i=0; i<opt[1]; i++) | |
462 | DBG(" %02x", opt[2+i]); | |
463 | DBG("\n"); | |
464 | } | |
465 | #endif | |
11cb6202 OZ |
466 | |
467 | ol = opt[1]; | |
a47a0108 MM |
468 | switch (opt[0]) |
469 | { | |
470 | case 2: | |
11cb6202 | 471 | bgp_parse_capabilities(conn, opt + 2, ol); |
a47a0108 | 472 | break; |
11cb6202 | 473 | |
a47a0108 MM |
474 | default: |
475 | /* | |
476 | * BGP specs don't tell us to send which option | |
477 | * we didn't recognize, but it's common practice | |
478 | * to do so. Also, capability negotiation with | |
479 | * Cisco routers doesn't work without that. | |
480 | */ | |
11cb6202 | 481 | bgp_error(conn, 2, 4, opt, ol); |
a47a0108 MM |
482 | return 0; |
483 | } | |
11cb6202 OZ |
484 | len -= 2 + ol; |
485 | opt += 2 + ol; | |
a47a0108 MM |
486 | } |
487 | return 0; | |
488 | } | |
489 | ||
3fdbafb6 MM |
490 | static void |
491 | bgp_rx_open(struct bgp_conn *conn, byte *pkt, int len) | |
492 | { | |
b552ecc4 | 493 | struct bgp_conn *other; |
3fdbafb6 MM |
494 | struct bgp_proto *p = conn->bgp; |
495 | struct bgp_config *cf = p->cf; | |
11cb6202 | 496 | unsigned hold; |
3fdbafb6 MM |
497 | u32 id; |
498 | ||
499 | /* Check state */ | |
500 | if (conn->state != BS_OPENSENT) | |
11b32d91 | 501 | { bgp_error(conn, 5, 0, NULL, 0); return; } |
3fdbafb6 MM |
502 | |
503 | /* Check message contents */ | |
504 | if (len < 29 || len != 29 + pkt[28]) | |
efcece2d | 505 | { bgp_error(conn, 1, 2, pkt+16, 2); return; } |
3fdbafb6 | 506 | if (pkt[19] != BGP_VERSION) |
efcece2d | 507 | { bgp_error(conn, 2, 1, pkt+19, 1); return; } /* RFC 1771 says 16 bits, draft-09 tells to use 8 */ |
11cb6202 | 508 | conn->advertised_as = get_u16(pkt+20); |
3fdbafb6 MM |
509 | hold = get_u16(pkt+22); |
510 | id = get_u32(pkt+24); | |
11cb6202 OZ |
511 | BGP_TRACE(D_PACKETS, "Got OPEN(as=%d,hold=%d,id=%08x)", conn->advertised_as, hold, id); |
512 | ||
a47a0108 MM |
513 | if (bgp_parse_options(conn, pkt+29, pkt[28])) |
514 | return; | |
11cb6202 OZ |
515 | |
516 | if (hold > 0 && hold < 3) | |
517 | { bgp_error(conn, 2, 6, pkt+22, 2); return; } | |
518 | ||
3fdbafb6 | 519 | if (!id || id == 0xffffffff || id == p->local_id) |
efcece2d | 520 | { bgp_error(conn, 2, 3, pkt+24, -4); return; } |
3fdbafb6 | 521 | |
11cb6202 OZ |
522 | if (conn->advertised_as != p->remote_as) |
523 | { | |
524 | bgp_error(conn, 2, 2, (byte *) &(conn->advertised_as), -4); return; | |
525 | } | |
526 | ||
b552ecc4 MM |
527 | /* Check the other connection */ |
528 | other = (conn == &p->outgoing_conn) ? &p->incoming_conn : &p->outgoing_conn; | |
529 | switch (other->state) | |
530 | { | |
531 | case BS_IDLE: | |
b552ecc4 MM |
532 | case BS_CONNECT: |
533 | case BS_ACTIVE: | |
534 | case BS_OPENSENT: | |
11b32d91 | 535 | case BS_CLOSE: |
b552ecc4 MM |
536 | break; |
537 | case BS_OPENCONFIRM: | |
538 | if ((p->local_id < id) == (conn == &p->incoming_conn)) | |
539 | { | |
540 | /* Should close the other connection */ | |
85368cd4 | 541 | BGP_TRACE(D_EVENTS, "Connection collision, giving up the other connection"); |
efcece2d | 542 | bgp_error(other, 6, 0, NULL, 0); |
b552ecc4 MM |
543 | break; |
544 | } | |
545 | /* Fall thru */ | |
546 | case BS_ESTABLISHED: | |
547 | /* Should close this connection */ | |
85368cd4 | 548 | BGP_TRACE(D_EVENTS, "Connection collision, giving up this connection"); |
efcece2d | 549 | bgp_error(conn, 6, 0, NULL, 0); |
b552ecc4 MM |
550 | return; |
551 | default: | |
552 | bug("bgp_rx_open: Unknown state"); | |
553 | } | |
554 | ||
3fdbafb6 | 555 | /* Update our local variables */ |
11b32d91 | 556 | conn->hold_time = MIN(hold, p->cf->hold_time); |
3fdbafb6 | 557 | conn->keepalive_time = p->cf->keepalive_time ? : conn->hold_time / 3; |
3fdbafb6 | 558 | p->remote_id = id; |
165a6227 OZ |
559 | p->as4_session = conn->want_as4_support && conn->peer_as4_support; |
560 | ||
11b32d91 | 561 | DBG("BGP: Hold timer set to %d, keepalive to %d, AS to %d, ID to %x, AS4 session to %d\n", conn->hold_time, conn->keepalive_time, p->remote_as, p->remote_id, p->as4_session); |
3fdbafb6 MM |
562 | |
563 | bgp_schedule_packet(conn, PKT_KEEPALIVE); | |
564 | bgp_start_timer(conn->hold_timer, conn->hold_time); | |
565 | conn->state = BS_OPENCONFIRM; | |
566 | } | |
567 | ||
973399ae MM |
568 | #define DECODE_PREFIX(pp, ll) do { \ |
569 | int b = *pp++; \ | |
570 | int q; \ | |
973399ae | 571 | ll--; \ |
1c1da87b | 572 | if (b > BITS_PER_IP_ADDRESS) { err=10; goto bad; } \ |
973399ae | 573 | q = (b+7) / 8; \ |
1c1da87b | 574 | if (ll < q) { err=1; goto bad; } \ |
c00d31be | 575 | memcpy(&prefix, pp, q); \ |
973399ae MM |
576 | pp += q; \ |
577 | ll -= q; \ | |
f421cfdd MM |
578 | ipa_ntoh(prefix); \ |
579 | prefix = ipa_and(prefix, ipa_mkmask(b)); \ | |
c00d31be | 580 | pxlen = b; \ |
973399ae MM |
581 | } while (0) |
582 | ||
1c1da87b MM |
583 | static inline int |
584 | bgp_get_nexthop(struct bgp_proto *bgp, rta *a) | |
585 | { | |
586 | neighbor *neigh; | |
587 | ip_addr nexthop; | |
588 | struct eattr *nh = ea_find(a->eattrs, EA_CODE(EAP_BGP, BA_NEXT_HOP)); | |
589 | ASSERT(nh); | |
590 | nexthop = *(ip_addr *) nh->u.ptr->data; | |
bc00185e MM |
591 | neigh = neigh_find(&bgp->p, &nexthop, 0); |
592 | if (neigh) | |
1c1da87b | 593 | { |
bc00185e MM |
594 | if (neigh->scope == SCOPE_HOST) |
595 | { | |
596 | DBG("BGP: Loop!\n"); | |
597 | return 0; | |
598 | } | |
1c1da87b | 599 | } |
bc00185e MM |
600 | else |
601 | neigh = bgp->neigh; | |
1c1da87b MM |
602 | a->gw = neigh->addr; |
603 | a->iface = neigh->iface; | |
604 | return 1; | |
605 | } | |
606 | ||
607 | #ifndef IPV6 /* IPv4 version */ | |
608 | ||
3fdbafb6 | 609 | static void |
1c1da87b MM |
610 | bgp_do_rx_update(struct bgp_conn *conn, |
611 | byte *withdrawn, int withdrawn_len, | |
612 | byte *nlri, int nlri_len, | |
613 | byte *attrs, int attr_len) | |
3fdbafb6 | 614 | { |
85368cd4 | 615 | struct bgp_proto *p = conn->bgp; |
1c1da87b MM |
616 | rta *a0; |
617 | rta *a = NULL; | |
c00d31be | 618 | ip_addr prefix; |
c00d31be | 619 | net *n; |
1c1da87b | 620 | int err = 0, pxlen; |
973399ae MM |
621 | |
622 | /* Withdraw routes */ | |
623 | while (withdrawn_len) | |
624 | { | |
625 | DECODE_PREFIX(withdrawn, withdrawn_len); | |
c00d31be | 626 | DBG("Withdraw %I/%d\n", prefix, pxlen); |
85368cd4 MM |
627 | if (n = net_find(p->p.table, prefix, pxlen)) |
628 | rte_update(p->p.table, n, &p->p, NULL); | |
973399ae MM |
629 | } |
630 | ||
f94557de MM |
631 | if (!attr_len && !nlri_len) /* shortcut */ |
632 | return; | |
633 | ||
2a9e064d | 634 | a0 = bgp_decode_attrs(conn, attrs, attr_len, bgp_linpool, nlri_len); |
1c1da87b | 635 | if (a0 && nlri_len && bgp_get_nexthop(p, a0)) |
973399ae | 636 | { |
2a9e064d | 637 | a = rta_lookup(a0); |
c00d31be | 638 | while (nlri_len) |
973399ae | 639 | { |
c00d31be | 640 | rte *e; |
f8809249 | 641 | DECODE_PREFIX(nlri, nlri_len); |
c00d31be | 642 | DBG("Add %I/%d\n", prefix, pxlen); |
f8809249 | 643 | e = rte_get_temp(rta_clone(a)); |
85368cd4 | 644 | n = net_get(p->p.table, prefix, pxlen); |
c00d31be MM |
645 | e->net = n; |
646 | e->pflags = 0; | |
85368cd4 | 647 | rte_update(p->p.table, n, &p->p, e); |
973399ae | 648 | } |
973399ae | 649 | } |
1c1da87b MM |
650 | bad: |
651 | if (a) | |
652 | rta_free(a); | |
653 | if (err) | |
654 | bgp_error(conn, 3, err, NULL, 0); | |
f8809249 | 655 | return; |
1c1da87b | 656 | } |
f8809249 | 657 | |
1c1da87b MM |
658 | #else /* IPv6 version */ |
659 | ||
660 | #define DO_NLRI(name) \ | |
661 | start = x = p->name##_start; \ | |
662 | len = len0 = p->name##_len; \ | |
663 | if (len) \ | |
664 | { \ | |
665 | if (len < 3) goto bad; \ | |
666 | af = get_u16(x); \ | |
667 | sub = x[2]; \ | |
668 | x += 3; \ | |
669 | len -= 3; \ | |
670 | DBG("\tNLRI AF=%d sub=%d len=%d\n", af, sub, len);\ | |
671 | } \ | |
672 | else \ | |
673 | af = 0; \ | |
674 | if (af == BGP_AF_IPV6) | |
675 | ||
676 | static void | |
677 | bgp_do_rx_update(struct bgp_conn *conn, | |
678 | byte *withdrawn, int withdrawn_len, | |
679 | byte *nlri, int nlri_len, | |
680 | byte *attrs, int attr_len) | |
681 | { | |
682 | struct bgp_proto *p = conn->bgp; | |
683 | byte *start, *x; | |
684 | int len, len0; | |
685 | unsigned af, sub; | |
686 | rta *a0; | |
687 | rta *a = NULL; | |
688 | ip_addr prefix; | |
689 | net *n; | |
690 | rte e; | |
691 | int err = 0, pxlen; | |
692 | ||
693 | p->mp_reach_len = 0; | |
694 | p->mp_unreach_len = 0; | |
695 | a0 = bgp_decode_attrs(conn, attrs, attr_len, bgp_linpool, 0); | |
696 | if (!a0) | |
697 | return; | |
698 | ||
699 | DO_NLRI(mp_unreach) | |
700 | { | |
701 | while (len) | |
702 | { | |
703 | DECODE_PREFIX(x, len); | |
704 | DBG("Withdraw %I/%d\n", prefix, pxlen); | |
705 | if (n = net_find(p->p.table, prefix, pxlen)) | |
706 | rte_update(p->p.table, n, &p->p, NULL); | |
707 | } | |
708 | } | |
709 | ||
710 | DO_NLRI(mp_reach) | |
711 | { | |
1c1da87b MM |
712 | int i; |
713 | ||
714 | /* Create fake NEXT_HOP attribute */ | |
715 | if (len < 1 || (*x != 16 && *x != 32) || len < *x + 2) | |
716 | goto bad; | |
1389f369 | 717 | memcpy(bgp_attach_attr_wa(&a0->eattrs, bgp_linpool, BA_NEXT_HOP, 16), x+1, 16); |
60a72ed4 | 718 | len -= *x + 2; |
1c1da87b MM |
719 | x += *x + 1; |
720 | ||
721 | /* Ignore SNPA info */ | |
722 | i = *x++; | |
723 | while (i--) | |
724 | { | |
725 | if (len < 1 || len < 1 + *x) | |
726 | goto bad; | |
727 | len -= *x + 1; | |
728 | x += *x + 1; | |
729 | } | |
730 | ||
731 | if (bgp_get_nexthop(p, a0)) | |
732 | { | |
733 | a = rta_lookup(a0); | |
734 | while (len) | |
735 | { | |
736 | rte *e; | |
737 | DECODE_PREFIX(x, len); | |
738 | DBG("Add %I/%d\n", prefix, pxlen); | |
739 | e = rte_get_temp(rta_clone(a)); | |
740 | n = net_get(p->p.table, prefix, pxlen); | |
741 | e->net = n; | |
742 | e->pflags = 0; | |
743 | rte_update(p->p.table, n, &p->p, e); | |
744 | } | |
745 | rta_free(a); | |
746 | } | |
747 | } | |
748 | ||
749 | return; | |
750 | ||
751 | bad: | |
752 | bgp_error(conn, 3, 9, start, len0); | |
f8809249 MM |
753 | if (a) |
754 | rta_free(a); | |
1c1da87b MM |
755 | return; |
756 | } | |
757 | ||
758 | #endif | |
759 | ||
760 | static void | |
761 | bgp_rx_update(struct bgp_conn *conn, byte *pkt, int len) | |
762 | { | |
763 | struct bgp_proto *p = conn->bgp; | |
764 | byte *withdrawn, *attrs, *nlri; | |
765 | int withdrawn_len, attr_len, nlri_len; | |
766 | ||
cb530392 OZ |
767 | BGP_TRACE_RL(&rl_rcv_update, D_PACKETS, "Got UPDATE"); |
768 | ||
1c1da87b MM |
769 | if (conn->state != BS_ESTABLISHED) |
770 | { bgp_error(conn, 5, 0, NULL, 0); return; } | |
771 | bgp_start_timer(conn->hold_timer, conn->hold_time); | |
772 | ||
773 | /* Find parts of the packet and check sizes */ | |
774 | if (len < 23) | |
775 | { | |
776 | bgp_error(conn, 1, 2, pkt+16, 2); | |
777 | return; | |
778 | } | |
779 | withdrawn = pkt + 21; | |
780 | withdrawn_len = get_u16(pkt + 19); | |
781 | if (withdrawn_len + 23 > len) | |
782 | goto malformed; | |
783 | attrs = withdrawn + withdrawn_len + 2; | |
784 | attr_len = get_u16(attrs - 2); | |
785 | if (withdrawn_len + attr_len + 23 > len) | |
786 | goto malformed; | |
787 | nlri = attrs + attr_len; | |
788 | nlri_len = len - withdrawn_len - attr_len - 23; | |
789 | if (!attr_len && nlri_len) | |
790 | goto malformed; | |
791 | DBG("Sizes: withdrawn=%d, attrs=%d, NLRI=%d\n", withdrawn_len, attr_len, nlri_len); | |
792 | ||
793 | lp_flush(bgp_linpool); | |
794 | ||
795 | bgp_do_rx_update(conn, withdrawn, withdrawn_len, nlri, nlri_len, attrs, attr_len); | |
796 | return; | |
797 | ||
798 | malformed: | |
efcece2d MM |
799 | bgp_error(conn, 3, 1, NULL, 0); |
800 | } | |
801 | ||
802 | static struct { | |
803 | byte major, minor; | |
804 | byte *msg; | |
805 | } bgp_msg_table[] = { | |
806 | { 1, 0, "Invalid message header" }, | |
807 | { 1, 1, "Connection not synchronized" }, | |
808 | { 1, 2, "Bad message length" }, | |
809 | { 1, 3, "Bad message type" }, | |
810 | { 2, 0, "Invalid OPEN message" }, | |
811 | { 2, 1, "Unsupported version number" }, | |
812 | { 2, 2, "Bad peer AS" }, | |
813 | { 2, 3, "Bad BGP identifier" }, | |
814 | { 2, 4, "Unsupported optional parameter" }, | |
815 | { 2, 5, "Authentication failure" }, | |
816 | { 2, 6, "Unacceptable hold time" }, | |
11cb6202 | 817 | { 2, 7, "Required capability missing" }, /* [RFC3392] */ |
efcece2d MM |
818 | { 3, 0, "Invalid UPDATE message" }, |
819 | { 3, 1, "Malformed attribute list" }, | |
820 | { 3, 2, "Unrecognized well-known attribute" }, | |
821 | { 3, 3, "Missing mandatory attribute" }, | |
822 | { 3, 4, "Invalid attribute flags" }, | |
823 | { 3, 5, "Invalid attribute length" }, | |
824 | { 3, 6, "Invalid ORIGIN attribute" }, | |
825 | { 3, 7, "AS routing loop" }, /* Deprecated */ | |
826 | { 3, 8, "Invalid NEXT_HOP attribute" }, | |
827 | { 3, 9, "Optional attribute error" }, | |
828 | { 3, 10, "Invalid network field" }, | |
829 | { 3, 11, "Malformed AS_PATH" }, | |
830 | { 4, 0, "Hold timer expired" }, | |
831 | { 5, 0, "Finite state machine error" }, | |
165a6227 OZ |
832 | { 6, 0, "Cease" }, /* Subcodes are according to [RFC4486] */ |
833 | { 6, 1, "Maximum number of prefixes reached" }, | |
834 | { 6, 2, "Administrative shutdown" }, | |
835 | { 6, 3, "Peer de-configured" }, | |
836 | { 6, 4, "Administrative reset" }, | |
837 | { 6, 5, "Connection rejected" }, | |
838 | { 6, 6, "Other configuration change" }, | |
839 | { 6, 7, "Connection collision resolution" }, | |
840 | { 6, 8, "Out of Resources" } | |
efcece2d MM |
841 | }; |
842 | ||
11b32d91 OZ |
843 | /** |
844 | * bgp_error_dsc - return BGP error description | |
845 | * @buff: temporary buffer | |
846 | * @code: BGP error code | |
847 | * @subcode: BGP error subcode | |
848 | * | |
849 | * bgp_error_dsc() returns error description for BGP errors | |
850 | * which might be static string or given temporary buffer. | |
851 | */ | |
852 | const byte * | |
853 | bgp_error_dsc(byte *buff, unsigned code, unsigned subcode) | |
854 | { | |
855 | unsigned i; | |
856 | for (i=0; i < ARRAY_SIZE(bgp_msg_table); i++) | |
857 | if (bgp_msg_table[i].major == code && bgp_msg_table[i].minor == subcode) | |
858 | { | |
859 | return bgp_msg_table[i].msg; | |
860 | } | |
861 | ||
862 | bsprintf(buff, "Unknown error %d.%d", code, subcode); | |
863 | return buff; | |
864 | } | |
865 | ||
efcece2d MM |
866 | void |
867 | bgp_log_error(struct bgp_proto *p, char *msg, unsigned code, unsigned subcode, byte *data, unsigned len) | |
868 | { | |
11b32d91 OZ |
869 | const byte *name; |
870 | byte namebuf[32]; | |
efcece2d MM |
871 | byte *t, argbuf[36]; |
872 | unsigned i; | |
873 | ||
85733143 MM |
874 | if (code == 6 && !subcode) /* Don't report Cease messages */ |
875 | return; | |
876 | ||
11b32d91 | 877 | name = bgp_error_dsc(namebuf, code, subcode); |
efcece2d MM |
878 | t = argbuf; |
879 | if (len) | |
880 | { | |
881 | *t++ = ':'; | |
882 | *t++ = ' '; | |
883 | if (len > 16) | |
884 | len = 16; | |
885 | for (i=0; i<len; i++) | |
886 | t += bsprintf(t, "%02x", data[i]); | |
887 | } | |
888 | *t = 0; | |
889 | log(L_REMOTE "%s: %s: %s%s", p->p.name, msg, name, argbuf); | |
3fdbafb6 MM |
890 | } |
891 | ||
892 | static void | |
893 | bgp_rx_notification(struct bgp_conn *conn, byte *pkt, int len) | |
894 | { | |
165a6227 | 895 | struct bgp_proto *p = conn->bgp; |
3fdbafb6 MM |
896 | if (len < 21) |
897 | { | |
efcece2d | 898 | bgp_error(conn, 1, 2, pkt+16, 2); |
3fdbafb6 MM |
899 | return; |
900 | } | |
11b32d91 OZ |
901 | |
902 | unsigned code = pkt[19]; | |
903 | unsigned subcode = pkt[20]; | |
165a6227 OZ |
904 | int delay = 1; |
905 | ||
906 | #ifndef IPV6 | |
907 | if ((code == 2) && ((subcode == 4) || (subcode == 7))) | |
908 | { | |
909 | /* Error related to capability: | |
910 | * 4 - Peer does not support capabilities at all. | |
911 | * 7 - Peer request some capability. Strange unless it is IPv6 only peer. | |
912 | * We try connect without capabilities | |
913 | */ | |
914 | BGP_TRACE(D_EVENTS, "Capability related error received, capabilities disabled"); | |
915 | conn->bgp->start_state = BSS_CONNECT_NOCAP; | |
916 | delay = 0; | |
917 | } | |
918 | #endif | |
919 | ||
11b32d91 OZ |
920 | bgp_log_error(conn->bgp, "Received error notification", code, subcode, pkt+21, len-21); |
921 | bgp_store_error(conn->bgp, conn, BE_BGP_RX, (code << 16) | subcode); | |
165a6227 | 922 | if (delay) bgp_update_startup_delay(conn->bgp, conn, code, subcode); |
11b32d91 | 923 | bgp_conn_enter_close_state(conn); |
3fdbafb6 MM |
924 | bgp_schedule_packet(conn, PKT_SCHEDULE_CLOSE); |
925 | } | |
926 | ||
927 | static void | |
e21423ba | 928 | bgp_rx_keepalive(struct bgp_conn *conn) |
3fdbafb6 | 929 | { |
85368cd4 MM |
930 | struct bgp_proto *p = conn->bgp; |
931 | ||
932 | BGP_TRACE(D_PACKETS, "Got KEEPALIVE"); | |
3fdbafb6 MM |
933 | bgp_start_timer(conn->hold_timer, conn->hold_time); |
934 | switch (conn->state) | |
935 | { | |
936 | case BS_OPENCONFIRM: | |
11b32d91 | 937 | bgp_conn_enter_established_state(conn); |
3fdbafb6 MM |
938 | break; |
939 | case BS_ESTABLISHED: | |
940 | break; | |
941 | default: | |
efcece2d | 942 | bgp_error(conn, 5, 0, NULL, 0); |
3fdbafb6 MM |
943 | } |
944 | } | |
945 | ||
54e55169 MM |
946 | /** |
947 | * bgp_rx_packet - handle a received packet | |
948 | * @conn: BGP connection | |
949 | * @pkt: start of the packet | |
950 | * @len: packet size | |
951 | * | |
952 | * bgp_rx_packet() takes a newly received packet and calls the corresponding | |
953 | * packet handler according to the packet type. | |
954 | */ | |
3fdbafb6 MM |
955 | static void |
956 | bgp_rx_packet(struct bgp_conn *conn, byte *pkt, unsigned len) | |
957 | { | |
958 | DBG("BGP: Got packet %02x (%d bytes)\n", pkt[18], len); | |
959 | switch (pkt[18]) | |
960 | { | |
961 | case PKT_OPEN: return bgp_rx_open(conn, pkt, len); | |
962 | case PKT_UPDATE: return bgp_rx_update(conn, pkt, len); | |
963 | case PKT_NOTIFICATION: return bgp_rx_notification(conn, pkt, len); | |
e21423ba | 964 | case PKT_KEEPALIVE: return bgp_rx_keepalive(conn); |
efcece2d | 965 | default: bgp_error(conn, 1, 3, pkt+18, 1); |
3fdbafb6 | 966 | } |
72a6ef11 MM |
967 | } |
968 | ||
54e55169 MM |
969 | /** |
970 | * bgp_rx - handle received data | |
971 | * @sk: socket | |
972 | * @size: amount of data received | |
973 | * | |
974 | * bgp_rx() is called by the socket layer whenever new data arrive from | |
975 | * the underlying TCP connection. It assembles the data fragments to packets, | |
976 | * checks their headers and framing and passes complete packets to | |
977 | * bgp_rx_packet(). | |
978 | */ | |
72a6ef11 MM |
979 | int |
980 | bgp_rx(sock *sk, int size) | |
981 | { | |
982 | struct bgp_conn *conn = sk->data; | |
983 | byte *pkt_start = sk->rbuf; | |
984 | byte *end = pkt_start + size; | |
3fdbafb6 | 985 | unsigned i, len; |
72a6ef11 MM |
986 | |
987 | DBG("BGP: RX hook: Got %d bytes\n", size); | |
988 | while (end >= pkt_start + BGP_HEADER_LENGTH) | |
989 | { | |
11b32d91 OZ |
990 | if ((conn->state == BS_CLOSE) || (conn->sk != sk)) |
991 | return 0; | |
3fdbafb6 MM |
992 | for(i=0; i<16; i++) |
993 | if (pkt_start[i] != 0xff) | |
994 | { | |
efcece2d | 995 | bgp_error(conn, 1, 1, NULL, 0); |
3fdbafb6 MM |
996 | break; |
997 | } | |
998 | len = get_u16(pkt_start+16); | |
999 | if (len < BGP_HEADER_LENGTH || len > BGP_MAX_PACKET_LENGTH) | |
1000 | { | |
efcece2d | 1001 | bgp_error(conn, 1, 2, pkt_start+16, 2); |
3fdbafb6 MM |
1002 | break; |
1003 | } | |
5f532add MM |
1004 | if (end < pkt_start + len) |
1005 | break; | |
1006 | bgp_rx_packet(conn, pkt_start, len); | |
1007 | pkt_start += len; | |
72a6ef11 MM |
1008 | } |
1009 | if (pkt_start != sk->rbuf) | |
1010 | { | |
1011 | memmove(sk->rbuf, pkt_start, end - pkt_start); | |
1012 | sk->rpos = sk->rbuf + (end - pkt_start); | |
1013 | } | |
1014 | return 0; | |
1015 | } |