diff options
-rw-r--r-- | usr.sbin/bgpd/bgpd.h | 12 | ||||
-rw-r--r-- | usr.sbin/bgpd/session.c | 120 |
2 files changed, 61 insertions, 71 deletions
diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h index b4bc9f1fab8..00db245eaa8 100644 --- a/usr.sbin/bgpd/bgpd.h +++ b/usr.sbin/bgpd/bgpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpd.h,v 1.19 2003/12/24 20:09:57 henning Exp $ */ +/* $OpenBSD: bgpd.h,v 1.20 2003/12/24 23:14:23 henning Exp $ */ /* * Copyright (c) 2003 Henning Brauer <henning@openbsd.org> @@ -34,6 +34,7 @@ #define MAX_PKTSIZE 4096 #define MIN_HOLDTIME 3 +#define READ_BUF_SIZE 65535 #define BGPD_OPT_VERBOSE 0x0001 #define BGPD_OPT_VERBOSE2 0x0002 @@ -107,12 +108,9 @@ struct bgpd_config { }; struct peer_buf_read { - u_char buf[MAX_PKTSIZE]; - ssize_t read_len; - u_int16_t pkt_len; - u_int8_t type; - u_char *wptr; - u_int8_t seen_hdr; + u_char buf[READ_BUF_SIZE]; + u_char *rptr; + ssize_t wpos; }; struct peer_config { diff --git a/usr.sbin/bgpd/session.c b/usr.sbin/bgpd/session.c index 33a9ce14418..8b99ee1981f 100644 --- a/usr.sbin/bgpd/session.c +++ b/usr.sbin/bgpd/session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: session.c,v 1.37 2003/12/24 21:19:48 henning Exp $ */ +/* $OpenBSD: session.c,v 1.38 2003/12/24 23:14:23 henning Exp $ */ /* * Copyright (c) 2003 Henning Brauer <henning@openbsd.org> @@ -323,8 +323,7 @@ bgp_fsm(struct peer *peer, enum session_events event) peer->rbuf = calloc(1, sizeof(struct peer_buf_read)); if (peer->rbuf == NULL) fatal(NULL, errno); - peer->rbuf->wptr = peer->rbuf->buf; - peer->rbuf->pkt_len = MSGSIZE_HEADER; + peer->rbuf->wpos = 0; /* init write buffer */ msgbuf_init(&peer->wbuf); @@ -868,9 +867,11 @@ session_notification(struct peer *peer, u_int8_t errcode, u_int8_t subcode, int session_dispatch_msg(struct pollfd *pfd, struct peer *peer) { - ssize_t n, read_total; + ssize_t n, rpos, av, left; socklen_t len; int error; + u_int16_t msglen; + u_int8_t msgtype; if (peer->state == STATE_CONNECT) { if (pfd->revents & POLLOUT) { @@ -922,10 +923,8 @@ session_dispatch_msg(struct pollfd *pfd, struct peer *peer) } if (pfd->revents & POLLIN) { - read_total = 0; - do { - if ((n = read(peer->sock, peer->rbuf->wptr, - peer->rbuf->pkt_len - peer->rbuf->read_len)) == + if ((n = read(peer->sock, peer->rbuf->buf + peer->rbuf->wpos, + sizeof(peer->rbuf->buf) - peer->rbuf->wpos)) == -1) { if (errno != EINTR) { log_err(peer, "read error"); @@ -933,61 +932,54 @@ session_dispatch_msg(struct pollfd *pfd, struct peer *peer) } return (1); } - read_total += n; - peer->rbuf->wptr += n; - peer->rbuf->read_len += n; - if (peer->rbuf->read_len == peer->rbuf->pkt_len) { - if (!peer->rbuf->seen_hdr) { /* got header */ - if (parse_header(peer, - peer->rbuf->buf, - &peer->rbuf->pkt_len, - &peer->rbuf->type) == 1) { - bgp_fsm(peer, EVNT_CON_FATAL); - return (1); - } - peer->rbuf->seen_hdr = 1; - } else { /* we got the full packet */ - switch (peer->rbuf->type) { - case OPEN: - bgp_fsm(peer, EVNT_RCVD_OPEN); - break; - case UPDATE: - bgp_fsm(peer, EVNT_RCVD_UPDATE); - break; - case NOTIFICATION: - bgp_fsm(peer, - EVNT_RCVD_NOTIFICATION); - break; - case KEEPALIVE: - bgp_fsm(peer, - EVNT_RCVD_KEEPALIVE); - break; - default: /* cannot happen */ - session_notification(peer, - ERR_HEADER, ERR_HDR_TYPE, - &peer->rbuf->type, 1); - logit(LOG_CRIT, - "received message with " - "unknown type %u", - peer->rbuf->type); - } - n = 0; /* give others a chance... */ - if (peer->rbuf != NULL) { - bzero(peer->rbuf, sizeof(struct - peer_buf_read)); - peer->rbuf->wptr = - peer->rbuf->buf; - peer->rbuf->pkt_len = - MSGSIZE_HEADER; - } + if (n == 0) /* connection closed */ + bgp_fsm(peer, EVNT_CON_CLOSED); + + rpos = 0; + av = peer->rbuf->wpos + n; + + for (;;) { + if (rpos + MSGSIZE_HEADER > av) + break; + if (parse_header(peer, peer->rbuf->buf + rpos, + &msglen, &msgtype) == -1) + return (0); + if (rpos + msglen > av) + break; + peer->rbuf->rptr = peer->rbuf->buf + rpos; + + switch (msgtype) { + case OPEN: + bgp_fsm(peer, EVNT_RCVD_OPEN); + break; + case UPDATE: + bgp_fsm(peer, EVNT_RCVD_UPDATE); + break; + case NOTIFICATION: + bgp_fsm(peer, EVNT_RCVD_NOTIFICATION); + break; + case KEEPALIVE: + bgp_fsm(peer, EVNT_RCVD_KEEPALIVE); + break; + default: /* cannot happen */ + session_notification(peer, ERR_HEADER, + ERR_HDR_TYPE, &msgtype, 1); + logit(LOG_CRIT, + "received message with unknown type" + " %u", msgtype); } + rpos += msglen; } - } while (n > 0); - if (read_total == 0) /* connection closed */ - bgp_fsm(peer, EVNT_CON_CLOSED); + if (rpos < av) { + left = av - rpos; + memcpy(&peer->rbuf->buf, peer->rbuf->buf + rpos, + left); + peer->rbuf->wpos = left; + } else + peer->rbuf->wpos = 0; + return (1); } - return (0); } @@ -1081,7 +1073,7 @@ parse_open(struct peer *peer) u_int32_t bgpid; u_int8_t optparamlen; - p = peer->rbuf->buf; + p = peer->rbuf->rptr; p += MSGSIZE_HEADER; /* header is already checked */ memcpy(&version, p, sizeof(version)); @@ -1152,12 +1144,12 @@ parse_update(struct peer *peer) * in case of errors the whole session is reset with a * notification anyway, we only need to know the peer */ - p = peer->rbuf->buf; + p = peer->rbuf->rptr; p += MSGSIZE_HEADER_MARKER; memcpy(&datalen, p, sizeof(datalen)); datalen = ntohs(datalen); - p = peer->rbuf->buf; + p = peer->rbuf->rptr; p += MSGSIZE_HEADER; /* header is already checked */ datalen -= MSGSIZE_HEADER; @@ -1175,12 +1167,12 @@ parse_notification(struct peer *peer) u_int16_t datalen; /* just log */ - p = peer->rbuf->buf; + p = peer->rbuf->rptr; p += MSGSIZE_HEADER_MARKER; memcpy(&datalen, p, sizeof(datalen)); datalen = ntohs(datalen); - p = peer->rbuf->buf; + p = peer->rbuf->rptr; p += MSGSIZE_HEADER; /* header is already checked */ datalen -= MSGSIZE_HEADER; |