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