diff --git a/include/zephyr/toolchain/gcc.h b/include/zephyr/toolchain/gcc.h index 4d3d85858d3d4..de2713f5ad425 100644 --- a/include/zephyr/toolchain/gcc.h +++ b/include/zephyr/toolchain/gcc.h @@ -174,6 +174,16 @@ do { \ #endif +/* + * Get the address of a structure member even if the member may not be properly + * aligned. Note that accessing such an address must be done with care (for + * example with UNALIGNED_GET/PUT) and cannot be in general de-referenced to + * access the member directly, as that would cause a fault in architectures + * which have alignment requirements. + */ +#define UNALIGNED_MEMBER_ADDR(_p, _member) ((__typeof__(_p->_member) *) \ + (((intptr_t)(_p)) + offsetof(__typeof__(*_p), _member))) + /* Double indirection to ensure section names are expanded before * stringification */ diff --git a/subsys/net/ip/igmp.c b/subsys/net/ip/igmp.c index de91ffb5af501..c8f93ff097500 100644 --- a/subsys/net/ip/igmp.c +++ b/subsys/net/ip/igmp.c @@ -68,7 +68,7 @@ static int igmp_v2_create(struct net_pkt *pkt, const struct in_addr *addr, igmp->type = type; igmp->max_rsp = 0U; - net_ipaddr_copy(&igmp->address, addr); + net_ipaddr_copy(UNALIGNED_MEMBER_ADDR(igmp, address), addr); igmp->chksum = 0; if (net_pkt_set_data(pkt, &igmp_access)) { diff --git a/subsys/net/ip/tcp.c b/subsys/net/ip/tcp.c index a4164997f63ef..48f9d21ac3d07 100644 --- a/subsys/net/ip/tcp.c +++ b/subsys/net/ip/tcp.c @@ -1262,8 +1262,8 @@ static int tcp_header_add(struct tcp *conn, struct net_pkt *pkt, uint8_t flags, memset(th, 0, sizeof(struct tcphdr)); - UNALIGNED_PUT(conn->src.sin.sin_port, &th->th_sport); - UNALIGNED_PUT(conn->dst.sin.sin_port, &th->th_dport); + UNALIGNED_PUT(conn->src.sin.sin_port, UNALIGNED_MEMBER_ADDR(th, th_sport)); + UNALIGNED_PUT(conn->dst.sin.sin_port, UNALIGNED_MEMBER_ADDR(th, th_dport)); th->th_off = 5; if (conn->send_options.mss_found) { @@ -1271,11 +1271,11 @@ static int tcp_header_add(struct tcp *conn, struct net_pkt *pkt, uint8_t flags, } UNALIGNED_PUT(flags, &th->th_flags); - UNALIGNED_PUT(htons(conn->recv_win), &th->th_win); - UNALIGNED_PUT(htonl(seq), &th->th_seq); + UNALIGNED_PUT(htons(conn->recv_win), UNALIGNED_MEMBER_ADDR(th, th_win)); + UNALIGNED_PUT(htonl(seq), UNALIGNED_MEMBER_ADDR(th, th_seq)); if (ACK & flags) { - UNALIGNED_PUT(htonl(conn->ack), &th->th_ack); + UNALIGNED_PUT(htonl(conn->ack), UNALIGNED_MEMBER_ADDR(th, th_ack)); } return net_pkt_set_data(pkt, &tcp_access); @@ -1415,13 +1415,13 @@ void net_tcp_reply_rst(struct net_pkt *pkt) memset(th_rst, 0, sizeof(struct tcphdr)); - UNALIGNED_PUT(th_pkt->th_dport, &th_rst->th_sport); - UNALIGNED_PUT(th_pkt->th_sport, &th_rst->th_dport); + UNALIGNED_PUT(th_pkt->th_dport, UNALIGNED_MEMBER_ADDR(th_rst, th_sport)); + UNALIGNED_PUT(th_pkt->th_sport, UNALIGNED_MEMBER_ADDR(th_rst, th_dport)); th_rst->th_off = 5; if (th_flags(th_pkt) & ACK) { UNALIGNED_PUT(RST, &th_rst->th_flags); - UNALIGNED_PUT(th_pkt->th_ack, &th_rst->th_seq); + UNALIGNED_PUT(th_pkt->th_ack, UNALIGNED_MEMBER_ADDR(th_rst, th_seq)); } else { uint32_t ack = ntohl(th_pkt->th_seq) + tcp_data_len(pkt); @@ -1430,7 +1430,7 @@ void net_tcp_reply_rst(struct net_pkt *pkt) } UNALIGNED_PUT(RST | ACK, &th_rst->th_flags); - UNALIGNED_PUT(htonl(ack), &th_rst->th_ack); + UNALIGNED_PUT(htonl(ack), UNALIGNED_MEMBER_ADDR(th_rst, th_ack)); } ret = net_pkt_set_data(rst, &tcp_access_rst); diff --git a/subsys/net/ip/tcp_private.h b/subsys/net/ip/tcp_private.h index f49f6073fbd6f..6c4d44bcf04ba 100644 --- a/subsys/net/ip/tcp_private.h +++ b/subsys/net/ip/tcp_private.h @@ -6,6 +6,7 @@ */ #include "tp.h" +#include #define is(_a, _b) (strcmp((_a), (_b)) == 0) @@ -13,13 +14,14 @@ #define MIN3(_a, _b, _c) MIN((_a), MIN((_b), (_c))) #endif -#define th_sport(_x) UNALIGNED_GET(&(_x)->th_sport) -#define th_dport(_x) UNALIGNED_GET(&(_x)->th_dport) -#define th_seq(_x) ntohl(UNALIGNED_GET(&(_x)->th_seq)) -#define th_ack(_x) ntohl(UNALIGNED_GET(&(_x)->th_ack)) +#define th_sport(_x) UNALIGNED_GET(UNALIGNED_MEMBER_ADDR((_x), th_sport)) +#define th_dport(_x) UNALIGNED_GET(UNALIGNED_MEMBER_ADDR((_x), th_dport)) +#define th_seq(_x) ntohl(UNALIGNED_GET(UNALIGNED_MEMBER_ADDR((_x), th_seq))) +#define th_ack(_x) ntohl(UNALIGNED_GET(UNALIGNED_MEMBER_ADDR((_x), th_ack))) + #define th_off(_x) ((_x)->th_off) -#define th_flags(_x) UNALIGNED_GET(&(_x)->th_flags) -#define th_win(_x) UNALIGNED_GET(&(_x)->th_win) +#define th_flags(_x) UNALIGNED_GET(UNALIGNED_MEMBER_ADDR((_x), th_flags)) +#define th_win(_x) UNALIGNED_GET(UNALIGNED_MEMBER_ADDR((_x), th_win)) #define tcp_slist(_conn, _slist, _op, _type, _link) \ ({ \ diff --git a/subsys/net/l2/ieee802154/ieee802154.c b/subsys/net/l2/ieee802154/ieee802154.c index 4302f1f09fa11..f06cdde8630be 100644 --- a/subsys/net/l2/ieee802154/ieee802154.c +++ b/subsys/net/l2/ieee802154/ieee802154.c @@ -16,6 +16,7 @@ LOG_MODULE_REGISTER(net_ieee802154, CONFIG_NET_L2_IEEE802154_LOG_LEVEL); #include +#include #include #include #include @@ -264,7 +265,8 @@ static inline void swap_and_set_pkt_ll_addr(struct net_linkaddr *addr, bool has_ (void)net_linkaddr_create( addr, (const uint8_t *)(has_pan_id ? - &ll->plain.addr.short_addr : &ll->comp.addr.short_addr), + UNALIGNED_MEMBER_ADDR(ll, plain.addr.short_addr) : + UNALIGNED_MEMBER_ADDR(ll, comp.addr.short_addr)), IEEE802154_SHORT_ADDR_LENGTH, NET_LINK_IEEE802154); break; diff --git a/subsys/net/lib/dhcpv6/dhcpv6.c b/subsys/net/lib/dhcpv6/dhcpv6.c index 88770bac66d9e..d87d1ca0e4ad5 100644 --- a/subsys/net/lib/dhcpv6/dhcpv6.c +++ b/subsys/net/lib/dhcpv6/dhcpv6.c @@ -2250,8 +2250,10 @@ static void dhcpv6_generate_client_duid(struct net_if *iface) memset(clientid, 0, sizeof(*clientid)); - UNALIGNED_PUT(htons(DHCPV6_DUID_TYPE_LL), &clientid->duid.type); - UNALIGNED_PUT(htons(DHCPV6_HARDWARE_ETHERNET_TYPE), &duid_ll->hw_type); + UNALIGNED_PUT(htons(DHCPV6_DUID_TYPE_LL), + UNALIGNED_MEMBER_ADDR(clientid, duid.type)); + UNALIGNED_PUT(htons(DHCPV6_HARDWARE_ETHERNET_TYPE), + UNALIGNED_MEMBER_ADDR(duid_ll, hw_type)); memcpy(duid_ll->ll_addr, lladdr->addr, lladdr->len); clientid->length = DHCPV6_DUID_LL_HEADER_SIZE + lladdr->len; diff --git a/subsys/net/lib/http/http_server_http2.c b/subsys/net/lib/http/http_server_http2.c index fad55b6265e39..ef311f1786577 100644 --- a/subsys/net/lib/http/http_server_http2.c +++ b/subsys/net/lib/http/http_server_http2.c @@ -261,14 +261,14 @@ int send_settings_frame(struct http_client_ctx *client, bool ack) setting = (struct http2_settings_field *) (settings_frame + HTTP2_FRAME_HEADER_SIZE); UNALIGNED_PUT(htons(HTTP2_SETTINGS_HEADER_TABLE_SIZE), - &setting->id); - UNALIGNED_PUT(0, &setting->value); + UNALIGNED_MEMBER_ADDR(setting, id)); + UNALIGNED_PUT(0, UNALIGNED_MEMBER_ADDR(setting, value)); setting++; UNALIGNED_PUT(htons(HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS), - &setting->id); + UNALIGNED_MEMBER_ADDR(setting, id)); UNALIGNED_PUT(htonl(CONFIG_HTTP_SERVER_MAX_STREAMS), - &setting->value); + UNALIGNED_MEMBER_ADDR(setting, value)); len = HTTP2_FRAME_HEADER_SIZE + 2 * sizeof(struct http2_settings_field); diff --git a/tests/net/dhcpv6/src/main.c b/tests/net/dhcpv6/src/main.c index b1375383c6783..a7c396cc07888 100644 --- a/tests/net/dhcpv6/src/main.c +++ b/tests/net/dhcpv6/src/main.c @@ -109,8 +109,10 @@ static void generate_fake_server_duid(void) memset(serverid, 0, sizeof(*serverid)); - UNALIGNED_PUT(htons(DHCPV6_DUID_TYPE_LL), &serverid->duid.type); - UNALIGNED_PUT(htons(DHCPV6_HARDWARE_ETHERNET_TYPE), &duid_ll->hw_type); + UNALIGNED_PUT(htons(DHCPV6_DUID_TYPE_LL), + UNALIGNED_MEMBER_ADDR(serverid, duid.type)); + UNALIGNED_PUT(htons(DHCPV6_HARDWARE_ETHERNET_TYPE), + UNALIGNED_MEMBER_ADDR(duid_ll, hw_type)); memcpy(duid_ll->ll_addr, fake_mac, sizeof(fake_mac)); serverid->length = DHCPV6_DUID_LL_HEADER_SIZE + sizeof(fake_mac);