Coverage Report

Created: 2026-08-26 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/frr/bgpd/bgp_io.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/* BGP I/O.
3
 * Implements packet I/O in a pthread.
4
 * Copyright (C) 2017  Cumulus Networks
5
 * Quentin Young
6
 */
7
8
/* clang-format off */
9
#include <zebra.h>
10
#include <pthread.h>    // for pthread_mutex_unlock, pthread_mutex_lock
11
#include <sys/uio.h>    // for writev
12
13
#include "frr_pthread.h"
14
#include "linklist.h"   // for list_delete, list_delete_all_node, lis...
15
#include "log.h"    // for zlog_debug, safe_strerror, zlog_err
16
#include "memory.h"   // for MTYPE_TMP, XCALLOC, XFREE
17
#include "network.h"    // for ERRNO_IO_RETRY
18
#include "stream.h"   // for stream_get_endp, stream_getw_from, str...
19
#include "ringbuf.h"    // for ringbuf_remain, ringbuf_peek, ringbuf_...
20
#include "frrevent.h"   // for EVENT_OFF, EVENT_ARG, thread...
21
22
#include "bgpd/bgp_io.h"
23
#include "bgpd/bgp_debug.h" // for bgp_debug_neighbor_events, bgp_type_str
24
#include "bgpd/bgp_errors.h"  // for expanded error reference information
25
#include "bgpd/bgp_fsm.h" // for BGP_EVENT_ADD, bgp_event
26
#include "bgpd/bgp_packet.h"  // for bgp_notify_io_invalid...
27
#include "bgpd/bgp_trace.h" // for frrtraces
28
#include "bgpd/bgpd.h"    // for peer, BGP_MARKER_SIZE, bgp_master, bm
29
/* clang-format on */
30
31
/* forward declarations */
32
static uint16_t bgp_write(struct peer *);
33
static uint16_t bgp_read(struct peer *peer, int *code_p);
34
static void bgp_process_writes(struct event *event);
35
static void bgp_process_reads(struct event *event);
36
bool validate_header(struct peer *);
37
38
/* generic i/o status codes */
39
#define BGP_IO_TRANS_ERR (1 << 0) /* EAGAIN or similar occurred */
40
#define BGP_IO_FATAL_ERR (1 << 1) /* some kind of fatal TCP error */
41
#define BGP_IO_WORK_FULL_ERR (1 << 2) /* No room in work buffer */
42
43
/* Thread external API ----------------------------------------------------- */
44
45
void bgp_writes_on(struct peer *peer)
46
2
{
47
2
#ifdef FUZZING
48
2
  return;
49
0
#endif
50
0
  struct frr_pthread *fpt = bgp_pth_io;
51
0
  assert(fpt->running);
52
53
0
  assert(peer->status != Deleted);
54
0
  assert(peer->obuf);
55
0
  assert(peer->ibuf);
56
0
  assert(peer->ibuf_work);
57
0
  assert(!peer->t_connect_check_r);
58
0
  assert(!peer->t_connect_check_w);
59
0
  assert(peer->fd);
60
61
0
  event_add_write(fpt->master, bgp_process_writes, peer, peer->fd,
62
0
      &peer->t_write);
63
0
  SET_FLAG(peer->thread_flags, PEER_THREAD_WRITES_ON);
64
0
}
65
66
void bgp_writes_off(struct peer *peer)
67
0
{
68
0
#ifdef FUZZING
69
0
  return;
70
0
#endif
71
0
  struct frr_pthread *fpt = bgp_pth_io;
72
0
  assert(fpt->running);
73
74
0
  event_cancel_async(fpt->master, &peer->t_write, NULL);
75
0
  EVENT_OFF(peer->t_generate_updgrp_packets);
76
77
0
  UNSET_FLAG(peer->thread_flags, PEER_THREAD_WRITES_ON);
78
0
}
79
80
void bgp_reads_on(struct peer *peer)
81
0
{
82
0
#ifdef FUZZING
83
0
  return;
84
0
#endif
85
0
  struct frr_pthread *fpt = bgp_pth_io;
86
0
  assert(fpt->running);
87
88
0
  assert(peer->status != Deleted);
89
0
  assert(peer->ibuf);
90
0
  assert(peer->fd);
91
0
  assert(peer->ibuf_work);
92
0
  assert(peer->obuf);
93
0
  assert(!peer->t_connect_check_r);
94
0
  assert(!peer->t_connect_check_w);
95
0
  assert(peer->fd);
96
97
0
  event_add_read(fpt->master, bgp_process_reads, peer, peer->fd,
98
0
           &peer->t_read);
99
100
0
  SET_FLAG(peer->thread_flags, PEER_THREAD_READS_ON);
101
0
}
102
103
void bgp_reads_off(struct peer *peer)
104
0
{
105
0
#ifdef FUZZING
106
0
  return;
107
0
#endif
108
0
  struct frr_pthread *fpt = bgp_pth_io;
109
0
  assert(fpt->running);
110
111
0
  event_cancel_async(fpt->master, &peer->t_read, NULL);
112
0
  EVENT_OFF(peer->t_process_packet);
113
0
  EVENT_OFF(peer->t_process_packet_error);
114
115
0
  UNSET_FLAG(peer->thread_flags, PEER_THREAD_READS_ON);
116
0
}
117
118
/* Thread internal functions ----------------------------------------------- */
119
120
/*
121
 * Called from I/O pthread when a file descriptor has become ready for writing.
122
 */
123
static void bgp_process_writes(struct event *thread)
124
0
{
125
0
  static struct peer *peer;
126
0
  peer = EVENT_ARG(thread);
127
0
  uint16_t status;
128
0
  bool reschedule;
129
0
  bool fatal = false;
130
0
131
0
  if (peer->fd < 0)
132
0
    return;
133
0
134
0
  struct frr_pthread *fpt = bgp_pth_io;
135
0
136
0
  frr_with_mutex (&peer->io_mtx) {
137
0
    status = bgp_write(peer);
138
0
    reschedule = (stream_fifo_head(peer->obuf) != NULL);
139
0
  }
140
0
141
0
  /* no problem */
142
0
  if (CHECK_FLAG(status, BGP_IO_TRANS_ERR)) {
143
0
  }
144
0
145
0
  /* problem */
146
0
  if (CHECK_FLAG(status, BGP_IO_FATAL_ERR)) {
147
0
    reschedule = false;
148
0
    fatal = true;
149
0
  }
150
0
151
0
  /* If suppress fib pending is enabled, route is advertised to peers when
152
0
   * the status is received from the FIB. The delay is added
153
0
   * to update group packet generate which will allow more routes to be
154
0
   * sent in the update message
155
0
   */
156
0
  if (reschedule) {
157
0
    event_add_write(fpt->master, bgp_process_writes, peer, peer->fd,
158
0
        &peer->t_write);
159
0
  } else if (!fatal) {
160
0
    BGP_UPDATE_GROUP_TIMER_ON(&peer->t_generate_updgrp_packets,
161
0
            bgp_generate_updgrp_packets);
162
0
  }
163
0
}
164
165
static int read_ibuf_work(struct peer *peer)
166
0
{
167
0
  /* static buffer for transferring packets */
168
0
  /* shorter alias to peer's input buffer */
169
0
  struct ringbuf *ibw = peer->ibuf_work;
170
0
  /* packet size as given by header */
171
0
  uint16_t pktsize = 0;
172
0
  struct stream *pkt;
173
0
174
0
  /* ============================================== */
175
0
  frr_with_mutex (&peer->io_mtx) {
176
0
    if (peer->ibuf->count >= bm->inq_limit)
177
0
      return -ENOMEM;
178
0
  }
179
0
180
0
  /* check that we have enough data for a header */
181
0
  if (ringbuf_remain(ibw) < BGP_HEADER_SIZE)
182
0
    return 0;
183
0
184
0
  /* check that header is valid */
185
0
  if (!validate_header(peer))
186
0
    return -EBADMSG;
187
0
188
0
  /* header is valid; retrieve packet size */
189
0
  ringbuf_peek(ibw, BGP_MARKER_SIZE, &pktsize, sizeof(pktsize));
190
0
191
0
  pktsize = ntohs(pktsize);
192
0
193
0
  /* if this fails we are seriously screwed */
194
0
  assert(pktsize <= peer->max_packet_size);
195
0
196
0
  /*
197
0
   * If we have that much data, chuck it into its own
198
0
   * stream and append to input queue for processing.
199
0
   *
200
0
   * Otherwise, come back later.
201
0
   */
202
0
  if (ringbuf_remain(ibw) < pktsize)
203
0
    return 0;
204
0
205
0
  pkt = stream_new(pktsize);
206
0
  assert(STREAM_WRITEABLE(pkt) == pktsize);
207
0
  assert(ringbuf_get(ibw, pkt->data, pktsize) == pktsize);
208
0
  stream_set_endp(pkt, pktsize);
209
0
210
0
  frrtrace(2, frr_bgp, packet_read, peer, pkt);
211
0
  frr_with_mutex (&peer->io_mtx) {
212
0
    stream_fifo_push(peer->ibuf, pkt);
213
0
  }
214
0
215
0
  return pktsize;
216
0
}
217
218
/*
219
 * Called from I/O pthread when a file descriptor has become ready for reading,
220
 * or has hung up.
221
 *
222
 * We read as much data as possible, process as many packets as we can and
223
 * place them on peer->ibuf for secondary processing by the main thread.
224
 */
225
static void bgp_process_reads(struct event *thread)
226
0
{
227
0
  /* clang-format off */
228
0
  static struct peer *peer;       /* peer to read from */
229
0
  uint16_t status;                /* bgp_read status code */
230
0
  bool fatal = false;             /* whether fatal error occurred */
231
0
  bool added_pkt = false;         /* whether we pushed onto ->ibuf */
232
0
  int code = 0;                   /* FSM code if error occurred */
233
0
  static bool ibuf_full_logged;   /* Have we logged full already */
234
0
  int ret = 1;
235
0
  /* clang-format on */
236
0
237
0
  peer = EVENT_ARG(thread);
238
0
239
0
  if (bm->terminating || peer->fd < 0)
240
0
    return;
241
0
242
0
  struct frr_pthread *fpt = bgp_pth_io;
243
0
244
0
  frr_with_mutex (&peer->io_mtx) {
245
0
    status = bgp_read(peer, &code);
246
0
  }
247
0
248
0
  /* error checking phase */
249
0
  if (CHECK_FLAG(status, BGP_IO_TRANS_ERR)) {
250
0
    /* no problem; just don't process packets */
251
0
    goto done;
252
0
  }
253
0
254
0
  if (CHECK_FLAG(status, BGP_IO_FATAL_ERR)) {
255
0
    /* problem; tear down session */
256
0
    fatal = true;
257
0
258
0
    /* Handle the error in the main pthread, include the
259
0
     * specific state change from 'bgp_read'.
260
0
     */
261
0
    event_add_event(bm->master, bgp_packet_process_error, peer,
262
0
        code, &peer->t_process_packet_error);
263
0
    goto done;
264
0
  }
265
0
266
0
  while (true) {
267
0
    ret = read_ibuf_work(peer);
268
0
    if (ret <= 0)
269
0
      break;
270
0
271
0
    added_pkt = true;
272
0
  }
273
0
274
0
  switch (ret) {
275
0
  case -EBADMSG:
276
0
    fatal = true;
277
0
    break;
278
0
  case -ENOMEM:
279
0
    if (!ibuf_full_logged) {
280
0
      if (bgp_debug_neighbor_events(peer))
281
0
        zlog_debug(
282
0
          "%s [Event] Peer Input-Queue is full: limit (%u)",
283
0
          peer->host, bm->inq_limit);
284
0
285
0
      ibuf_full_logged = true;
286
0
    }
287
0
    break;
288
0
  default:
289
0
    ibuf_full_logged = false;
290
0
    break;
291
0
  }
292
0
293
0
done:
294
0
  /* handle invalid header */
295
0
  if (fatal) {
296
0
    /* wipe buffer just in case someone screwed up */
297
0
    ringbuf_wipe(peer->ibuf_work);
298
0
    return;
299
0
  }
300
0
301
0
  event_add_read(fpt->master, bgp_process_reads, peer, peer->fd,
302
0
           &peer->t_read);
303
0
  if (added_pkt)
304
0
    event_add_event(bm->master, bgp_process_packet, peer, 0,
305
0
        &peer->t_process_packet);
306
0
}
307
308
/*
309
 * Flush peer output buffer.
310
 *
311
 * This function pops packets off of peer->obuf and writes them to peer->fd.
312
 * The amount of packets written is equal to the minimum of peer->wpkt_quanta
313
 * and the number of packets on the output buffer, unless an error occurs.
314
 *
315
 * If write() returns an error, the appropriate FSM event is generated.
316
 *
317
 * The return value is equal to the number of packets written
318
 * (which may be zero).
319
 */
320
static uint16_t bgp_write(struct peer *peer)
321
0
{
322
0
  uint8_t type;
323
0
  struct stream *s;
324
0
  int update_last_write = 0;
325
0
  unsigned int count;
326
0
  uint32_t uo = 0;
327
0
  uint16_t status = 0;
328
0
  uint32_t wpkt_quanta_old;
329
0
330
0
  int writenum = 0;
331
0
  int num;
332
0
  unsigned int iovsz;
333
0
  unsigned int strmsz;
334
0
  unsigned int total_written;
335
0
  time_t now;
336
0
337
0
  wpkt_quanta_old = atomic_load_explicit(&peer->bgp->wpkt_quanta,
338
0
                 memory_order_relaxed);
339
0
  struct stream *ostreams[wpkt_quanta_old];
340
0
  struct stream **streams = ostreams;
341
0
  struct iovec iov[wpkt_quanta_old];
342
0
343
0
  s = stream_fifo_head(peer->obuf);
344
0
345
0
  if (!s)
346
0
    goto done;
347
0
348
0
  count = iovsz = 0;
349
0
  while (count < wpkt_quanta_old && iovsz < array_size(iov) && s) {
350
0
    ostreams[iovsz] = s;
351
0
    iov[iovsz].iov_base = stream_pnt(s);
352
0
    iov[iovsz].iov_len = STREAM_READABLE(s);
353
0
    writenum += STREAM_READABLE(s);
354
0
    s = s->next;
355
0
    ++iovsz;
356
0
    ++count;
357
0
  }
358
0
359
0
  strmsz = iovsz;
360
0
  total_written = 0;
361
0
362
0
  do {
363
0
    num = writev(peer->fd, iov, iovsz);
364
0
365
0
    if (num < 0) {
366
0
      if (!ERRNO_IO_RETRY(errno)) {
367
0
        BGP_EVENT_ADD(peer, TCP_fatal_error);
368
0
        SET_FLAG(status, BGP_IO_FATAL_ERR);
369
0
      } else {
370
0
        SET_FLAG(status, BGP_IO_TRANS_ERR);
371
0
      }
372
0
373
0
      break;
374
0
    } else if (num != writenum) {
375
0
      unsigned int msg_written = 0;
376
0
      unsigned int ic = iovsz;
377
0
378
0
      for (unsigned int i = 0; i < ic; i++) {
379
0
        size_t ss = iov[i].iov_len;
380
0
381
0
        if (ss > (unsigned int) num)
382
0
          break;
383
0
384
0
        msg_written++;
385
0
        iovsz--;
386
0
        writenum -= ss;
387
0
        num -= ss;
388
0
      }
389
0
390
0
      total_written += msg_written;
391
0
392
0
      assert(total_written < count);
393
0
394
0
      memmove(&iov, &iov[msg_written],
395
0
        sizeof(iov[0]) * iovsz);
396
0
      streams = &streams[msg_written];
397
0
      stream_forward_getp(streams[0], num);
398
0
      iov[0].iov_base = stream_pnt(streams[0]);
399
0
      iov[0].iov_len = STREAM_READABLE(streams[0]);
400
0
401
0
      writenum -= num;
402
0
      num = 0;
403
0
      assert(writenum > 0);
404
0
    } else {
405
0
      total_written = strmsz;
406
0
    }
407
0
408
0
  } while (num != writenum);
409
0
410
0
  /* Handle statistics */
411
0
  for (unsigned int i = 0; i < total_written; i++) {
412
0
    s = stream_fifo_pop(peer->obuf);
413
0
414
0
    assert(s == ostreams[i]);
415
0
416
0
    /* Retrieve BGP packet type. */
417
0
    stream_set_getp(s, BGP_MARKER_SIZE + 2);
418
0
    type = stream_getc(s);
419
0
420
0
    switch (type) {
421
0
    case BGP_MSG_OPEN:
422
0
      atomic_fetch_add_explicit(&peer->open_out, 1,
423
0
              memory_order_relaxed);
424
0
      break;
425
0
    case BGP_MSG_UPDATE:
426
0
      atomic_fetch_add_explicit(&peer->update_out, 1,
427
0
              memory_order_relaxed);
428
0
      uo++;
429
0
      break;
430
0
    case BGP_MSG_NOTIFY:
431
0
      atomic_fetch_add_explicit(&peer->notify_out, 1,
432
0
              memory_order_relaxed);
433
0
      /* Double start timer. */
434
0
      peer->v_start *= 2;
435
0
436
0
      /* Overflow check. */
437
0
      if (peer->v_start >= (60 * 2))
438
0
        peer->v_start = (60 * 2);
439
0
440
0
      /*
441
0
       * Handle Graceful Restart case where the state changes
442
0
       * to Connect instead of Idle.
443
0
       */
444
0
      BGP_EVENT_ADD(peer, BGP_Stop);
445
0
      goto done;
446
0
447
0
    case BGP_MSG_KEEPALIVE:
448
0
      atomic_fetch_add_explicit(&peer->keepalive_out, 1,
449
0
              memory_order_relaxed);
450
0
      break;
451
0
    case BGP_MSG_ROUTE_REFRESH_NEW:
452
0
    case BGP_MSG_ROUTE_REFRESH_OLD:
453
0
      atomic_fetch_add_explicit(&peer->refresh_out, 1,
454
0
              memory_order_relaxed);
455
0
      break;
456
0
    case BGP_MSG_CAPABILITY:
457
0
      atomic_fetch_add_explicit(&peer->dynamic_cap_out, 1,
458
0
              memory_order_relaxed);
459
0
      break;
460
0
    }
461
0
462
0
    stream_free(s);
463
0
    ostreams[i] = NULL;
464
0
    update_last_write = 1;
465
0
  }
466
0
467
0
done : {
468
0
  now = monotime(NULL);
469
0
  /*
470
0
   * Update last_update if UPDATEs were written.
471
0
   * Note: that these are only updated at end,
472
0
   *       not per message (i.e., per loop)
473
0
   */
474
0
  if (uo)
475
0
    atomic_store_explicit(&peer->last_update, now,
476
0
              memory_order_relaxed);
477
0
478
0
  /* If we TXed any flavor of packet */
479
0
  if (update_last_write) {
480
0
    atomic_store_explicit(&peer->last_write, now,
481
0
              memory_order_relaxed);
482
0
    peer->last_sendq_ok = now;
483
0
  }
484
0
}
485
0
486
0
  return status;
487
0
}
488
489
uint8_t ibuf_scratch[BGP_EXTENDED_MESSAGE_MAX_PACKET_SIZE * BGP_READ_PACKET_MAX];
490
/*
491
 * Reads a chunk of data from peer->fd into peer->ibuf_work.
492
 *
493
 * code_p
494
 *    Pointer to location to store FSM event code in case of fatal error.
495
 *
496
 * @return status flag (see top-of-file)
497
 *
498
 * PLEASE NOTE:  If we ever transform the bgp_read to be a pthread
499
 * per peer then we need to rethink the global ibuf_scratch
500
 * data structure above.
501
 */
502
static uint16_t bgp_read(struct peer *peer, int *code_p)
503
0
{
504
0
  size_t readsize; /* how many bytes we want to read */
505
0
  ssize_t nbytes;  /* how many bytes we actually read */
506
0
  size_t ibuf_work_space; /* space we can read into the work buf */
507
0
  uint16_t status = 0;
508
0
509
0
  ibuf_work_space = ringbuf_space(peer->ibuf_work);
510
0
511
0
  if (ibuf_work_space == 0) {
512
0
    SET_FLAG(status, BGP_IO_WORK_FULL_ERR);
513
0
    return status;
514
0
  }
515
0
516
0
  readsize = MIN(ibuf_work_space, sizeof(ibuf_scratch));
517
0
518
0
  nbytes = read(peer->fd, ibuf_scratch, readsize);
519
0
520
0
  /* EAGAIN or EWOULDBLOCK; come back later */
521
0
  if (nbytes < 0 && ERRNO_IO_RETRY(errno)) {
522
0
    SET_FLAG(status, BGP_IO_TRANS_ERR);
523
0
  } else if (nbytes < 0) {
524
0
    /* Fatal error; tear down session */
525
0
    flog_err(EC_BGP_UPDATE_RCV,
526
0
       "%s [Error] bgp_read_packet error: %s", peer->host,
527
0
       safe_strerror(errno));
528
0
529
0
    /* Handle the error in the main pthread. */
530
0
    if (code_p)
531
0
      *code_p = TCP_fatal_error;
532
0
533
0
    SET_FLAG(status, BGP_IO_FATAL_ERR);
534
0
535
0
  } else if (nbytes == 0) {
536
0
    /* Received EOF / TCP session closed */
537
0
    if (bgp_debug_neighbor_events(peer))
538
0
      zlog_debug("%s [Event] BGP connection closed fd %d",
539
0
           peer->host, peer->fd);
540
0
541
0
    /* Handle the error in the main pthread. */
542
0
    if (code_p)
543
0
      *code_p = TCP_connection_closed;
544
0
545
0
    SET_FLAG(status, BGP_IO_FATAL_ERR);
546
0
  } else {
547
0
    assert(ringbuf_put(peer->ibuf_work, ibuf_scratch, nbytes) ==
548
0
           (size_t)nbytes);
549
0
  }
550
0
551
0
  return status;
552
0
}
553
554
/*
555
 * Called after we have read a BGP packet header. Validates marker, message
556
 * type and packet length. If any of these aren't correct, sends a notify.
557
 *
558
 * Assumes that there are at least BGP_HEADER_SIZE readable bytes in the input
559
 * buffer.
560
 */
561
bool validate_header(struct peer *peer)
562
797
{
563
797
  uint16_t size;
564
797
  uint8_t type;
565
797
  struct ringbuf *pkt = peer->ibuf_work;
566
567
797
  static const uint8_t m_correct[BGP_MARKER_SIZE] = {
568
797
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
569
797
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
570
797
  uint8_t m_rx[BGP_MARKER_SIZE] = {0x00};
571
572
797
  if (ringbuf_peek(pkt, 0, m_rx, BGP_MARKER_SIZE) != BGP_MARKER_SIZE)
573
0
    return false;
574
575
797
  if (memcmp(m_correct, m_rx, BGP_MARKER_SIZE) != 0) {
576
19
    bgp_notify_io_invalid(peer, BGP_NOTIFY_HEADER_ERR,
577
19
              BGP_NOTIFY_HEADER_NOT_SYNC, NULL, 0);
578
19
    return false;
579
19
  }
580
581
  /* Get size and type in network byte order. */
582
778
  ringbuf_peek(pkt, BGP_MARKER_SIZE, &size, sizeof(size));
583
778
  ringbuf_peek(pkt, BGP_MARKER_SIZE + 2, &type, sizeof(type));
584
585
778
  size = ntohs(size);
586
587
  /* BGP type check. */
588
778
  if (type != BGP_MSG_OPEN && type != BGP_MSG_UPDATE
589
150
      && type != BGP_MSG_NOTIFY && type != BGP_MSG_KEEPALIVE
590
134
      && type != BGP_MSG_ROUTE_REFRESH_NEW
591
32
      && type != BGP_MSG_ROUTE_REFRESH_OLD
592
16
      && type != BGP_MSG_CAPABILITY) {
593
9
    if (bgp_debug_neighbor_events(peer))
594
0
      zlog_debug("%s unknown message type 0x%02x", peer->host,
595
9
           type);
596
597
9
    bgp_notify_io_invalid(peer, BGP_NOTIFY_HEADER_ERR,
598
9
              BGP_NOTIFY_HEADER_BAD_MESTYPE, &type, 1);
599
9
    return false;
600
9
  }
601
602
  /* Minimum packet length check. */
603
769
  if ((size < BGP_HEADER_SIZE) || (size > peer->max_packet_size)
604
769
      || (type == BGP_MSG_OPEN && size < BGP_MSG_OPEN_MIN_SIZE)
605
769
      || (type == BGP_MSG_UPDATE && size < BGP_MSG_UPDATE_MIN_SIZE)
606
769
      || (type == BGP_MSG_NOTIFY && size < BGP_MSG_NOTIFY_MIN_SIZE)
607
769
      || (type == BGP_MSG_KEEPALIVE && size != BGP_MSG_KEEPALIVE_MIN_SIZE)
608
769
      || (type == BGP_MSG_ROUTE_REFRESH_NEW
609
102
    && size < BGP_MSG_ROUTE_REFRESH_MIN_SIZE)
610
769
      || (type == BGP_MSG_ROUTE_REFRESH_OLD
611
16
    && size < BGP_MSG_ROUTE_REFRESH_MIN_SIZE)
612
769
      || (type == BGP_MSG_CAPABILITY
613
7
    && size < BGP_MSG_CAPABILITY_MIN_SIZE)) {
614
0
    if (bgp_debug_neighbor_events(peer)) {
615
0
      zlog_debug("%s bad message length - %d for %s",
616
0
           peer->host, size,
617
0
           type == 128 ? "ROUTE-REFRESH"
618
0
                 : bgp_type_str[(int)type]);
619
0
    }
620
621
0
    uint16_t nsize = htons(size);
622
623
0
    bgp_notify_io_invalid(peer, BGP_NOTIFY_HEADER_ERR,
624
0
              BGP_NOTIFY_HEADER_BAD_MESLEN,
625
0
              (unsigned char *)&nsize, 2);
626
0
    return false;
627
0
  }
628
629
769
  return true;
630
769
}