From 38d6a0f22a5790ef6e46752eee5f70163bae8d7f Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 26 Jan 2015 16:41:41 +0000 Subject: [PATCH] Add endian-specific word load/store functions ... and remove a subset of them, less optimally implemented, from ntlm.c Signed-off-by: David Woodhouse --- configure.ac | 7 +++ ntlm.c | 26 ---------- openconnect-internal.h | 107 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+), 26 deletions(-) diff --git a/configure.ac b/configure.ac index 81a848bd..d3be5809 100644 --- a/configure.ac +++ b/configure.ac @@ -884,6 +884,13 @@ AC_CHECK_HEADER([if_tun.h], AC_CHECK_HEADER([net/if_utun.h], AC_DEFINE([HAVE_NET_UTUN_H], 1, [Have net/utun.h])) AC_CHECK_HEADER([alloca.h], AC_DEFINE([HAVE_ALLOCA_H], 1, [Have alloca.h])) +AC_CHECK_HEADER([endian.h], + [AC_DEFINE([ENDIAN_HDR], [], [endian header include path])], + [AC_CHECK_HEADER([sys/endian.h], + [AC_DEFINE([ENDIAN_HDR], [])], + [AC_CHECK_HEADER([sys/isa_defs.h], + [AC_DEFINE([ENDIAN_HDR], [])])])]) + if test "$ssl_library" = "openssl" || test "$ssl_library" = "both"; then oldLIBS="$LIBS" LIBS="$LIBS $OPENSSL_LIBS" diff --git a/ntlm.c b/ntlm.c index 098f8168..0472f27f 100644 --- a/ntlm.c +++ b/ntlm.c @@ -826,32 +826,6 @@ static void ntlm_calc_response (const unsigned char key[21], des (ks, results + 16); } -static inline uint32_t load_le32(void *_p) -{ - unsigned char *p = _p; - return (p[3] << 24) | (p[2] << 16) | p[1] << 8 | p[0]; -} -static inline uint16_t load_le16(void *_p) -{ - unsigned char *p = _p; - return p[1] << 8 | p[0]; -} - -static inline void store_le32(void *_p, uint32_t v) -{ - unsigned char *p = _p; - p[0] = v; - p[1] = v >> 8; - p[2] = v >> 16; - p[3] = v >> 24; -} -static inline void store_le16(void *_p, uint16_t v) -{ - unsigned char *p = _p; - p[0] = v; - p[1] = v >> 8; -} - #define NTLM_CHALLENGE_DOMAIN_OFFSET 12 #define NTLM_CHALLENGE_FLAGS_OFFSET 20 #define NTLM_CHALLENGE_NONCE_OFFSET 24 diff --git a/openconnect-internal.h b/openconnect-internal.h index 65623a4c..567c8b44 100644 --- a/openconnect-internal.h +++ b/openconnect-internal.h @@ -939,4 +939,111 @@ extern const char *openconnect_version_str; return; \ } +/* Let's stop open-coding big-endian and little-endian loads/stores. + * + * Start with a packed structure so that we can let the compiler + * decide whether the target CPU can cope with unaligned load/stores + * or not. Then there are three cases to handle: + * - For big-endian loads/stores, just use htons() et al. + * - For little-endian when we *know* the CPU is LE, just load/store + * - For little-endian otherwise, do the data acess byte-wise + */ +struct oc_packed_uint32_t { + uint32_t d; +} __attribute__((packed)); +struct oc_packed_uint16_t { + uint16_t d; +} __attribute__((packed)); + +static inline uint32_t load_be32(const void *_p) +{ + const struct oc_packed_uint32_t *p = _p; + return ntohl(p->d); +} + +static inline uint16_t load_be16(const void *_p) +{ + const struct oc_packed_uint16_t *p = _p; + return ntohs(p->d); +} + +static inline void store_be32(void *_p, uint32_t d) +{ + struct oc_packed_uint32_t *p = _p; + p->d = htonl(d); +} + +static inline void store_be16(void *_p, uint16_t d) +{ + struct oc_packed_uint16_t *p = _p; + p->d = htons(d); +} + +/* It doesn't matter if we don't find one. It'll default to the + * "not known to be little-endian" case, and do the bytewise + * load/store. Modern compilers might even spot the pattern and + * optimise it (see GCC PR#55177 around comment 15). */ +#ifdef ENDIAN_HDR +#include ENDIAN_HDR +#endif + +#if defined(_WIN32) || \ + (defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)) /* Solaris */ || \ + (defined(__LITTLE_ENDIAN) && defined(__BIG_ENDIAN) && defined(__BYTE_ORDER) \ + && __BYTE_ORDER == __LITTLE_ENDIAN) /* Linux */ || \ + (defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN) && defined(BYTE_ORDER) \ + && BYTE_ORDER == LITTLE_ENDIAN) /* *BSD */ +static inline uint32_t load_le32(const void *_p) +{ + const struct oc_packed_uint32_t *p = _p; + return p->d; +} + +static inline uint16_t load_le16(const void *_p) +{ + const struct oc_packed_uint16_t *p = _p; + return p->d; +} + +static inline void store_le32(void *_p, uint32_t d) +{ + struct oc_packed_uint32_t *p = _p; + p->d = d; +} + +static inline void store_le16(void *_p, uint16_t d) +{ + struct oc_packed_uint16_t *p = _p; + p->d = d; +} +#else +static inline uint32_t load_le32(const void *_p) +{ + const unsigned char *p = _p; + return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); +} + +static inline uint16_t load_le16(const void *_p) +{ + const unsigned char *p = _p; + return p[0] | (p[1] << 8); +} + +static inline void store_le32(void *_p, uint32_t d) +{ + unsigned char *p = _p; + p[0] = d; + p[1] = d >> 8; +} + +static inline void store_le16(void *_p, uint16_t d) +{ + unsigned char *p = _p; + p[0] = d; + p[1] = d >> 8; + p[2] = d >> 16; + p[3] = d >> 24; +} +#endif /* !Not known to be little-endian */ + #endif /* __OPENCONNECT_INTERNAL_H__ */