diff options
Diffstat (limited to 'zebra/kernel_socket.c')
| -rw-r--r-- | zebra/kernel_socket.c | 35 |
1 files changed, 31 insertions, 4 deletions
diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 3e46a79e96..84b06e579f 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -232,7 +232,9 @@ int dplane_routing_sock = -1; /* Yes I'm checking ugly routing socket behavior. */ /* #define DEBUG */ +size_t _rta_get(caddr_t sap, void *destp, size_t destlen, bool checkaf); size_t rta_get(caddr_t sap, void *dest, size_t destlen); +size_t rta_getattr(caddr_t sap, void *destp, size_t destlen); size_t rta_getsdlname(caddr_t sap, void *dest, short *destlen); /* Supported address family check. */ @@ -245,9 +247,10 @@ static inline int af_check(int family) return 0; } -size_t rta_get(caddr_t sap, void *destp, size_t destlen) +size_t _rta_get(caddr_t sap, void *destp, size_t destlen, bool checkaf) { struct sockaddr *sa = (struct sockaddr *)sap; + struct sockaddr_dl *sdl; uint8_t *dest = destp; size_t tlen, copylen; @@ -258,7 +261,21 @@ size_t rta_get(caddr_t sap, void *destp, size_t destlen) copylen = tlen = SAROUNDUP(sap); #endif /* !HAVE_STRUCT_SOCKADDR_SA_LEN */ - if (copylen > 0 && dest != NULL && af_check(sa->sa_family)) { + if (copylen > 0 && dest != NULL) { + if (checkaf && af_check(sa->sa_family) == 0) + return tlen; + /* + * Handle sockaddr_dl corner case: + * RTA_NETMASK might be AF_LINK, but it doesn't anything + * relevant (e.g. zeroed out fields). Check for this + * case and avoid warning log message. + */ + if (sa->sa_family == AF_LINK) { + sdl = (struct sockaddr_dl *)sa; + if (sdl->sdl_index == 0 || sdl->sdl_nlen == 0) + copylen = sizeof(*sdl) - sizeof(sdl->sdl_data); + } + if (copylen > destlen) { zlog_warn("%s: destination buffer too small (%lu vs %lu)", __func__, copylen, destlen); @@ -270,6 +287,16 @@ size_t rta_get(caddr_t sap, void *destp, size_t destlen) return tlen; } +size_t rta_get(caddr_t sap, void *destp, size_t destlen) +{ + return _rta_get(sap, destp, destlen, true); +} + +size_t rta_getattr(caddr_t sap, void *destp, size_t destlen) +{ + return _rta_get(sap, destp, destlen, false); +} + size_t rta_getsdlname(caddr_t sap, void *destp, short *destlen) { struct sockaddr_dl *sdl = (struct sockaddr_dl *)sap; @@ -684,7 +711,7 @@ static void ifam_read_mesg(struct ifa_msghdr *ifm, union sockunion *addr, pnt += rta_get(pnt, &gateway, sizeof(gateway)); break; case RTA_NETMASK: - pnt += rta_get(pnt, mask, sizeof(*mask)); + pnt += rta_getattr(pnt, mask, sizeof(*mask)); break; case RTA_IFP: pnt += rta_getsdlname(pnt, ifname, ifnlen); @@ -742,7 +769,7 @@ static void ifam_read_mesg(struct ifa_msghdr *ifm, union sockunion *addr, /* Assert read up end point matches to end point */ pnt = (caddr_t)ROUNDUP((size_t)pnt); - if (pnt != end) + if (pnt != (caddr_t)ROUNDUP((size_t)end)) zlog_debug("ifam_read() doesn't read all socket data"); } |
