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