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