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