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>
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.
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.
29 static struct iface
*disc_find_iface(unsigned int, int,
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
);
39 gen_ldp_hdr(struct ibuf
*buf
, uint16_t size
)
41 struct ldp_hdr ldp_hdr
;
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;
50 return (ibuf_add(buf
, &ldp_hdr
, LDP_HDR_SIZE
));
54 gen_msg_hdr(struct ibuf
*buf
, uint16_t type
, uint16_t size
)
56 static int msgcnt
= 0;
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
);
65 return (ibuf_add(buf
, &msg
, sizeof(msg
)));
70 send_packet(int fd
, int af
, union ldpd_addr
*dst
, struct iface_af
*ia
,
71 void *pkt
, size_t len
)
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
);
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
);
95 fatalx("send_packet: unknown af");
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
));
108 /* Discovery functions */
109 void disc_recv_packet(struct thread
*thread
)
111 int fd
= THREAD_FD(thread
);
112 struct thread
**threadp
= THREAD_ARG(thread
);
116 #ifdef HAVE_STRUCT_SOCKADDR_DL
117 char buf
[CMSG_SPACE(sizeof(struct sockaddr_dl
))];
119 char buf
[CMSG_SPACE(sizeof(struct in6_pktinfo
))];
123 struct sockaddr_storage from
;
127 struct cmsghdr
*cmsg
;
133 unsigned int ifindex
= 0;
134 struct iface
*iface
= NULL
;
136 struct ldp_hdr ldp_hdr
;
140 struct in_addr lsr_id
;
142 /* reschedule read */
143 thread_add_read(master
, disc_recv_packet
, threadp
, fd
, threadp
);
146 memset(&m
, 0, sizeof(m
));
147 iov
.iov_base
= buf
= pkt_ptr
;
148 iov
.iov_len
= IBUF_READ_SIZE
;
150 m
.msg_namelen
= sizeof(from
);
153 m
.msg_control
= &cmsgbuf
.buf
;
154 m
.msg_controllen
= sizeof(cmsgbuf
.buf
);
156 if ((r
= recvmsg(fd
, &m
, 0)) == -1) {
157 if (errno
!= EAGAIN
&& errno
!= EINTR
)
158 log_debug("%s: read error: %s", __func__
,
163 sa2addr((struct sockaddr
*)&from
, &af
, &src
, NULL
);
165 multicast
= (m
.msg_flags
& MSG_MCAST
) ? 1 : 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
;
175 pktinfo
= (struct in_pktinfo
*)CMSG_DATA(cmsg
);
176 if (IN_MULTICAST(ntohl(pktinfo
->ipi_addr
.s_addr
)))
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
;
185 addr
= (struct in_addr
*)CMSG_DATA(cmsg
);
186 if (IN_MULTICAST(ntohl(addr
->s_addr
)))
191 #error "Unsupported socket API"
193 if (af
== AF_INET6
&& cmsg
->cmsg_level
== IPPROTO_IPV6
&&
194 cmsg
->cmsg_type
== IPV6_PKTINFO
) {
195 struct in6_pktinfo
*pktinfo
;
197 pktinfo
= (struct in6_pktinfo
*)CMSG_DATA(cmsg
);
198 if (IN6_IS_ADDR_MULTICAST(&pktinfo
->ipi6_addr
))
203 #endif /* MSG_MCAST */
204 if (bad_addr(af
, &src
)) {
205 log_debug("%s: invalid source address: %s", __func__
,
209 ifindex
= getsockopt_ifindex(af
, &m
);
211 /* find a matching interface */
213 iface
= disc_find_iface(ifindex
, af
, &src
);
218 /* check packet size */
220 if (len
< (LDP_HDR_SIZE
+ LDP_MSG_SIZE
) || len
> LDP_MAX_LEN
) {
221 log_debug("%s: bad packet size, source %s", __func__
,
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
));
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
));
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
));
249 lsr_id
.s_addr
= ldp_hdr
.lsr_id
;
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
256 memcpy(&msg
, buf
, sizeof(msg
));
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
));
268 /* switch LDP packet type */
269 switch (ntohs(msg
.type
)) {
271 recv_hello(lsr_id
, &msg
, af
, &src
, iface
, multicast
, buf
, len
);
274 log_debug("%s: unknown LDP packet type, source %s", __func__
,
279 static struct iface
*
280 disc_find_iface(unsigned int ifindex
, int af
, union ldpd_addr
*src
)
285 iface
= if_lookup(leconf
, ifindex
);
289 ia
= iface_af_get(iface
, af
);
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".
298 if (af
== AF_INET6
&& !IN6_IS_ADDR_LINKLOCAL(&src
->v6
))
304 void session_accept(struct thread
*thread
)
306 int fd
= THREAD_FD(thread
);
307 struct sockaddr_storage src
;
308 socklen_t len
= sizeof(src
);
311 union ldpd_addr addr
;
313 struct pending_conn
*pconn
;
315 newfd
= accept(fd
, (struct sockaddr
*)&src
, &len
);
318 * Pause accept if we are out of file descriptors, or
319 * libevent will haunt us here too.
321 if (errno
== ENFILE
|| errno
== EMFILE
) {
323 } else if (errno
!= EWOULDBLOCK
&& errno
!= EINTR
&&
324 errno
!= ECONNABORTED
)
325 log_debug("%s: accept error: %s", __func__
,
329 sock_set_nonblock(newfd
);
331 sa2addr((struct sockaddr
*)&src
, &af
, &addr
, NULL
);
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.
338 nbr
= nbr_find_addr(af
, &addr
);
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.
351 pconn
= pending_conn_find(af
, &addr
);
355 pending_conn_new(newfd
, af
, &addr
);
358 /* protection against buggy implementations */
359 if (nbr_session_active_role(nbr
)) {
363 if (nbr
->state
!= NBR_STA_PRESENT
) {
364 log_debug("%s: lsr-id %pI4: rejecting additional transport connection", __func__
, &nbr
->id
);
369 session_accept_nbr(nbr
, newfd
);
373 session_accept_nbr(struct nbr
*nbr
, int fd
)
376 struct nbr_params
*nbrp
;
380 nbrp
= nbr_params_find(leconf
, nbr
->id
);
381 if (nbr_gtsm_check(fd
, nbr
, nbrp
)) {
386 if (nbrp
&& nbrp
->auth
.method
== AUTH_MD5SIG
) {
387 if (sysdep
.no_pfkey
|| sysdep
.no_md5sig
) {
388 log_warnx("md5sig configured but not available");
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");
404 nbr
->tcp
= tcp_new(fd
, nbr
);
405 nbr_fsm(nbr
, NBR_EVT_MATCH_ADJ
);
408 static void session_read(struct thread
*thread
)
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
;
415 char *buf
= NULL
, *pdu
;
417 uint16_t pdu_len
, msg_len
, msg_size
, max_pdu_len
;
420 thread_add_read(master
, session_read
, nbr
, fd
, &tcp
->rev
);
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
);
433 /* connection closed */
434 log_debug("%s: connection closed by remote end", __func__
);
435 nbr_fsm(nbr
, NBR_EVT_CLOSE_SESSION
);
438 tcp
->rbuf
->wpos
+= n
;
440 while ((len
= session_get_pdu(tcp
->rbuf
, &buf
)) > 0) {
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);
449 pdu_len
= ntohs(ldp_hdr
->length
);
451 * RFC 5036 - Section 3.5.3:
452 * "Prior to completion of the negotiation, the maximum
453 * allowable length is 4096 bytes".
455 if (nbr
->state
== NBR_STA_OPER
)
456 max_pdu_len
= nbr
->max_pdu_len
;
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);
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);
475 nbr_fsm(nbr
, NBR_EVT_PDU_RCVD
);
477 while (len
>= LDP_MSG_SIZE
) {
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
,
490 msg_size
= msg_len
+ LDP_MSG_DEAD_LEN
;
493 /* check for error conditions earlier */
496 if ((nbr
->state
!= NBR_STA_INITIAL
) &&
497 (nbr
->state
!= NBR_STA_OPENSENT
)) {
498 session_shutdown(nbr
, S_SHUTDOWN
,
504 case MSG_TYPE_KEEPALIVE
:
505 if ((nbr
->state
== NBR_STA_INITIAL
) ||
506 (nbr
->state
== NBR_STA_OPENSENT
)) {
507 session_shutdown(nbr
, S_SHUTDOWN
,
513 case MSG_TYPE_NOTIFICATION
:
516 if (nbr
->state
!= NBR_STA_OPER
) {
517 session_shutdown(nbr
, S_SHUTDOWN
,
525 /* switch LDP packet type */
527 case MSG_TYPE_NOTIFICATION
:
528 ret
= recv_notification(nbr
, pdu
, msg_size
);
531 ret
= recv_init(nbr
, pdu
, msg_size
);
533 case MSG_TYPE_KEEPALIVE
:
534 ret
= recv_keepalive(nbr
, pdu
, msg_size
);
536 case MSG_TYPE_CAPABILITY
:
537 ret
= recv_capability(nbr
, pdu
, msg_size
);
540 case MSG_TYPE_ADDRWITHDRAW
:
541 ret
= recv_address(nbr
, pdu
, msg_size
);
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
,
552 log_debug("%s: unknown LDP message from nbr %pI4",
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
);
559 /* ignore the message */
565 /* parser failed, giving up */
570 /* no errors - update per neighbor message counters */
572 case MSG_TYPE_NOTIFICATION
:
573 nbr
->stats
.notif_rcvd
++;
575 case MSG_TYPE_KEEPALIVE
:
576 nbr
->stats
.kalive_rcvd
++;
578 case MSG_TYPE_CAPABILITY
:
579 nbr
->stats
.capability_rcvd
++;
582 nbr
->stats
.addr_rcvd
++;
584 case MSG_TYPE_ADDRWITHDRAW
:
585 nbr
->stats
.addrwdraw_rcvd
++;
587 case MSG_TYPE_LABELMAPPING
:
588 nbr
->stats
.labelmap_rcvd
++;
590 case MSG_TYPE_LABELREQUEST
:
591 nbr
->stats
.labelreq_rcvd
++;
593 case MSG_TYPE_LABELWITHDRAW
:
594 nbr
->stats
.labelwdraw_rcvd
++;
596 case MSG_TYPE_LABELRELEASE
:
597 nbr
->stats
.labelrel_rcvd
++;
599 case MSG_TYPE_LABELABORTREQ
:
600 nbr
->stats
.labelabreq_rcvd
++;
606 /* Analyse the next message */
613 session_shutdown(nbr
, S_BAD_PDU_LEN
, 0, 0);
618 /* shouldn't happen, session_get_pdu should be > 0 if buf was
619 * allocated - but let's get rid of the SA warning.
624 static void session_write(struct thread
*thread
)
626 struct tcp_conn
*tcp
= THREAD_ARG(thread
);
627 struct nbr
*nbr
= tcp
->nbr
;
631 if (msgbuf_write(&tcp
->wbuf
.wbuf
) <= 0)
632 if (errno
!= EAGAIN
&& nbr
)
633 nbr_fsm(nbr
, NBR_EVT_CLOSE_SESSION
);
635 if (nbr
== NULL
&& !tcp
->wbuf
.wbuf
.queued
) {
637 * We are done sending the notification message, now we can
644 evbuf_event_add(&tcp
->wbuf
);
648 session_shutdown(struct nbr
*nbr
, uint32_t status
, uint32_t msg_id
,
651 switch (nbr
->state
) {
652 case NBR_STA_PRESENT
:
653 if (nbr_pending_connect(nbr
))
654 THREAD_OFF(nbr
->ev_connect
);
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
);
663 nbr_fsm(nbr
, NBR_EVT_CLOSE_SESSION
);
666 send_notification(nbr
->tcp
, status
, msg_id
, msg_type
);
668 nbr_fsm(nbr
, NBR_EVT_CLOSE_SESSION
);
671 fatalx("session_shutdown: unknown neighbor state");
676 session_close(struct nbr
*nbr
)
678 log_debug("%s: closing session with lsr-id %pI4", __func__
,
681 ldp_sync_fsm_nbr_event(nbr
, LDP_SYNC_EVT_SESSION_CLOSE
);
684 nbr_stop_ktimer(nbr
);
685 nbr_stop_ktimeout(nbr
);
686 nbr_stop_itimeout(nbr
);
690 session_get_pdu(struct ibuf_read
*r
, char **b
)
693 size_t av
, dlen
, left
;
699 memcpy(&l
, r
->buf
, sizeof(l
));
700 dlen
= ntohs(l
.length
) + LDP_HDR_DEAD_LEN
;
704 if ((*b
= malloc(dlen
)) == NULL
)
707 memcpy(*b
, r
->buf
, dlen
);
710 memmove(r
->buf
, r
->buf
+ dlen
, left
);
719 tcp_new(int fd
, struct nbr
*nbr
)
721 struct tcp_conn
*tcp
;
722 struct sockaddr_storage ss
;
723 socklen_t len
= sizeof(ss
);
725 if ((tcp
= calloc(1, sizeof(*tcp
))) == NULL
)
729 evbuf_init(&tcp
->wbuf
, tcp
->fd
, session_write
, tcp
);
732 if ((tcp
->rbuf
= calloc(1, sizeof(struct ibuf_read
))) == NULL
)
735 thread_add_read(master
, session_read
, nbr
, tcp
->fd
, &tcp
->rev
);
739 if (getsockname(fd
, (struct sockaddr
*)&ss
, &len
) != 0)
740 log_warn("%s: getsockname", __func__
);
742 sa2addr((struct sockaddr
*)&ss
, NULL
, NULL
, &tcp
->lport
);
743 if (getpeername(fd
, (struct sockaddr
*)&ss
, &len
) != 0)
744 log_warn("%s: getpeername", __func__
);
746 sa2addr((struct sockaddr
*)&ss
, NULL
, NULL
, &tcp
->rport
);
752 tcp_close(struct tcp_conn
*tcp
)
754 /* try to flush write buffer */
755 msgbuf_write(&tcp
->wbuf
.wbuf
);
756 evbuf_clear(&tcp
->wbuf
);
759 THREAD_OFF(tcp
->rev
);
761 tcp
->nbr
->tcp
= NULL
;
769 static struct pending_conn
*
770 pending_conn_new(int fd
, int af
, union ldpd_addr
*addr
)
772 struct pending_conn
*pconn
;
774 if ((pconn
= calloc(1, sizeof(*pconn
))) == NULL
)
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
,
789 pending_conn_del(struct pending_conn
*pconn
)
791 THREAD_OFF(pconn
->ev_timeout
);
792 TAILQ_REMOVE(&global
.pending_conns
, pconn
, entry
);
796 struct pending_conn
*
797 pending_conn_find(int af
, union ldpd_addr
*addr
)
799 struct pending_conn
*pconn
;
801 TAILQ_FOREACH(pconn
, &global
.pending_conns
, entry
)
802 if (af
== pconn
->af
&&
803 ldp_addrcmp(af
, addr
, &pconn
->addr
) == 0)
809 static void pending_conn_timeout(struct thread
*thread
)
811 struct pending_conn
*pconn
= THREAD_ARG(thread
);
812 struct tcp_conn
*tcp
;
814 pconn
->ev_timeout
= NULL
;
816 log_debug("%s: no adjacency with remote end: %s", __func__
,
817 log_addr(pconn
->af
, &pconn
->addr
));
820 * Create a write buffer detached from any neighbor to send a
821 * notification message reliably.
823 tcp
= tcp_new(pconn
->fd
, NULL
);
824 send_notification(tcp
, S_NO_HELLO
, 0, 0);
825 msgbuf_write(&tcp
->wbuf
.wbuf
);
827 pending_conn_del(pconn
);