summaryrefslogtreecommitdiffstats
path: root/pimd/pim_pim.c
diff options
context:
space:
mode:
authorDonald Sharp <sharpd@cumulusnetworks.com>2016-09-08 14:42:04 +0200
committerDonald Sharp <sharpd@cumulusnetworks.com>2016-12-22 02:26:08 +0100
commitc305ed63eba226a78fff6179b2b9aef84826b728 (patch)
treed72c01c71fb17540f7e974b43690256be5664b73 /pimd/pim_pim.c
parentpimd: Fix display of rp information in 'show run' (diff)
downloadfrr-c305ed63eba226a78fff6179b2b9aef84826b728.tar.xz
frr-c305ed63eba226a78fff6179b2b9aef84826b728.zip
pimd: Allow breaking up of packet.
When a packet is too large to send in one go, break it up. Ticket: CM-12768 Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
Diffstat (limited to 'pimd/pim_pim.c')
-rw-r--r--pimd/pim_pim.c84
1 files changed, 57 insertions, 27 deletions
diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c
index 4924acea7..8b34a4557 100644
--- a/pimd/pim_pim.c
+++ b/pimd/pim_pim.c
@@ -480,14 +480,62 @@ void pim_sock_reset(struct interface *ifp)
static uint16_t ip_id = 0;
-int pim_msg_send(int fd,
- struct in_addr src,
- struct in_addr dst,
- uint8_t *pim_msg,
- int pim_msg_size,
- const char *ifname)
+
+static int
+pim_msg_send_frame (int fd, char *buf, size_t len,
+ struct sockaddr *dst, size_t salen)
+{
+ struct ip *ip = (struct ip *)buf;
+
+ while (sendto (fd, buf, len, MSG_DONTWAIT, dst, salen) < 0)
+ {
+ char dst_str[100];
+
+ 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) == 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);
+ }
+ }
+
+ return -1;
+ break;
+ default:
+ pim_inet4_dump ("<dst?>", ip->ip_dst, dst_str, sizeof (dst_str));
+ zlog_warn ("%s: sendto() failure to %s: fd=%d msg_size=%zd: errno=%d: %s",
+ __PRETTY_FUNCTION__,
+ dst_str, fd, len,
+ errno, safe_strerror(errno));
+ break;
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int
+pim_msg_send(int fd, struct in_addr src,
+ struct in_addr dst, uint8_t *pim_msg,
+ int pim_msg_size, const char *ifname)
{
- ssize_t sent;
struct sockaddr_in to;
socklen_t tolen;
unsigned char buffer[3000];
@@ -528,26 +576,8 @@ int pim_msg_send(int fd,
pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_size);
}
- sent = sendto(fd, buffer, sendlen, MSG_DONTWAIT,
- (struct sockaddr *)&to, tolen);
- if (sent != (ssize_t) sendlen) {
- char dst_str[100];
- pim_inet4_dump("<dst?>", dst, dst_str, sizeof(dst_str));
- if (sent < 0) {
- zlog_warn("%s: sendto() failure to %s on %s: fd=%d msg_size=%d: errno=%d: %s",
- __PRETTY_FUNCTION__,
- dst_str, ifname, fd, pim_msg_size,
- errno, safe_strerror(errno));
- }
- else {
- zlog_warn("%s: sendto() partial to %s on %s: fd=%d msg_size=%d: sent=%zd",
- __PRETTY_FUNCTION__,
- dst_str, ifname, fd,
- pim_msg_size, sent);
- }
- return -1;
- }
-
+ pim_msg_send_frame (fd, (char *)buffer, sendlen,
+ (struct sockaddr *)&to, tolen);
return 0;
}