summaryrefslogtreecommitdiff
path: root/pimd/pim_pim.c
diff options
context:
space:
mode:
Diffstat (limited to 'pimd/pim_pim.c')
-rw-r--r--pimd/pim_pim.c183
1 files changed, 106 insertions, 77 deletions
diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c
index 82f735465a..1baa5c38ca 100644
--- a/pimd/pim_pim.c
+++ b/pimd/pim_pim.c
@@ -152,6 +152,7 @@ static bool pim_pkt_dst_addr_ok(enum pim_msg_type type, pim_addr addr)
int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len,
pim_sgaddr sg)
{
+ struct iovec iov[2], *iovp = iov;
#if PIM_IPV == 4
struct ip *ip_hdr = (struct ip *)buf;
size_t ip_hlen; /* ip header length in bytes */
@@ -179,11 +180,26 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len,
pim_msg = buf + ip_hlen;
pim_msg_len = len - ip_hlen;
#else
+ struct ipv6_ph phdr = {
+ .src = sg.src,
+ .dst = sg.grp,
+ .ulpl = htonl(len),
+ .next_hdr = IPPROTO_PIM,
+ };
+
+ iovp->iov_base = &phdr;
+ iovp->iov_len = sizeof(phdr);
+ iovp++;
+
/* NB: header is not included in IPv6 RX */
pim_msg = buf;
pim_msg_len = len;
#endif
+ iovp->iov_base = pim_msg;
+ iovp->iov_len = pim_msg_len;
+ iovp++;
+
header = (struct pim_msg_header *)pim_msg;
if (pim_msg_len < PIM_PIM_MIN_LEN) {
if (PIM_DEBUG_PIM_PACKETS)
@@ -215,10 +231,21 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len,
pim_msg_len, PIM_MSG_REGISTER_LEN);
return -1;
}
+
+#if PIM_IPV == 6
+ phdr.ulpl = htonl(PIM_MSG_REGISTER_LEN);
+#endif
/* First 8 byte header checksum */
- checksum = in_cksum(pim_msg, PIM_MSG_REGISTER_LEN);
+ iovp[-1].iov_len = PIM_MSG_REGISTER_LEN;
+ checksum = in_cksumv(iov, iovp - iov);
+
if (checksum != pim_checksum) {
- checksum = in_cksum(pim_msg, pim_msg_len);
+#if PIM_IPV == 6
+ phdr.ulpl = htonl(pim_msg_len);
+#endif
+ iovp[-1].iov_len = pim_msg_len;
+
+ checksum = in_cksumv(iov, iovp - iov);
if (checksum != pim_checksum) {
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug(
@@ -230,7 +257,7 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len,
}
}
} else {
- checksum = in_cksum(pim_msg, pim_msg_len);
+ checksum = in_cksumv(iov, iovp - iov);
if (checksum != pim_checksum) {
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug(
@@ -499,11 +526,8 @@ void pim_sock_reset(struct interface *ifp)
PIM_DEFAULT_PROPAGATION_DELAY_MSEC;
pim_ifp->pim_override_interval_msec =
PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC;
- if (PIM_DEFAULT_CAN_DISABLE_JOIN_SUPPRESSION) {
- PIM_IF_DO_PIM_CAN_DISABLE_JOIN_SUPPRESSION(pim_ifp->options);
- } else {
- PIM_IF_DONT_PIM_CAN_DISABLE_JOIN_SUPPRESSION(pim_ifp->options);
- }
+ pim_ifp->pim_can_disable_join_suppression =
+ PIM_DEFAULT_CAN_DISABLE_JOIN_SUPPRESSION;
/* neighbors without lan_delay */
pim_ifp->pim_number_of_nonlandelay_neighbors = 0;
@@ -522,75 +546,62 @@ void pim_sock_reset(struct interface *ifp)
pim_ifstat_reset(ifp);
}
+#if PIM_IPV == 4
static uint16_t ip_id = 0;
-
+#endif
static int pim_msg_send_frame(int fd, char *buf, size_t len,
struct sockaddr *dst, size_t salen,
const char *ifname)
{
- struct ip *ip = (struct ip *)buf;
-
- if (sendto(fd, buf, len, MSG_DONTWAIT, dst, salen) < 0) {
- char dst_str[INET_ADDRSTRLEN];
-
- switch (errno) {
- case EMSGSIZE: {
- size_t hdrsize = sizeof(struct ip);
- size_t newlen1 = ((len - hdrsize) / 2) & 0xFFF8;
- size_t sendlen = newlen1 + hdrsize;
- size_t offset = ntohs(ip->ip_off);
-
- ip->ip_len = htons(sendlen);
- ip->ip_off = htons(offset | IP_MF);
- if (pim_msg_send_frame(fd, buf, sendlen, dst, salen,
- ifname) == 0) {
- struct ip *ip2 = (struct ip *)(buf + newlen1);
- size_t newlen2 = len - sendlen;
- sendlen = newlen2 + hdrsize;
-
- memcpy(ip2, ip, hdrsize);
- ip2->ip_len = htons(sendlen);
- ip2->ip_off = htons(offset + (newlen1 >> 3));
- return pim_msg_send_frame(fd, (char *)ip2,
- sendlen, dst, salen,
- ifname);
- }
- }
+ if (sendto(fd, buf, len, MSG_DONTWAIT, dst, salen) >= 0)
+ return 0;
- return -1;
- default:
- if (PIM_DEBUG_PIM_PACKETS) {
- pim_inet4_dump("<dst?>", ip->ip_dst, dst_str,
- sizeof(dst_str));
- zlog_warn(
- "%s: sendto() failure to %s: iface=%s fd=%d msg_size=%zd: errno=%d: %s",
- __func__, dst_str, ifname, fd, len,
- errno, safe_strerror(errno));
- }
- return -1;
- }
+#if PIM_IPV == 4
+ if (errno == EMSGSIZE) {
+ struct ip *ip = (struct ip *)buf;
+ size_t hdrsize = sizeof(struct ip);
+ size_t newlen1 = ((len - hdrsize) / 2) & 0xFFF8;
+ size_t sendlen = newlen1 + hdrsize;
+ size_t offset = ntohs(ip->ip_off);
+ int ret;
+
+ ip->ip_len = htons(sendlen);
+ ip->ip_off = htons(offset | IP_MF);
+
+ ret = pim_msg_send_frame(fd, buf, sendlen, dst, salen, ifname);
+ if (ret)
+ return ret;
+
+ struct ip *ip2 = (struct ip *)(buf + newlen1);
+ size_t newlen2 = len - sendlen;
+
+ sendlen = newlen2 + hdrsize;
+
+ memcpy(ip2, ip, hdrsize);
+ ip2->ip_len = htons(sendlen);
+ ip2->ip_off = htons(offset + (newlen1 >> 3));
+ return pim_msg_send_frame(fd, (char *)ip2, sendlen, dst, salen,
+ ifname);
}
+#endif
- return 0;
+ zlog_warn(
+ "%s: sendto() failure to %pSU: iface=%s fd=%d msg_size=%zd: %m",
+ __func__, dst, ifname, fd, len);
+ return -1;
}
int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg,
int pim_msg_size, const char *ifname)
{
- struct sockaddr_in to;
socklen_t tolen;
unsigned char buffer[10000];
unsigned char *msg_start;
uint8_t ttl;
struct pim_msg_header *header;
- struct ip *ip;
memset(buffer, 0, 10000);
- int sendlen = sizeof(struct ip) + pim_msg_size;
-
- msg_start = buffer + sizeof(struct ip);
- memcpy(msg_start, pim_msg, pim_msg_size);
header = (struct pim_msg_header *)pim_msg;
/*
@@ -620,7 +631,11 @@ int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg,
break;
}
- ip = (struct ip *)buffer;
+#if PIM_IPV == 4
+ struct ip *ip = (struct ip *)buffer;
+ struct sockaddr_in to = {};
+ int sendlen = sizeof(*ip) + pim_msg_size;
+
ip->ip_id = htons(++ip_id);
ip->ip_hl = 5;
ip->ip_v = 4;
@@ -631,17 +646,34 @@ int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg,
ip->ip_ttl = ttl;
ip->ip_len = htons(sendlen);
- if (PIM_DEBUG_PIM_PACKETS) {
- char dst_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<dst?>", dst, dst_str, sizeof(dst_str));
- zlog_debug("%s: to %s on %s: msg_size=%d checksum=%x", __func__,
- dst_str, ifname, pim_msg_size, header->checksum);
- }
-
- memset(&to, 0, sizeof(to));
to.sin_family = AF_INET;
to.sin_addr = dst;
tolen = sizeof(to);
+#else
+ struct ip6_hdr *ip = (struct ip6_hdr *)buffer;
+ struct sockaddr_in6 to = {};
+ int sendlen = sizeof(*ip) + pim_msg_size;
+
+ ip->ip6_flow = 0;
+ ip->ip6_vfc = (6 << 4) | (IPTOS_PREC_INTERNETCONTROL >> 4);
+ ip->ip6_plen = htons(pim_msg_size);
+ ip->ip6_nxt = PIM_IP_PROTO_PIM;
+ ip->ip6_hlim = ttl;
+ ip->ip6_src = src;
+ ip->ip6_dst = dst;
+
+ to.sin6_family = AF_INET6;
+ to.sin6_addr = dst;
+ tolen = sizeof(to);
+#endif
+
+ msg_start = buffer + sizeof(*ip);
+ memcpy(msg_start, pim_msg, pim_msg_size);
+
+ if (PIM_DEBUG_PIM_PACKETS)
+ zlog_debug("%s: to %pPA on %s: msg_size=%d checksum=%x",
+ __func__, &dst, ifname, pim_msg_size,
+ header->checksum);
if (PIM_DEBUG_PIM_PACKETDUMP_SEND) {
pim_pkt_dump(__func__, pim_msg, pim_msg_size);
@@ -661,20 +693,15 @@ static int hello_send(struct interface *ifp, uint16_t holdtime)
pim_ifp = ifp->info;
- if (PIM_DEBUG_PIM_HELLO) {
- char dst_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<dst?>", qpim_all_pim_routers_addr, dst_str,
- sizeof(dst_str));
+ if (PIM_DEBUG_PIM_HELLO)
zlog_debug(
- "%s: to %s on %s: holdt=%u prop_d=%u overr_i=%u dis_join_supp=%d dr_prio=%u gen_id=%08x addrs=%d",
- __func__, dst_str, ifp->name, holdtime,
- pim_ifp->pim_propagation_delay_msec,
+ "%s: to %pPA on %s: holdt=%u prop_d=%u overr_i=%u dis_join_supp=%d dr_prio=%u gen_id=%08x addrs=%d",
+ __func__, &qpim_all_pim_routers_addr, ifp->name,
+ holdtime, pim_ifp->pim_propagation_delay_msec,
pim_ifp->pim_override_interval_msec,
- PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPPRESSION(
- pim_ifp->options),
+ pim_ifp->pim_can_disable_join_suppression,
pim_ifp->pim_dr_priority, pim_ifp->pim_generation_id,
listcount(ifp->connected));
- }
pim_tlv_size = pim_hello_build_tlv(
ifp, pim_msg + PIM_PIM_MIN_LEN,
@@ -682,7 +709,7 @@ static int hello_send(struct interface *ifp, uint16_t holdtime)
pim_ifp->pim_dr_priority, pim_ifp->pim_generation_id,
pim_ifp->pim_propagation_delay_msec,
pim_ifp->pim_override_interval_msec,
- PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPPRESSION(pim_ifp->options));
+ pim_ifp->pim_can_disable_join_suppression);
if (pim_tlv_size < 0) {
return -1;
}
@@ -692,7 +719,9 @@ static int hello_send(struct interface *ifp, uint16_t holdtime)
assert(pim_msg_size >= PIM_PIM_MIN_LEN);
assert(pim_msg_size <= PIM_PIM_BUFSIZE_WRITE);
- pim_msg_build_header(pim_msg, pim_msg_size, PIM_MSG_TYPE_HELLO, false);
+ pim_msg_build_header(pim_ifp->primary_address,
+ qpim_all_pim_routers_addr, pim_msg, pim_msg_size,
+ PIM_MSG_TYPE_HELLO, false);
if (pim_msg_send(pim_ifp->pim_sock_fd, pim_ifp->primary_address,
qpim_all_pim_routers_addr, pim_msg, pim_msg_size,