bsd: Fix receive buffer alignment issue
authorYi Zhu <Yi.Zhu@Atheros.com>
Thu, 9 Dec 2010 19:30:20 +0000 (11:30 -0800)
committerJouni Malinen <j@w1.fi>
Thu, 30 Dec 2010 14:13:19 +0000 (16:13 +0200)
wpa_supplicant seems to crash from time to time on a NetBSD 4.0 MIPS
platform. The root cause turned out to be a MIPS alignment issue.

In my wpa_supplicant crash case, in function
wpa_driver_bsd_event_receive (from driver_bsd.c), the buf[2048] address
is started from i.e. 0x7fffd546, which is not 4 bytes aligned. Later
when it is casted to (struct if_msghdr *), and rtm->rtm_flags is used.
rtm->rtm_flags is "int" type, but its address is not 4 bytes aligned.
This is because the start address of rtm is not 4 bytes aligned.
Unfortunately in NetBSD MIPS kernel (unlike Linux MIPS kernel emulates
unaligned access in its exception handler), the default behavior is to
generate a memory fault to the application that accesses unaligned
memory address. Thus comes the early mentioned wpa_supplicant crash. An
interesting note is when I'm using the wpa_supplicant version 0.4.9, I
never saw this problem. Maybe the stack layout is different. But I
didn't look into details.

I used below patch to resolve this problem. Now it runs correctly for at
least several hours. But you might have a better fix (maybe we can use
malloc/free so that it is at least cache line aligned?). I'm also not
sure if other drivers should have the same problem.

src/drivers/driver_bsd.c

index 837a318..6067dc3 100644 (file)
@@ -693,7 +693,7 @@ static void
 bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
 {
        struct bsd_driver_data *drv = ctx;
-       char buf[2048];
+       char buf[2048] __attribute__ ((aligned (4)));
        struct if_announcemsghdr *ifan;
        struct rt_msghdr *rtm;
        struct ieee80211_michael_event *mic;
@@ -1117,7 +1117,7 @@ static void
 wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
 {
        struct bsd_driver_data *drv = sock_ctx;
-       char buf[2048];
+       char buf[2048] __attribute__ ((aligned (4)));
        struct if_announcemsghdr *ifan;
        struct if_msghdr *ifm;
        struct rt_msghdr *rtm;