diff options
author | Marc <foxtrot@malloc.me> | 2022-03-07 20:53:35 +0000 |
---|---|---|
committer | Marc <foxtrot@malloc.me> | 2022-03-07 20:53:41 +0000 |
commit | d3d1dd24e3941c03a6c6bf127764c768825fdbe2 (patch) | |
tree | 61aa614dfe391b4d1d8b904b11a302eb7fd11d1c /src | |
parent | 565611c2d15d304f7b03b163e03fec88c6b9a7cc (diff) | |
download | libwifi-d3d1dd24e3941c03a6c6bf127764c768825fdbe2.tar.gz libwifi-d3d1dd24e3941c03a6c6bf127764c768825fdbe2.tar.bz2 libwifi-d3d1dd24e3941c03a6c6bf127764c768825fdbe2.zip |
core: Avoid double frame copy in radiotap handling
Thanks @dragorn !
Diffstat (limited to 'src')
-rw-r--r-- | src/libwifi/core/frame/frame.c | 25 |
1 files changed, 7 insertions, 18 deletions
diff --git a/src/libwifi/core/frame/frame.c b/src/libwifi/core/frame/frame.c index 408808d..c8b6816 100644 --- a/src/libwifi/core/frame/frame.c +++ b/src/libwifi/core/frame/frame.c | |||
@@ -37,31 +37,23 @@ int libwifi_get_wifi_frame(struct libwifi_frame *fi, const unsigned char *frame, | |||
37 | union libwifi_frame_header fh = {0}; | 37 | union libwifi_frame_header fh = {0}; |
38 | size_t header_len = 0; | 38 | size_t header_len = 0; |
39 | size_t frame_data_len = frame_len; | 39 | size_t frame_data_len = frame_len; |
40 | unsigned char *frame_data = malloc(frame_data_len); | 40 | const unsigned char *frame_data = frame; |
41 | memcpy(frame_data, (unsigned char *) frame, frame_data_len); | ||
42 | 41 | ||
43 | if (radiotap) { | 42 | if (radiotap) { |
44 | struct libwifi_radiotap_info rtap_info = {0}; | 43 | struct libwifi_radiotap_info rtap_info = {0}; |
45 | int ret = libwifi_parse_radiotap_info(&rtap_info, frame_data, frame_len); | 44 | int ret = libwifi_parse_radiotap_info(&rtap_info, frame, frame_len); |
46 | if (ret != 0) { | 45 | if (ret != 0) { |
47 | return ret; | 46 | return ret; |
48 | } | 47 | } |
49 | 48 | ||
50 | // Skip forward by the length of the radiotap header | 49 | // Skip forward by the length of the radiotap header |
51 | frame_data_len -= rtap_info.length; | 50 | frame_data_len -= rtap_info.length; |
52 | unsigned char *new_data = malloc(frame_data_len); | 51 | frame_data += rtap_info.length; |
53 | memcpy(new_data, frame_data + rtap_info.length, frame_data_len); | ||
54 | free(frame_data); | ||
55 | frame_data = new_data; | ||
56 | 52 | ||
57 | // Remove the FCS from the end of the frame data, if present | 53 | // Remove the FCS from the end of the frame data, if present |
58 | if (rtap_info.flags & IEEE80211_RADIOTAP_F_FCS) { | 54 | if (rtap_info.flags & IEEE80211_RADIOTAP_F_FCS) { |
59 | fi->flags |= LIBWIFI_FLAGS_FCS_PRESENT; | 55 | fi->flags |= LIBWIFI_FLAGS_FCS_PRESENT; |
60 | frame_data_len -= sizeof(uint32_t); // FCS is 4 bytes wide | 56 | frame_data_len -= sizeof(uint32_t); // FCS is 4 bytes wide |
61 | frame_data = realloc(frame_data, frame_data_len); | ||
62 | if (frame_data == NULL) { | ||
63 | return -ENOMEM; | ||
64 | } | ||
65 | } | 57 | } |
66 | } | 58 | } |
67 | 59 | ||
@@ -88,7 +80,6 @@ int libwifi_get_wifi_frame(struct libwifi_frame *fi, const unsigned char *frame, | |||
88 | } | 80 | } |
89 | 81 | ||
90 | if (frame_data_len < header_len) { | 82 | if (frame_data_len < header_len) { |
91 | free(frame_data); | ||
92 | return -EINVAL; | 83 | return -EINVAL; |
93 | } | 84 | } |
94 | 85 | ||
@@ -105,14 +96,12 @@ int libwifi_get_wifi_frame(struct libwifi_frame *fi, const unsigned char *frame, | |||
105 | fi->flags |= LIBWIFI_FLAGS_IS_ORDERED; | 96 | fi->flags |= LIBWIFI_FLAGS_IS_ORDERED; |
106 | header_len = sizeof(struct libwifi_mgmt_ordered_frame_header); | 97 | header_len = sizeof(struct libwifi_mgmt_ordered_frame_header); |
107 | if (frame_data_len < header_len) { | 98 | if (frame_data_len < header_len) { |
108 | free(frame_data); | ||
109 | return -EINVAL; | 99 | return -EINVAL; |
110 | } | 100 | } |
111 | memcpy(&fh.mgmt_ordered, frame_data, header_len); | 101 | memcpy(&fh.mgmt_ordered, frame_data, header_len); |
112 | } else { | 102 | } else { |
113 | header_len = sizeof(struct libwifi_mgmt_unordered_frame_header); | 103 | header_len = sizeof(struct libwifi_mgmt_unordered_frame_header); |
114 | if (frame_data_len < header_len) { | 104 | if (frame_data_len < header_len) { |
115 | free(frame_data); | ||
116 | return -EINVAL; | 105 | return -EINVAL; |
117 | } | 106 | } |
118 | memcpy(&fh.mgmt_unordered, frame_data, header_len); | 107 | memcpy(&fh.mgmt_unordered, frame_data, header_len); |
@@ -121,13 +110,11 @@ int libwifi_get_wifi_frame(struct libwifi_frame *fi, const unsigned char *frame, | |||
121 | case TYPE_CONTROL: | 110 | case TYPE_CONTROL: |
122 | header_len = sizeof(struct libwifi_ctrl_frame_header); | 111 | header_len = sizeof(struct libwifi_ctrl_frame_header); |
123 | if (frame_data_len < header_len) { | 112 | if (frame_data_len < header_len) { |
124 | free(frame_data); | ||
125 | return -EINVAL; | 113 | return -EINVAL; |
126 | } | 114 | } |
127 | memcpy(&fh.ctrl, frame_data, sizeof(struct libwifi_ctrl_frame_header)); | 115 | memcpy(&fh.ctrl, frame_data, sizeof(struct libwifi_ctrl_frame_header)); |
128 | break; | 116 | break; |
129 | default: | 117 | default: |
130 | free(frame_data); | ||
131 | return -EINVAL; | 118 | return -EINVAL; |
132 | } | 119 | } |
133 | 120 | ||
@@ -137,9 +124,11 @@ int libwifi_get_wifi_frame(struct libwifi_frame *fi, const unsigned char *frame, | |||
137 | memcpy(&fi->frame_control, frame_control, sizeof(struct libwifi_frame_ctrl)); | 124 | memcpy(&fi->frame_control, frame_control, sizeof(struct libwifi_frame_ctrl)); |
138 | 125 | ||
139 | fi->body = malloc(fi->len - fi->header_len); | 126 | fi->body = malloc(fi->len - fi->header_len); |
140 | memcpy(fi->body, frame_data + header_len, (fi->len - fi->header_len)); | 127 | if (fi->body == NULL) { |
128 | return -ENOMEM; | ||
129 | } | ||
141 | 130 | ||
142 | free(frame_data); | 131 | memcpy(fi->body, frame_data + header_len, (fi->len - fi->header_len)); |
143 | 132 | ||
144 | return 0; | 133 | return 0; |
145 | } | 134 | } |