diff options
| author | Quentin Young <qlyoung@cumulusnetworks.com> | 2018-12-07 23:36:09 +0000 | 
|---|---|---|
| committer | Quentin Young <qlyoung@cumulusnetworks.com> | 2019-05-17 00:27:08 +0000 | 
| commit | 3eca38577afdd262e72740f16e0b1a6057d0aed6 (patch) | |
| tree | a491a53717d07415459b53deb603b046ef66176b /vrrpd/vrrp_packet.c | |
| parent | ef4cc1ebfffaf74c303fd1b5c96d739f08766751 (diff) | |
vrrpd: fix packet encode
* Properly encode VRRP packets
* Calculate checksum appropriately
* Update signature to provide caller both packet and result length
Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
Diffstat (limited to 'vrrpd/vrrp_packet.c')
| -rw-r--r-- | vrrpd/vrrp_packet.c | 62 | 
1 files changed, 39 insertions, 23 deletions
diff --git a/vrrpd/vrrp_packet.c b/vrrpd/vrrp_packet.c index a5eb40fda8..608be06a0c 100644 --- a/vrrpd/vrrp_packet.c +++ b/vrrpd/vrrp_packet.c @@ -19,32 +19,48 @@   */  #include <zebra.h> -#include "memory.h" -#include "ipaddr.h" +#include "lib/memory.h" +#include "lib/ipaddr.h" +#include "lib/checksum.h"  #include "vrrp_packet.h" -/* - * Builds a VRRP packet. - */ -struct vrrp_pkt *vrrp_pkt_build(uint8_t vrid, uint8_t prio, -				uint16_t max_adver_int, bool v6, uint8_t numip, -				void **ips) +ssize_t vrrp_pkt_build(struct vrrp_pkt **pkt, uint8_t vrid, uint8_t prio, +		       uint16_t max_adver_int, bool v6, uint8_t numip, +		       void **ips)  { +	/* Used for pointer math when filling IPvX field */ +	struct in6_addr *v6ptr; +	struct in_addr *v4ptr; +  	size_t addrsz = v6 ? sizeof(struct in6_addr) : sizeof(struct in_addr); -	struct vrrp_pkt *pkt = -		XCALLOC(MTYPE_TMP, sizeof(struct vrrp_pkt) + addrsz * numip); - -	pkt->hdr.version = VRRP_VERSION; -	pkt->hdr.type = VRRP_TYPE_ADVERTISEMENT; -	pkt->hdr.vrid = vrid; -	pkt->hdr.priority = prio; -	pkt->hdr.v3.rsvd = 0; -	pkt->hdr.v3.adver_int = max_adver_int; -	for (uint8_t i = 0; i < numip; i++) -		memcpy(&pkt->addrs[i].v4, ips[i], addrsz); -	/* FIXME */ -	pkt->hdr.chksum = 0; - -	return pkt; +	size_t pktsize = sizeof(struct vrrp_hdr) + addrsz * numip; +	*pkt = XCALLOC(MTYPE_TMP, pktsize); + +	v6ptr = (struct in6_addr *) (*pkt)->addrs; +	v4ptr = (struct in_addr *) (*pkt)->addrs; + +	(*pkt)->hdr.vertype |= VRRP_VERSION << 4; +	(*pkt)->hdr.vertype |= VRRP_TYPE_ADVERTISEMENT; +	(*pkt)->hdr.vrid = vrid; +	(*pkt)->hdr.priority = prio; +	(*pkt)->hdr.naddr = numip; +	(*pkt)->hdr.v3.adver_int = htons(max_adver_int); + +	char buf[INET_ADDRSTRLEN]; +	for (int i = 0; i < numip; i++) { +		/* If v4, treat as array of v4 addresses */ +		inet_ntop(AF_INET, ips[i], buf, sizeof(buf)); +		if (!v6) +			memcpy(&v4ptr[i], ips[i], addrsz); +		else +			memcpy(&v6ptr[i], ips[i], addrsz); +		inet_ntop(AF_INET, &v4ptr[i], buf, sizeof(buf)); +	} +	(*pkt)->hdr.chksum = 0; + +	uint16_t chksum = in_cksum(*pkt, pktsize); +	(*pkt)->hdr.chksum = htons(chksum); + +	return pktsize;  }  | 
