| 449 | */ |
| 450 | #ifdef INET |
| 451 | int |
| 452 | carp_input(struct mbuf **mp, int *offp, int proto) |
| 453 | { |
| 454 | struct mbuf *m = *mp; |
| 455 | struct ip *ip = mtod(m, struct ip *); |
| 456 | struct carp_header *ch; |
| 457 | int iplen, len; |
| 458 | |
| 459 | iplen = *offp; |
| 460 | *mp = NULL; |
| 461 | |
| 462 | CARPSTATS_INC(carps_ipackets); |
| 463 | |
| 464 | if (!V_carp_allow) { |
| 465 | m_freem(m); |
| 466 | return (IPPROTO_DONE); |
| 467 | } |
| 468 | |
| 469 | /* verify that the IP TTL is 255. */ |
| 470 | if (ip->ip_ttl != CARP_DFLTTL) { |
| 471 | CARPSTATS_INC(carps_badttl); |
| 472 | CARP_DEBUG("%s: received ttl %d != 255 on %s\n", __func__, |
| 473 | ip->ip_ttl, |
| 474 | m->m_pkthdr.rcvif->if_xname); |
| 475 | m_freem(m); |
| 476 | return (IPPROTO_DONE); |
| 477 | } |
| 478 | |
| 479 | iplen = ip->ip_hl << 2; |
| 480 | |
| 481 | if (m->m_pkthdr.len < iplen + sizeof(*ch)) { |
| 482 | CARPSTATS_INC(carps_badlen); |
| 483 | CARP_DEBUG("%s: received len %zd < sizeof(struct carp_header) " |
| 484 | "on %s\n", __func__, m->m_len - sizeof(struct ip), |
| 485 | m->m_pkthdr.rcvif->if_xname); |
| 486 | m_freem(m); |
| 487 | return (IPPROTO_DONE); |
| 488 | } |
| 489 | |
| 490 | if (iplen + sizeof(*ch) < m->m_len) { |
| 491 | if ((m = m_pullup(m, iplen + sizeof(*ch))) == NULL) { |
| 492 | CARPSTATS_INC(carps_hdrops); |
| 493 | CARP_DEBUG("%s: pullup failed\n", __func__); |
| 494 | return (IPPROTO_DONE); |
| 495 | } |
| 496 | ip = mtod(m, struct ip *); |
| 497 | } |
| 498 | ch = (struct carp_header *)((char *)ip + iplen); |
| 499 | |
| 500 | /* |
| 501 | * verify that the received packet length is |
| 502 | * equal to the CARP header |
| 503 | */ |
| 504 | len = iplen + sizeof(*ch); |
| 505 | if (len > m->m_pkthdr.len) { |
| 506 | CARPSTATS_INC(carps_badlen); |
| 507 | CARP_DEBUG("%s: packet too short %d on %s\n", __func__, |
| 508 | m->m_pkthdr.len, |
nothing calls this directly
no test coverage detected