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