diff options
Diffstat (limited to 'networking/udhcp/options.c')
-rw-r--r-- | networking/udhcp/options.c | 96 |
1 files changed, 49 insertions, 47 deletions
diff --git a/networking/udhcp/options.c b/networking/udhcp/options.c index 581a7b671..143a1fd1c 100644 --- a/networking/udhcp/options.c +++ b/networking/udhcp/options.c | |||
@@ -119,58 +119,61 @@ const uint8_t dhcp_option_lengths[] ALIGN1 = { | |||
119 | }; | 119 | }; |
120 | 120 | ||
121 | 121 | ||
122 | /* get an option with bounds checking (warning, not aligned). */ | 122 | /* get an option with bounds checking (warning, result is not aligned). */ |
123 | uint8_t* FAST_FUNC get_option(struct dhcpMessage *packet, int code) | 123 | uint8_t* FAST_FUNC get_option(struct dhcpMessage *packet, int code) |
124 | { | 124 | { |
125 | int i, length; | ||
126 | uint8_t *optionptr; | 125 | uint8_t *optionptr; |
127 | int over = 0; | 126 | int len; |
128 | int curr = OPTION_FIELD; | 127 | int rem; |
129 | 128 | int overload = 0; | |
129 | enum { | ||
130 | FILE_FIELD101 = FILE_FIELD * 0x101, | ||
131 | SNAME_FIELD101 = SNAME_FIELD * 0x101, | ||
132 | }; | ||
133 | |||
134 | /* option bytes: [code][len][data1][data2]..[dataLEN] */ | ||
130 | optionptr = packet->options; | 135 | optionptr = packet->options; |
131 | i = 0; | 136 | rem = sizeof(packet->options); |
132 | length = sizeof(packet->options); | ||
133 | while (1) { | 137 | while (1) { |
134 | if (i >= length) { | 138 | if (rem <= 0) { |
135 | bb_error_msg("bogus packet, option fields too long"); | 139 | bb_error_msg("bogus packet, malformed option field"); |
136 | return NULL; | 140 | return NULL; |
137 | } | 141 | } |
138 | if (optionptr[i + OPT_CODE] == code) { | 142 | if (optionptr[OPT_CODE] == DHCP_PADDING) { |
139 | if (i + 1 + optionptr[i + OPT_LEN] >= length) { | 143 | rem--; |
140 | bb_error_msg("bogus packet, option fields too long"); | 144 | optionptr++; |
141 | return NULL; | 145 | continue; |
142 | } | ||
143 | return optionptr + i + 2; | ||
144 | } | 146 | } |
145 | switch (optionptr[i + OPT_CODE]) { | 147 | if (optionptr[OPT_CODE] == DHCP_END) { |
146 | case DHCP_PADDING: | 148 | if ((overload & FILE_FIELD101) == FILE_FIELD) { |
147 | i++; | 149 | /* can use packet->file, and didn't look at it yet */ |
148 | break; | 150 | overload |= FILE_FIELD101; /* "we looked at it" */ |
149 | case DHCP_OPTION_OVER: | ||
150 | if (i + 1 + optionptr[i + OPT_LEN] >= length) { | ||
151 | bb_error_msg("bogus packet, option fields too long"); | ||
152 | return NULL; | ||
153 | } | ||
154 | over = optionptr[i + 3]; | ||
155 | i += optionptr[OPT_LEN] + 2; | ||
156 | break; | ||
157 | case DHCP_END: | ||
158 | if (curr == OPTION_FIELD && (over & FILE_FIELD)) { | ||
159 | optionptr = packet->file; | 151 | optionptr = packet->file; |
160 | i = 0; | 152 | rem = sizeof(packet->file); |
161 | length = sizeof(packet->file); | 153 | continue; |
162 | curr = FILE_FIELD; | 154 | } |
163 | } else if (curr == FILE_FIELD && (over & SNAME_FIELD)) { | 155 | if ((overload & SNAME_FIELD101) == SNAME_FIELD) { |
156 | /* can use packet->sname, and didn't look at it yet */ | ||
157 | overload |= SNAME_FIELD101; /* "we looked at it" */ | ||
164 | optionptr = packet->sname; | 158 | optionptr = packet->sname; |
165 | i = 0; | 159 | rem = sizeof(packet->sname); |
166 | length = sizeof(packet->sname); | 160 | continue; |
167 | curr = SNAME_FIELD; | 161 | } |
168 | } else | 162 | return NULL; |
169 | return NULL; | 163 | } |
170 | break; | 164 | len = 2 + optionptr[OPT_LEN]; |
171 | default: | 165 | rem -= len; |
172 | i += optionptr[OPT_LEN + i] + 2; | 166 | if (rem < 0) |
167 | continue; /* complain and return NULL */ | ||
168 | |||
169 | if (optionptr[OPT_CODE] == code) | ||
170 | return optionptr + OPT_DATA; | ||
171 | |||
172 | if (optionptr[OPT_CODE] == DHCP_OPTION_OVERLOAD) { | ||
173 | overload |= optionptr[OPT_DATA]; | ||
174 | /* fall through */ | ||
173 | } | 175 | } |
176 | optionptr += len; | ||
174 | } | 177 | } |
175 | return NULL; | 178 | return NULL; |
176 | } | 179 | } |
@@ -182,17 +185,16 @@ int FAST_FUNC end_option(uint8_t *optionptr) | |||
182 | int i = 0; | 185 | int i = 0; |
183 | 186 | ||
184 | while (optionptr[i] != DHCP_END) { | 187 | while (optionptr[i] != DHCP_END) { |
185 | if (optionptr[i] == DHCP_PADDING) | 188 | if (optionptr[i] != DHCP_PADDING) |
186 | i++; | 189 | i += optionptr[i + OPT_LEN] + 1; |
187 | else | 190 | i++; |
188 | i += optionptr[i + OPT_LEN] + 2; | ||
189 | } | 191 | } |
190 | return i; | 192 | return i; |
191 | } | 193 | } |
192 | 194 | ||
193 | 195 | ||
194 | /* add an option string to the options (an option string contains an option code, | 196 | /* add an option string to the options */ |
195 | * length, then data) */ | 197 | /* option bytes: [code][len][data1][data2]..[dataLEN] */ |
196 | int FAST_FUNC add_option_string(uint8_t *optionptr, uint8_t *string) | 198 | int FAST_FUNC add_option_string(uint8_t *optionptr, uint8_t *string) |
197 | { | 199 | { |
198 | int end = end_option(optionptr); | 200 | int end = end_option(optionptr); |