]> git.proxmox.com Git - mirror_frr.git/blame - ldpd/packet.c
Merge pull request #3069 from donaldsharp/bgp_nexthop_address
[mirror_frr.git] / ldpd / packet.c
CommitLineData
8429abe0
RW
1/* $OpenBSD$ */
2
3/*
4 * Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org>
5 * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
6 * Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org>
7 *
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 */
20
eac6e3f0 21#include <zebra.h>
8429abe0
RW
22
23#include "ldpd.h"
24#include "ldpe.h"
25#include "log.h"
26
eac6e3f0
RW
27#include "sockopt.h"
28
8429abe0 29static struct iface *disc_find_iface(unsigned int, int,
097e36bf 30 union ldpd_addr *);
eac6e3f0
RW
31static int session_read(struct thread *);
32static int session_write(struct thread *);
8429abe0
RW
33static ssize_t session_get_pdu(struct ibuf_read *, char **);
34static void tcp_close(struct tcp_conn *);
35static struct pending_conn *pending_conn_new(int, int, union ldpd_addr *);
eac6e3f0 36static int pending_conn_timeout(struct thread *);
8429abe0
RW
37
38int
39gen_ldp_hdr(struct ibuf *buf, uint16_t size)
40{
41 struct ldp_hdr ldp_hdr;
42
43 memset(&ldp_hdr, 0, sizeof(ldp_hdr));
44 ldp_hdr.version = htons(LDP_VERSION);
45 /* exclude the 'Version' and 'PDU Length' fields from the total */
46 ldp_hdr.length = htons(size - LDP_HDR_DEAD_LEN);
eac6e3f0 47 ldp_hdr.lsr_id = ldp_rtr_id_get(leconf);
8429abe0
RW
48 ldp_hdr.lspace_id = 0;
49
50 return (ibuf_add(buf, &ldp_hdr, LDP_HDR_SIZE));
51}
52
53int
54gen_msg_hdr(struct ibuf *buf, uint16_t type, uint16_t size)
55{
56 static int msgcnt = 0;
57 struct ldp_msg msg;
58
59 memset(&msg, 0, sizeof(msg));
60 msg.type = htons(type);
61 /* exclude the 'Type' and 'Length' fields from the total */
62 msg.length = htons(size - LDP_MSG_DEAD_LEN);
63 msg.id = htonl(++msgcnt);
64
65 return (ibuf_add(buf, &msg, sizeof(msg)));
66}
67
68/* send packets */
69int
70send_packet(int fd, int af, union ldpd_addr *dst, struct iface_af *ia,
71 void *pkt, size_t len)
72{
4149ef7c 73 union sockunion su;
8429abe0
RW
74
75 switch (af) {
76 case AF_INET:
77 if (ia && IN_MULTICAST(ntohl(dst->v4.s_addr))) {
78 /* set outgoing interface for multicast traffic */
79 if (sock_set_ipv4_mcast(ia->iface) == -1) {
80 log_debug("%s: error setting multicast "
81 "interface, %s", __func__, ia->iface->name);
82 return (-1);
83 }
84 }
85 break;
86 case AF_INET6:
87 if (ia && IN6_IS_ADDR_MULTICAST(&dst->v6)) {
88 /* set outgoing interface for multicast traffic */
89 if (sock_set_ipv6_mcast(ia->iface) == -1) {
90 log_debug("%s: error setting multicast "
91 "interface, %s", __func__, ia->iface->name);
92 return (-1);
93 }
94 }
95 break;
96 default:
97 fatalx("send_packet: unknown af");
98 }
99
4149ef7c
A
100 addr2sa(af, dst, LDP_PORT, &su);
101 if (sendto(fd, pkt, len, 0, &su.sa, sockaddr_len(&su.sa)) == -1) {
8429abe0 102 log_warn("%s: error sending packet to %s", __func__,
4149ef7c 103 log_sockaddr(&su.sa));
8429abe0
RW
104 return (-1);
105 }
106
107 return (0);
108}
109
110/* Discovery functions */
eac6e3f0
RW
111int
112disc_recv_packet(struct thread *thread)
8429abe0 113{
eac6e3f0
RW
114 int fd = THREAD_FD(thread);
115 struct thread **threadp = THREAD_ARG(thread);
116
8429abe0
RW
117 union {
118 struct cmsghdr hdr;
eac6e3f0
RW
119#ifdef HAVE_STRUCT_SOCKADDR_DL
120 char buf[CMSG_SPACE(sizeof(struct sockaddr_dl))];
121#else
122 char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
123#endif
8429abe0
RW
124 } cmsgbuf;
125 struct msghdr m;
126 struct sockaddr_storage from;
127 struct iovec iov;
128 char *buf;
eac6e3f0 129#ifndef MSG_MCAST
8429abe0 130 struct cmsghdr *cmsg;
eac6e3f0 131#endif
8429abe0
RW
132 ssize_t r;
133 int multicast;
134 int af;
135 union ldpd_addr src;
136 unsigned int ifindex = 0;
097e36bf 137 struct iface *iface = NULL;
8429abe0
RW
138 uint16_t len;
139 struct ldp_hdr ldp_hdr;
140 uint16_t pdu_len;
141 struct ldp_msg msg;
142 uint16_t msg_len;
143 struct in_addr lsr_id;
144
eac6e3f0 145 /* reschedule read */
66e78ae6 146 *threadp = NULL;
e83c042a 147 thread_add_read(master, disc_recv_packet, threadp, fd, threadp);
8429abe0
RW
148
149 /* setup buffer */
150 memset(&m, 0, sizeof(m));
151 iov.iov_base = buf = pkt_ptr;
152 iov.iov_len = IBUF_READ_SIZE;
153 m.msg_name = &from;
154 m.msg_namelen = sizeof(from);
155 m.msg_iov = &iov;
156 m.msg_iovlen = 1;
157 m.msg_control = &cmsgbuf.buf;
158 m.msg_controllen = sizeof(cmsgbuf.buf);
159
160 if ((r = recvmsg(fd, &m, 0)) == -1) {
161 if (errno != EAGAIN && errno != EINTR)
162 log_debug("%s: read error: %s", __func__,
163 strerror(errno));
eac6e3f0 164 return (0);
8429abe0
RW
165 }
166
eac6e3f0
RW
167 sa2addr((struct sockaddr *)&from, &af, &src, NULL);
168#ifdef MSG_MCAST
8429abe0 169 multicast = (m.msg_flags & MSG_MCAST) ? 1 : 0;
eac6e3f0
RW
170#else
171 multicast = 0;
8429abe0
RW
172 for (cmsg = CMSG_FIRSTHDR(&m); cmsg != NULL;
173 cmsg = CMSG_NXTHDR(&m, cmsg)) {
eac6e3f0
RW
174#if defined(HAVE_IP_PKTINFO)
175 if (af == AF_INET && cmsg->cmsg_level == IPPROTO_IP &&
176 cmsg->cmsg_type == IP_PKTINFO) {
177 struct in_pktinfo *pktinfo;
178
179 pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
180 if (IN_MULTICAST(ntohl(pktinfo->ipi_addr.s_addr)))
181 multicast = 1;
182 break;
183 }
184#elif defined(HAVE_IP_RECVDSTADDR)
8429abe0 185 if (af == AF_INET && cmsg->cmsg_level == IPPROTO_IP &&
eac6e3f0
RW
186 cmsg->cmsg_type == IP_RECVDSTADDR) {
187 struct in_addr *addr;
188
189 addr = (struct in_addr *)CMSG_DATA(cmsg);
190 if (IN_MULTICAST(ntohl(addr->s_addr)))
191 multicast = 1;
8429abe0
RW
192 break;
193 }
eac6e3f0
RW
194#else
195#error "Unsupported socket API"
196#endif
8429abe0
RW
197 if (af == AF_INET6 && cmsg->cmsg_level == IPPROTO_IPV6 &&
198 cmsg->cmsg_type == IPV6_PKTINFO) {
eac6e3f0
RW
199 struct in6_pktinfo *pktinfo;
200
201 pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
202 if (IN6_IS_ADDR_MULTICAST(&pktinfo->ipi6_addr))
203 multicast = 1;
8429abe0
RW
204 break;
205 }
206 }
eac6e3f0
RW
207#endif /* MSG_MCAST */
208 if (bad_addr(af, &src)) {
209 log_debug("%s: invalid source address: %s", __func__,
210 log_addr(af, &src));
211 return (0);
212 }
213 ifindex = getsockopt_ifindex(af, &m);
8429abe0
RW
214
215 /* find a matching interface */
097e36bf
RW
216 if (multicast) {
217 iface = disc_find_iface(ifindex, af, &src);
218 if (iface == NULL)
219 return (0);
220 }
8429abe0
RW
221
222 /* check packet size */
223 len = (uint16_t)r;
224 if (len < (LDP_HDR_SIZE + LDP_MSG_SIZE) || len > LDP_MAX_LEN) {
225 log_debug("%s: bad packet size, source %s", __func__,
226 log_addr(af, &src));
eac6e3f0 227 return (0);
8429abe0
RW
228 }
229
230 /* LDP header sanity checks */
231 memcpy(&ldp_hdr, buf, sizeof(ldp_hdr));
232 if (ntohs(ldp_hdr.version) != LDP_VERSION) {
233 log_debug("%s: invalid LDP version %d, source %s", __func__,
234 ntohs(ldp_hdr.version), log_addr(af, &src));
eac6e3f0 235 return (0);
8429abe0
RW
236 }
237 if (ntohs(ldp_hdr.lspace_id) != 0) {
238 log_debug("%s: invalid label space %u, source %s", __func__,
239 ntohs(ldp_hdr.lspace_id), log_addr(af, &src));
eac6e3f0 240 return (0);
8429abe0
RW
241 }
242 /* check "PDU Length" field */
243 pdu_len = ntohs(ldp_hdr.length);
244 if ((pdu_len < (LDP_HDR_PDU_LEN + LDP_MSG_SIZE)) ||
245 (pdu_len > (len - LDP_HDR_DEAD_LEN))) {
246 log_debug("%s: invalid LDP packet length %u, source %s",
247 __func__, ntohs(ldp_hdr.length), log_addr(af, &src));
eac6e3f0 248 return (0);
8429abe0
RW
249 }
250 buf += LDP_HDR_SIZE;
251 len -= LDP_HDR_SIZE;
252
253 lsr_id.s_addr = ldp_hdr.lsr_id;
254
255 /*
256 * For UDP, we process only the first message of each packet. This does
257 * not impose any restrictions since LDP uses UDP only for sending Hello
258 * packets.
259 */
260 memcpy(&msg, buf, sizeof(msg));
261
262 /* check "Message Length" field */
263 msg_len = ntohs(msg.length);
264 if (msg_len < LDP_MSG_LEN || ((msg_len + LDP_MSG_DEAD_LEN) > pdu_len)) {
265 log_debug("%s: invalid LDP message length %u, source %s",
266 __func__, ntohs(msg.length), log_addr(af, &src));
eac6e3f0 267 return (0);
8429abe0
RW
268 }
269 buf += LDP_MSG_SIZE;
270 len -= LDP_MSG_SIZE;
271
272 /* switch LDP packet type */
273 switch (ntohs(msg.type)) {
274 case MSG_TYPE_HELLO:
275 recv_hello(lsr_id, &msg, af, &src, iface, multicast, buf, len);
276 break;
277 default:
278 log_debug("%s: unknown LDP packet type, source %s", __func__,
279 log_addr(af, &src));
280 }
eac6e3f0
RW
281
282 return (0);
8429abe0
RW
283}
284
285static struct iface *
097e36bf 286disc_find_iface(unsigned int ifindex, int af, union ldpd_addr *src)
8429abe0
RW
287{
288 struct iface *iface;
289 struct iface_af *ia;
8429abe0
RW
290
291 iface = if_lookup(leconf, ifindex);
292 if (iface == NULL)
293 return (NULL);
294
4913a168
RW
295 ia = iface_af_get(iface, af);
296 if (!ia->enabled)
297 return (NULL);
298
8429abe0 299 /*
e885fc27
RW
300 * RFC 7552 - Section 5.1:
301 * "Link-local IPv6 address MUST be used as the source IP address in
302 * IPv6 LDP Link Hellos".
8429abe0 303 */
097e36bf 304 if (af == AF_INET6 && !IN6_IS_ADDR_LINKLOCAL(&src->v6))
e885fc27 305 return (NULL);
8429abe0 306
e885fc27 307 return (iface);
8429abe0
RW
308}
309
eac6e3f0
RW
310int
311session_accept(struct thread *thread)
8429abe0 312{
eac6e3f0 313 int fd = THREAD_FD(thread);
8429abe0
RW
314 struct sockaddr_storage src;
315 socklen_t len = sizeof(src);
316 int newfd;
317 int af;
318 union ldpd_addr addr;
319 struct nbr *nbr;
320 struct pending_conn *pconn;
321
eac6e3f0 322 newfd = accept(fd, (struct sockaddr *)&src, &len);
8429abe0
RW
323 if (newfd == -1) {
324 /*
325 * Pause accept if we are out of file descriptors, or
326 * libevent will haunt us here too.
327 */
328 if (errno == ENFILE || errno == EMFILE) {
329 accept_pause();
330 } else if (errno != EWOULDBLOCK && errno != EINTR &&
331 errno != ECONNABORTED)
332 log_debug("%s: accept error: %s", __func__,
333 strerror(errno));
eac6e3f0 334 return (0);
8429abe0 335 }
eac6e3f0 336 sock_set_nonblock(newfd);
8429abe0 337
eac6e3f0 338 sa2addr((struct sockaddr *)&src, &af, &addr, NULL);
8429abe0
RW
339
340 /*
341 * Since we don't support label spaces, we can identify this neighbor
342 * just by its source address. This way we don't need to wait for its
343 * Initialization message to know who we are talking to.
344 */
345 nbr = nbr_find_addr(af, &addr);
346 if (nbr == NULL) {
347 /*
348 * According to RFC 5036, we would need to send a No Hello
349 * Error Notification message and close this TCP connection
350 * right now. But doing so would trigger the backoff exponential
351 * timer in the remote peer, which would considerably slow down
352 * the session establishment process. The trick here is to wait
353 * five seconds before sending the Notification Message. There's
354 * a good chance that the remote peer will send us a Hello
355 * message within this interval, so it's worth waiting before
356 * taking a more drastic measure.
357 */
358 pconn = pending_conn_find(af, &addr);
359 if (pconn)
360 close(newfd);
361 else
362 pending_conn_new(newfd, af, &addr);
eac6e3f0 363 return (0);
8429abe0
RW
364 }
365 /* protection against buggy implementations */
366 if (nbr_session_active_role(nbr)) {
367 close(newfd);
eac6e3f0 368 return (0);
8429abe0
RW
369 }
370 if (nbr->state != NBR_STA_PRESENT) {
371 log_debug("%s: lsr-id %s: rejecting additional transport "
372 "connection", __func__, inet_ntoa(nbr->id));
373 close(newfd);
eac6e3f0 374 return (0);
8429abe0
RW
375 }
376
377 session_accept_nbr(nbr, newfd);
eac6e3f0
RW
378
379 return (0);
8429abe0
RW
380}
381
382void
383session_accept_nbr(struct nbr *nbr, int fd)
384{
eac6e3f0 385#ifdef __OpenBSD__
8429abe0
RW
386 struct nbr_params *nbrp;
387 int opt;
388 socklen_t len;
389
390 nbrp = nbr_params_find(leconf, nbr->id);
391 if (nbr_gtsm_check(fd, nbr, nbrp)) {
392 close(fd);
393 return;
394 }
395
396 if (nbrp && nbrp->auth.method == AUTH_MD5SIG) {
397 if (sysdep.no_pfkey || sysdep.no_md5sig) {
398 log_warnx("md5sig configured but not available");
399 close(fd);
400 return;
401 }
402
403 len = sizeof(opt);
404 if (getsockopt(fd, IPPROTO_TCP, TCP_MD5SIG, &opt, &len) == -1)
405 fatal("getsockopt TCP_MD5SIG");
406 if (!opt) { /* non-md5'd connection! */
407 log_warnx("connection attempt without md5 signature");
408 close(fd);
409 return;
410 }
411 }
eac6e3f0 412#endif
8429abe0
RW
413
414 nbr->tcp = tcp_new(fd, nbr);
415 nbr_fsm(nbr, NBR_EVT_MATCH_ADJ);
416}
417
eac6e3f0
RW
418static int
419session_read(struct thread *thread)
8429abe0 420{
eac6e3f0
RW
421 int fd = THREAD_FD(thread);
422 struct nbr *nbr = THREAD_ARG(thread);
8429abe0
RW
423 struct tcp_conn *tcp = nbr->tcp;
424 struct ldp_hdr *ldp_hdr;
425 struct ldp_msg *msg;
eac6e3f0 426 char *buf = NULL, *pdu;
8429abe0
RW
427 ssize_t n, len;
428 uint16_t pdu_len, msg_len, msg_size, max_pdu_len;
429 int ret;
430
66e78ae6
QY
431 tcp->rev = NULL;
432 thread_add_read(master, session_read, nbr, fd, &tcp->rev);
8429abe0
RW
433
434 if ((n = read(fd, tcp->rbuf->buf + tcp->rbuf->wpos,
435 sizeof(tcp->rbuf->buf) - tcp->rbuf->wpos)) == -1) {
436 if (errno != EINTR && errno != EAGAIN) {
437 log_warn("%s: read error", __func__);
438 nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION);
eac6e3f0 439 return (0);
8429abe0
RW
440 }
441 /* retry read */
eac6e3f0 442 return (0);
8429abe0
RW
443 }
444 if (n == 0) {
445 /* connection closed */
446 log_debug("%s: connection closed by remote end", __func__);
447 nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION);
eac6e3f0 448 return (0);
8429abe0
RW
449 }
450 tcp->rbuf->wpos += n;
451
452 while ((len = session_get_pdu(tcp->rbuf, &buf)) > 0) {
453 pdu = buf;
454 ldp_hdr = (struct ldp_hdr *)pdu;
455 if (ntohs(ldp_hdr->version) != LDP_VERSION) {
456 session_shutdown(nbr, S_BAD_PROTO_VER, 0, 0);
457 free(buf);
eac6e3f0 458 return (0);
8429abe0
RW
459 }
460
461 pdu_len = ntohs(ldp_hdr->length);
462 /*
463 * RFC 5036 - Section 3.5.3:
464 * "Prior to completion of the negotiation, the maximum
465 * allowable length is 4096 bytes".
466 */
467 if (nbr->state == NBR_STA_OPER)
468 max_pdu_len = nbr->max_pdu_len;
469 else
470 max_pdu_len = LDP_MAX_LEN;
471 if (pdu_len < (LDP_HDR_PDU_LEN + LDP_MSG_SIZE) ||
472 pdu_len > max_pdu_len) {
473 session_shutdown(nbr, S_BAD_PDU_LEN, 0, 0);
474 free(buf);
eac6e3f0 475 return (0);
8429abe0
RW
476 }
477 pdu_len -= LDP_HDR_PDU_LEN;
478 if (ldp_hdr->lsr_id != nbr->id.s_addr ||
479 ldp_hdr->lspace_id != 0) {
480 session_shutdown(nbr, S_BAD_LDP_ID, 0, 0);
481 free(buf);
eac6e3f0 482 return (0);
8429abe0
RW
483 }
484 pdu += LDP_HDR_SIZE;
485 len -= LDP_HDR_SIZE;
486
487 nbr_fsm(nbr, NBR_EVT_PDU_RCVD);
488
489 while (len >= LDP_MSG_SIZE) {
490 uint16_t type;
491
492 msg = (struct ldp_msg *)pdu;
493 type = ntohs(msg->type);
494 msg_len = ntohs(msg->length);
495 if (msg_len < LDP_MSG_LEN ||
496 (msg_len + LDP_MSG_DEAD_LEN) > pdu_len) {
a901e098 497 session_shutdown(nbr, S_BAD_MSG_LEN, msg->id,
8429abe0
RW
498 msg->type);
499 free(buf);
eac6e3f0 500 return (0);
8429abe0
RW
501 }
502 msg_size = msg_len + LDP_MSG_DEAD_LEN;
503 pdu_len -= msg_size;
504
505 /* check for error conditions earlier */
506 switch (type) {
507 case MSG_TYPE_INIT:
508 if ((nbr->state != NBR_STA_INITIAL) &&
509 (nbr->state != NBR_STA_OPENSENT)) {
510 session_shutdown(nbr, S_SHUTDOWN,
511 msg->id, msg->type);
512 free(buf);
eac6e3f0 513 return (0);
8429abe0
RW
514 }
515 break;
516 case MSG_TYPE_KEEPALIVE:
517 if ((nbr->state == NBR_STA_INITIAL) ||
518 (nbr->state == NBR_STA_OPENSENT)) {
519 session_shutdown(nbr, S_SHUTDOWN,
520 msg->id, msg->type);
521 free(buf);
eac6e3f0 522 return (0);
8429abe0
RW
523 }
524 break;
90989cb3
RW
525 case MSG_TYPE_NOTIFICATION:
526 break;
8819fc38 527 default:
8429abe0
RW
528 if (nbr->state != NBR_STA_OPER) {
529 session_shutdown(nbr, S_SHUTDOWN,
530 msg->id, msg->type);
531 free(buf);
eac6e3f0 532 return (0);
8429abe0
RW
533 }
534 break;
8429abe0
RW
535 }
536
537 /* switch LDP packet type */
538 switch (type) {
539 case MSG_TYPE_NOTIFICATION:
540 ret = recv_notification(nbr, pdu, msg_size);
541 break;
542 case MSG_TYPE_INIT:
543 ret = recv_init(nbr, pdu, msg_size);
544 break;
545 case MSG_TYPE_KEEPALIVE:
546 ret = recv_keepalive(nbr, pdu, msg_size);
547 break;
8819fc38
RW
548 case MSG_TYPE_CAPABILITY:
549 ret = recv_capability(nbr, pdu, msg_size);
550 break;
8429abe0
RW
551 case MSG_TYPE_ADDR:
552 case MSG_TYPE_ADDRWITHDRAW:
553 ret = recv_address(nbr, pdu, msg_size);
554 break;
555 case MSG_TYPE_LABELMAPPING:
556 case MSG_TYPE_LABELREQUEST:
557 case MSG_TYPE_LABELWITHDRAW:
558 case MSG_TYPE_LABELRELEASE:
559 case MSG_TYPE_LABELABORTREQ:
560 ret = recv_labelmessage(nbr, pdu, msg_size,
561 type);
562 break;
563 default:
564 log_debug("%s: unknown LDP message from nbr %s",
565 __func__, inet_ntoa(nbr->id));
566 if (!(ntohs(msg->type) & UNKNOWN_FLAG))
adbdf465 567 send_notification(nbr->tcp,
8429abe0
RW
568 S_UNKNOWN_MSG, msg->id, msg->type);
569 /* ignore the message */
570 ret = 0;
571 break;
572 }
573
574 if (ret == -1) {
575 /* parser failed, giving up */
576 free(buf);
eac6e3f0 577 return (0);
8429abe0
RW
578 }
579
0f7b5df9
RW
580 /* no errors - update per neighbor message counters */
581 switch (type) {
582 case MSG_TYPE_NOTIFICATION:
583 nbr->stats.notif_rcvd++;
584 break;
585 case MSG_TYPE_KEEPALIVE:
586 nbr->stats.kalive_rcvd++;
587 break;
588 case MSG_TYPE_CAPABILITY:
589 nbr->stats.capability_rcvd++;
590 break;
591 case MSG_TYPE_ADDR:
592 nbr->stats.addr_rcvd++;
593 break;
594 case MSG_TYPE_ADDRWITHDRAW:
595 nbr->stats.addrwdraw_rcvd++;
596 break;
597 case MSG_TYPE_LABELMAPPING:
598 nbr->stats.labelmap_rcvd++;
599 break;
600 case MSG_TYPE_LABELREQUEST:
601 nbr->stats.labelreq_rcvd++;
602 break;
603 case MSG_TYPE_LABELWITHDRAW:
604 nbr->stats.labelwdraw_rcvd++;
605 break;
606 case MSG_TYPE_LABELRELEASE:
607 nbr->stats.labelrel_rcvd++;
608 break;
609 case MSG_TYPE_LABELABORTREQ:
610 nbr->stats.labelabreq_rcvd++;
611 break;
612 default:
613 break;
614 }
615
8429abe0
RW
616 /* Analyse the next message */
617 pdu += msg_size;
618 len -= msg_size;
619 }
620 free(buf);
621 if (len != 0) {
622 session_shutdown(nbr, S_BAD_PDU_LEN, 0, 0);
eac6e3f0 623 return (0);
8429abe0
RW
624 }
625 }
eac6e3f0
RW
626
627 return (0);
8429abe0
RW
628}
629
eac6e3f0
RW
630static int
631session_write(struct thread *thread)
8429abe0 632{
eac6e3f0 633 struct tcp_conn *tcp = THREAD_ARG(thread);
8429abe0
RW
634 struct nbr *nbr = tcp->nbr;
635
eac6e3f0 636 tcp->wbuf.ev = NULL;
8429abe0
RW
637
638 if (msgbuf_write(&tcp->wbuf.wbuf) <= 0)
639 if (errno != EAGAIN && nbr)
640 nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION);
641
642 if (nbr == NULL && !tcp->wbuf.wbuf.queued) {
643 /*
644 * We are done sending the notification message, now we can
645 * close the socket.
646 */
647 tcp_close(tcp);
eac6e3f0 648 return (0);
8429abe0
RW
649 }
650
651 evbuf_event_add(&tcp->wbuf);
eac6e3f0
RW
652
653 return (0);
8429abe0
RW
654}
655
656void
657session_shutdown(struct nbr *nbr, uint32_t status, uint32_t msg_id,
658 uint32_t msg_type)
659{
660 switch (nbr->state) {
661 case NBR_STA_PRESENT:
662 if (nbr_pending_connect(nbr))
eac6e3f0 663 THREAD_WRITE_OFF(nbr->ev_connect);
8429abe0
RW
664 break;
665 case NBR_STA_INITIAL:
666 case NBR_STA_OPENREC:
667 case NBR_STA_OPENSENT:
668 case NBR_STA_OPER:
adbdf465 669 send_notification(nbr->tcp, status, msg_id, msg_type);
8429abe0
RW
670
671 nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION);
672 break;
673 default:
674 fatalx("session_shutdown: unknown neighbor state");
675 }
676}
677
678void
679session_close(struct nbr *nbr)
680{
681 log_debug("%s: closing session with lsr-id %s", __func__,
682 inet_ntoa(nbr->id));
683
684 tcp_close(nbr->tcp);
685 nbr_stop_ktimer(nbr);
686 nbr_stop_ktimeout(nbr);
687 nbr_stop_itimeout(nbr);
688}
689
690static ssize_t
691session_get_pdu(struct ibuf_read *r, char **b)
692{
693 struct ldp_hdr l;
694 size_t av, dlen, left;
695
696 av = r->wpos;
697 if (av < sizeof(l))
698 return (0);
699
700 memcpy(&l, r->buf, sizeof(l));
701 dlen = ntohs(l.length) + LDP_HDR_DEAD_LEN;
702 if (dlen > av)
703 return (0);
704
705 if ((*b = malloc(dlen)) == NULL)
706 return (-1);
707
708 memcpy(*b, r->buf, dlen);
709 if (dlen < av) {
710 left = av - dlen;
711 memmove(r->buf, r->buf + dlen, left);
712 r->wpos = left;
713 } else
714 r->wpos = 0;
715
716 return (dlen);
717}
718
719struct tcp_conn *
720tcp_new(int fd, struct nbr *nbr)
721{
eac6e3f0 722 struct tcp_conn *tcp;
f82a5428
RW
723 struct sockaddr_storage ss;
724 socklen_t len = sizeof(ss);
8429abe0
RW
725
726 if ((tcp = calloc(1, sizeof(*tcp))) == NULL)
727 fatal(__func__);
728
729 tcp->fd = fd;
730 evbuf_init(&tcp->wbuf, tcp->fd, session_write, tcp);
731
732 if (nbr) {
733 if ((tcp->rbuf = calloc(1, sizeof(struct ibuf_read))) == NULL)
734 fatal(__func__);
735
66e78ae6
QY
736 tcp->rev = NULL;
737 thread_add_read(master, session_read, nbr, tcp->fd, &tcp->rev);
8429abe0
RW
738 tcp->nbr = nbr;
739 }
740
f82a5428
RW
741 if (getsockname(fd, (struct sockaddr *)&ss, &len) != 0)
742 log_warn("%s: getsockname", __func__);
743 else
744 sa2addr((struct sockaddr *)&ss, NULL, NULL, &tcp->lport);
745 if (getpeername(fd, (struct sockaddr *)&ss, &len) != 0)
746 log_warn("%s: getpeername", __func__);
747 else
748 sa2addr((struct sockaddr *)&ss, NULL, NULL, &tcp->rport);
eac6e3f0 749
8429abe0
RW
750 return (tcp);
751}
752
753static void
754tcp_close(struct tcp_conn *tcp)
755{
756 /* try to flush write buffer */
757 msgbuf_write(&tcp->wbuf.wbuf);
758 evbuf_clear(&tcp->wbuf);
759
760 if (tcp->nbr) {
eac6e3f0 761 THREAD_READ_OFF(tcp->rev);
8429abe0
RW
762 free(tcp->rbuf);
763 tcp->nbr->tcp = NULL;
764 }
765
766 close(tcp->fd);
767 accept_unpause();
768 free(tcp);
769}
770
771static struct pending_conn *
772pending_conn_new(int fd, int af, union ldpd_addr *addr)
773{
774 struct pending_conn *pconn;
8429abe0
RW
775
776 if ((pconn = calloc(1, sizeof(*pconn))) == NULL)
777 fatal(__func__);
778
779 pconn->fd = fd;
780 pconn->af = af;
781 pconn->addr = *addr;
8429abe0 782 TAILQ_INSERT_TAIL(&global.pending_conns, pconn, entry);
66e78ae6
QY
783 pconn->ev_timeout = NULL;
784 thread_add_timer(master, pending_conn_timeout, pconn, PENDING_CONN_TIMEOUT,
785 &pconn->ev_timeout);
8429abe0
RW
786
787 return (pconn);
788}
789
790void
791pending_conn_del(struct pending_conn *pconn)
792{
eac6e3f0 793 THREAD_TIMER_OFF(pconn->ev_timeout);
8429abe0
RW
794 TAILQ_REMOVE(&global.pending_conns, pconn, entry);
795 free(pconn);
796}
797
798struct pending_conn *
799pending_conn_find(int af, union ldpd_addr *addr)
800{
801 struct pending_conn *pconn;
802
803 TAILQ_FOREACH(pconn, &global.pending_conns, entry)
804 if (af == pconn->af &&
805 ldp_addrcmp(af, addr, &pconn->addr) == 0)
806 return (pconn);
807
808 return (NULL);
809}
810
eac6e3f0
RW
811static int
812pending_conn_timeout(struct thread *thread)
8429abe0 813{
eac6e3f0 814 struct pending_conn *pconn = THREAD_ARG(thread);
8429abe0
RW
815 struct tcp_conn *tcp;
816
eac6e3f0
RW
817 pconn->ev_timeout = NULL;
818
8429abe0
RW
819 log_debug("%s: no adjacency with remote end: %s", __func__,
820 log_addr(pconn->af, &pconn->addr));
821
822 /*
823 * Create a write buffer detached from any neighbor to send a
824 * notification message reliably.
825 */
826 tcp = tcp_new(pconn->fd, NULL);
adbdf465 827 send_notification(tcp, S_NO_HELLO, 0, 0);
8429abe0
RW
828 msgbuf_write(&tcp->wbuf.wbuf);
829
830 pending_conn_del(pconn);
eac6e3f0
RW
831
832 return (0);
8429abe0 833}