summaryrefslogtreecommitdiff
path: root/zebra/kernel_socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/kernel_socket.c')
-rw-r--r--zebra/kernel_socket.c37
1 files changed, 33 insertions, 4 deletions
diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c
index 4f89d53e39..84b06e579f 100644
--- a/zebra/kernel_socket.c
+++ b/zebra/kernel_socket.c
@@ -139,7 +139,9 @@ const struct message rtm_type_str[] = {{RTM_ADD, "RTM_ADD"},
{RTM_LOSING, "RTM_LOSING"},
{RTM_REDIRECT, "RTM_REDIRECT"},
{RTM_MISS, "RTM_MISS"},
+#ifdef RTM_LOCK
{RTM_LOCK, "RTM_LOCK"},
+#endif /* RTM_LOCK */
#ifdef OLDADD
{RTM_OLDADD, "RTM_OLDADD"},
#endif /* RTM_OLDADD */
@@ -230,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. */
@@ -243,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;
@@ -256,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);
@@ -268,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;
@@ -682,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);
@@ -740,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");
}