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>
This commit is contained in:
Quentin Young 2018-12-07 23:36:09 +00:00
parent ef4cc1ebff
commit 3eca38577a
2 changed files with 75 additions and 29 deletions

View File

@ -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);
size_t pktsize = sizeof(struct vrrp_hdr) + addrsz * numip;
*pkt = XCALLOC(MTYPE_TMP, pktsize);
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;
v6ptr = (struct in6_addr *) (*pkt)->addrs;
v4ptr = (struct in_addr *) (*pkt)->addrs;
return pkt;
(*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;
}

View File

@ -30,8 +30,12 @@
* Shared header for VRRPv2/v3 packets.
*/
struct vrrp_hdr {
uint8_t version : 4;
uint8_t type : 4;
/*
* H L H L
* 0000 0000
* ver type
*/
uint8_t vertype;
uint8_t vrid;
uint8_t priority;
uint8_t naddr;
@ -42,9 +46,13 @@ struct vrrp_hdr {
uint8_t adver_int;
} v2;
struct {
/* advertisement interval (in centiseconds) */
uint16_t rsvd : 4;
uint16_t adver_int : 12;
/*
* advertisement interval (in centiseconds)
* H L H L
* 0000 000000000000
* rsvd adver_int
*/
uint16_t adver_int;
} v3;
};
uint16_t chksum;
@ -60,7 +68,29 @@ struct vrrp_pkt {
/*
* Builds a VRRP packet.
*
* pkt
* Pointer to store pointer to result buffer in
*
* vrid
* Virtual Router Identifier
*
* prio
* Virtual Router Priority
*
* max_adver_int
* time between ADVERTISEMENTs
*
* v6
* whether 'ips' is an array of v4 or v6 addresses
*
* numip
* number of IPvX addresses in 'ips'
*
* ips
* array of pointer to either struct in_addr (v6 = false) or struct in6_addr
* (v6 = true)
*/
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);