diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/batman-adv/icmp_socket.c | 128 | ||||
-rw-r--r-- | net/batman-adv/icmp_socket.h | 2 | ||||
-rw-r--r-- | net/batman-adv/packet.h | 2 | ||||
-rw-r--r-- | net/batman-adv/routing.c | 120 | ||||
-rw-r--r-- | net/batman-adv/types.h | 2 |
5 files changed, 157 insertions, 97 deletions
diff --git a/net/batman-adv/icmp_socket.c b/net/batman-adv/icmp_socket.c index 82ac6472fa6f..29ae4efe3543 100644 --- a/net/batman-adv/icmp_socket.c +++ b/net/batman-adv/icmp_socket.c | |||
@@ -29,7 +29,7 @@ | |||
29 | static struct batadv_socket_client *batadv_socket_client_hash[256]; | 29 | static struct batadv_socket_client *batadv_socket_client_hash[256]; |
30 | 30 | ||
31 | static void batadv_socket_add_packet(struct batadv_socket_client *socket_client, | 31 | static void batadv_socket_add_packet(struct batadv_socket_client *socket_client, |
32 | struct batadv_icmp_packet_rr *icmp_packet, | 32 | struct batadv_icmp_header *icmph, |
33 | size_t icmp_len); | 33 | size_t icmp_len); |
34 | 34 | ||
35 | void batadv_socket_init(void) | 35 | void batadv_socket_init(void) |
@@ -155,13 +155,13 @@ static ssize_t batadv_socket_write(struct file *file, const char __user *buff, | |||
155 | struct batadv_priv *bat_priv = socket_client->bat_priv; | 155 | struct batadv_priv *bat_priv = socket_client->bat_priv; |
156 | struct batadv_hard_iface *primary_if = NULL; | 156 | struct batadv_hard_iface *primary_if = NULL; |
157 | struct sk_buff *skb; | 157 | struct sk_buff *skb; |
158 | struct batadv_icmp_packet_rr *icmp_packet; | 158 | struct batadv_icmp_packet_rr *icmp_packet_rr; |
159 | 159 | struct batadv_icmp_header *icmp_header; | |
160 | struct batadv_orig_node *orig_node = NULL; | 160 | struct batadv_orig_node *orig_node = NULL; |
161 | struct batadv_neigh_node *neigh_node = NULL; | 161 | struct batadv_neigh_node *neigh_node = NULL; |
162 | size_t packet_len = sizeof(struct batadv_icmp_packet); | 162 | size_t packet_len = sizeof(struct batadv_icmp_packet); |
163 | 163 | ||
164 | if (len < sizeof(struct batadv_icmp_packet)) { | 164 | if (len < sizeof(struct batadv_icmp_header)) { |
165 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | 165 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, |
166 | "Error - can't send packet from char device: invalid packet size\n"); | 166 | "Error - can't send packet from char device: invalid packet size\n"); |
167 | return -EINVAL; | 167 | return -EINVAL; |
@@ -174,8 +174,10 @@ static ssize_t batadv_socket_write(struct file *file, const char __user *buff, | |||
174 | goto out; | 174 | goto out; |
175 | } | 175 | } |
176 | 176 | ||
177 | if (len >= sizeof(struct batadv_icmp_packet_rr)) | 177 | if (len >= BATADV_ICMP_MAX_PACKET_SIZE) |
178 | packet_len = sizeof(struct batadv_icmp_packet_rr); | 178 | packet_len = BATADV_ICMP_MAX_PACKET_SIZE; |
179 | else | ||
180 | packet_len = len; | ||
179 | 181 | ||
180 | skb = netdev_alloc_skb_ip_align(NULL, packet_len + ETH_HLEN); | 182 | skb = netdev_alloc_skb_ip_align(NULL, packet_len + ETH_HLEN); |
181 | if (!skb) { | 183 | if (!skb) { |
@@ -185,67 +187,78 @@ static ssize_t batadv_socket_write(struct file *file, const char __user *buff, | |||
185 | 187 | ||
186 | skb->priority = TC_PRIO_CONTROL; | 188 | skb->priority = TC_PRIO_CONTROL; |
187 | skb_reserve(skb, ETH_HLEN); | 189 | skb_reserve(skb, ETH_HLEN); |
188 | icmp_packet = (struct batadv_icmp_packet_rr *)skb_put(skb, packet_len); | 190 | icmp_header = (struct batadv_icmp_header *)skb_put(skb, packet_len); |
189 | 191 | ||
190 | if (copy_from_user(icmp_packet, buff, packet_len)) { | 192 | if (copy_from_user(icmp_header, buff, packet_len)) { |
191 | len = -EFAULT; | 193 | len = -EFAULT; |
192 | goto free_skb; | 194 | goto free_skb; |
193 | } | 195 | } |
194 | 196 | ||
195 | if (icmp_packet->icmph.header.packet_type != BATADV_ICMP) { | 197 | if (icmp_header->header.packet_type != BATADV_ICMP) { |
196 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | 198 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, |
197 | "Error - can't send packet from char device: got bogus packet type (expected: BAT_ICMP)\n"); | 199 | "Error - can't send packet from char device: got bogus packet type (expected: BAT_ICMP)\n"); |
198 | len = -EINVAL; | 200 | len = -EINVAL; |
199 | goto free_skb; | 201 | goto free_skb; |
200 | } | 202 | } |
201 | 203 | ||
202 | if (icmp_packet->icmph.msg_type != BATADV_ECHO_REQUEST) { | 204 | switch (icmp_header->msg_type) { |
205 | case BATADV_ECHO_REQUEST: | ||
206 | if (len < sizeof(struct batadv_icmp_packet)) { | ||
207 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | ||
208 | "Error - can't send packet from char device: invalid packet size\n"); | ||
209 | len = -EINVAL; | ||
210 | goto free_skb; | ||
211 | } | ||
212 | |||
213 | if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) | ||
214 | goto dst_unreach; | ||
215 | |||
216 | orig_node = batadv_orig_hash_find(bat_priv, icmp_header->dst); | ||
217 | if (!orig_node) | ||
218 | goto dst_unreach; | ||
219 | |||
220 | neigh_node = batadv_orig_node_get_router(orig_node); | ||
221 | if (!neigh_node) | ||
222 | goto dst_unreach; | ||
223 | |||
224 | if (!neigh_node->if_incoming) | ||
225 | goto dst_unreach; | ||
226 | |||
227 | if (neigh_node->if_incoming->if_status != BATADV_IF_ACTIVE) | ||
228 | goto dst_unreach; | ||
229 | |||
230 | icmp_packet_rr = (struct batadv_icmp_packet_rr *)icmp_header; | ||
231 | if (packet_len == sizeof(*icmp_packet_rr)) | ||
232 | memcpy(icmp_packet_rr->rr, | ||
233 | neigh_node->if_incoming->net_dev->dev_addr, | ||
234 | ETH_ALEN); | ||
235 | |||
236 | break; | ||
237 | default: | ||
203 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | 238 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, |
204 | "Error - can't send packet from char device: got bogus message type (expected: ECHO_REQUEST)\n"); | 239 | "Error - can't send packet from char device: got unknown message type\n"); |
205 | len = -EINVAL; | 240 | len = -EINVAL; |
206 | goto free_skb; | 241 | goto free_skb; |
207 | } | 242 | } |
208 | 243 | ||
209 | icmp_packet->icmph.uid = socket_client->index; | 244 | icmp_header->uid = socket_client->index; |
210 | 245 | ||
211 | if (icmp_packet->icmph.header.version != BATADV_COMPAT_VERSION) { | 246 | if (icmp_header->header.version != BATADV_COMPAT_VERSION) { |
212 | icmp_packet->icmph.msg_type = BATADV_PARAMETER_PROBLEM; | 247 | icmp_header->msg_type = BATADV_PARAMETER_PROBLEM; |
213 | icmp_packet->icmph.header.version = BATADV_COMPAT_VERSION; | 248 | icmp_header->header.version = BATADV_COMPAT_VERSION; |
214 | batadv_socket_add_packet(socket_client, icmp_packet, | 249 | batadv_socket_add_packet(socket_client, icmp_header, |
215 | packet_len); | 250 | packet_len); |
216 | goto free_skb; | 251 | goto free_skb; |
217 | } | 252 | } |
218 | 253 | ||
219 | if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) | 254 | memcpy(icmp_header->orig, primary_if->net_dev->dev_addr, ETH_ALEN); |
220 | goto dst_unreach; | ||
221 | |||
222 | orig_node = batadv_orig_hash_find(bat_priv, icmp_packet->icmph.dst); | ||
223 | if (!orig_node) | ||
224 | goto dst_unreach; | ||
225 | |||
226 | neigh_node = batadv_orig_node_get_router(orig_node); | ||
227 | if (!neigh_node) | ||
228 | goto dst_unreach; | ||
229 | |||
230 | if (!neigh_node->if_incoming) | ||
231 | goto dst_unreach; | ||
232 | |||
233 | if (neigh_node->if_incoming->if_status != BATADV_IF_ACTIVE) | ||
234 | goto dst_unreach; | ||
235 | |||
236 | memcpy(icmp_packet->icmph.orig, | ||
237 | primary_if->net_dev->dev_addr, ETH_ALEN); | ||
238 | |||
239 | if (packet_len == sizeof(struct batadv_icmp_packet_rr)) | ||
240 | memcpy(icmp_packet->rr, | ||
241 | neigh_node->if_incoming->net_dev->dev_addr, ETH_ALEN); | ||
242 | 255 | ||
243 | batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); | 256 | batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); |
244 | goto out; | 257 | goto out; |
245 | 258 | ||
246 | dst_unreach: | 259 | dst_unreach: |
247 | icmp_packet->icmph.msg_type = BATADV_DESTINATION_UNREACHABLE; | 260 | icmp_header->msg_type = BATADV_DESTINATION_UNREACHABLE; |
248 | batadv_socket_add_packet(socket_client, icmp_packet, packet_len); | 261 | batadv_socket_add_packet(socket_client, icmp_header, packet_len); |
249 | free_skb: | 262 | free_skb: |
250 | kfree_skb(skb); | 263 | kfree_skb(skb); |
251 | out: | 264 | out: |
@@ -298,27 +311,40 @@ err: | |||
298 | return -ENOMEM; | 311 | return -ENOMEM; |
299 | } | 312 | } |
300 | 313 | ||
314 | /** | ||
315 | * batadv_socket_receive_packet - schedule an icmp packet to be sent to userspace | ||
316 | * on an icmp socket. | ||
317 | * @socket_client: the socket this packet belongs to | ||
318 | * @icmph: pointer to the header of the icmp packet | ||
319 | * @icmp_len: total length of the icmp packet | ||
320 | */ | ||
301 | static void batadv_socket_add_packet(struct batadv_socket_client *socket_client, | 321 | static void batadv_socket_add_packet(struct batadv_socket_client *socket_client, |
302 | struct batadv_icmp_packet_rr *icmp_packet, | 322 | struct batadv_icmp_header *icmph, |
303 | size_t icmp_len) | 323 | size_t icmp_len) |
304 | { | 324 | { |
305 | struct batadv_socket_packet *socket_packet; | 325 | struct batadv_socket_packet *socket_packet; |
326 | size_t len; | ||
306 | 327 | ||
307 | socket_packet = kmalloc(sizeof(*socket_packet), GFP_ATOMIC); | 328 | socket_packet = kmalloc(sizeof(*socket_packet), GFP_ATOMIC); |
308 | 329 | ||
309 | if (!socket_packet) | 330 | if (!socket_packet) |
310 | return; | 331 | return; |
311 | 332 | ||
333 | len = icmp_len; | ||
334 | /* check the maximum length before filling the buffer */ | ||
335 | if (len > sizeof(socket_packet->icmp_packet)) | ||
336 | len = sizeof(socket_packet->icmp_packet); | ||
337 | |||
312 | INIT_LIST_HEAD(&socket_packet->list); | 338 | INIT_LIST_HEAD(&socket_packet->list); |
313 | memcpy(&socket_packet->icmp_packet, icmp_packet, icmp_len); | 339 | memcpy(&socket_packet->icmp_packet, icmph, len); |
314 | socket_packet->icmp_len = icmp_len; | 340 | socket_packet->icmp_len = len; |
315 | 341 | ||
316 | spin_lock_bh(&socket_client->lock); | 342 | spin_lock_bh(&socket_client->lock); |
317 | 343 | ||
318 | /* while waiting for the lock the socket_client could have been | 344 | /* while waiting for the lock the socket_client could have been |
319 | * deleted | 345 | * deleted |
320 | */ | 346 | */ |
321 | if (!batadv_socket_client_hash[icmp_packet->icmph.uid]) { | 347 | if (!batadv_socket_client_hash[icmph->uid]) { |
322 | spin_unlock_bh(&socket_client->lock); | 348 | spin_unlock_bh(&socket_client->lock); |
323 | kfree(socket_packet); | 349 | kfree(socket_packet); |
324 | return; | 350 | return; |
@@ -342,12 +368,18 @@ static void batadv_socket_add_packet(struct batadv_socket_client *socket_client, | |||
342 | wake_up(&socket_client->queue_wait); | 368 | wake_up(&socket_client->queue_wait); |
343 | } | 369 | } |
344 | 370 | ||
345 | void batadv_socket_receive_packet(struct batadv_icmp_packet_rr *icmp_packet, | 371 | /** |
372 | * batadv_socket_receive_packet - schedule an icmp packet to be received | ||
373 | * locally and sent to userspace. | ||
374 | * @icmph: pointer to the header of the icmp packet | ||
375 | * @icmp_len: total length of the icmp packet | ||
376 | */ | ||
377 | void batadv_socket_receive_packet(struct batadv_icmp_header *icmph, | ||
346 | size_t icmp_len) | 378 | size_t icmp_len) |
347 | { | 379 | { |
348 | struct batadv_socket_client *hash; | 380 | struct batadv_socket_client *hash; |
349 | 381 | ||
350 | hash = batadv_socket_client_hash[icmp_packet->icmph.uid]; | 382 | hash = batadv_socket_client_hash[icmph->uid]; |
351 | if (hash) | 383 | if (hash) |
352 | batadv_socket_add_packet(hash, icmp_packet, icmp_len); | 384 | batadv_socket_add_packet(hash, icmph, icmp_len); |
353 | } | 385 | } |
diff --git a/net/batman-adv/icmp_socket.h b/net/batman-adv/icmp_socket.h index 1fcca37b6223..6665080dff79 100644 --- a/net/batman-adv/icmp_socket.h +++ b/net/batman-adv/icmp_socket.h | |||
@@ -24,7 +24,7 @@ | |||
24 | 24 | ||
25 | void batadv_socket_init(void); | 25 | void batadv_socket_init(void); |
26 | int batadv_socket_setup(struct batadv_priv *bat_priv); | 26 | int batadv_socket_setup(struct batadv_priv *bat_priv); |
27 | void batadv_socket_receive_packet(struct batadv_icmp_packet_rr *icmp_packet, | 27 | void batadv_socket_receive_packet(struct batadv_icmp_header *icmph, |
28 | size_t icmp_len); | 28 | size_t icmp_len); |
29 | 29 | ||
30 | #endif /* _NET_BATMAN_ADV_ICMP_SOCKET_H_ */ | 30 | #endif /* _NET_BATMAN_ADV_ICMP_SOCKET_H_ */ |
diff --git a/net/batman-adv/packet.h b/net/batman-adv/packet.h index 843b96ac355a..207459b62966 100644 --- a/net/batman-adv/packet.h +++ b/net/batman-adv/packet.h | |||
@@ -239,6 +239,8 @@ struct batadv_icmp_packet_rr { | |||
239 | uint8_t rr[BATADV_RR_LEN][ETH_ALEN]; | 239 | uint8_t rr[BATADV_RR_LEN][ETH_ALEN]; |
240 | }; | 240 | }; |
241 | 241 | ||
242 | #define BATADV_ICMP_MAX_PACKET_SIZE sizeof(struct batadv_icmp_packet_rr) | ||
243 | |||
242 | /* All packet headers in front of an ethernet header have to be completely | 244 | /* All packet headers in front of an ethernet header have to be completely |
243 | * divisible by 2 but not by 4 to make the payload after the ethernet | 245 | * divisible by 2 but not by 4 to make the payload after the ethernet |
244 | * header again 4 bytes boundary aligned. | 246 | * header again 4 bytes boundary aligned. |
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index 71fba146ddf1..d4114d775ad6 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c | |||
@@ -260,47 +260,65 @@ bool batadv_check_management_packet(struct sk_buff *skb, | |||
260 | return true; | 260 | return true; |
261 | } | 261 | } |
262 | 262 | ||
263 | /** | ||
264 | * batadv_recv_my_icmp_packet - receive an icmp packet locally | ||
265 | * @bat_priv: the bat priv with all the soft interface information | ||
266 | * @skb: icmp packet to process | ||
267 | * | ||
268 | * Returns NET_RX_SUCCESS if the packet has been consumed or NET_RX_DROP | ||
269 | * otherwise. | ||
270 | */ | ||
263 | static int batadv_recv_my_icmp_packet(struct batadv_priv *bat_priv, | 271 | static int batadv_recv_my_icmp_packet(struct batadv_priv *bat_priv, |
264 | struct sk_buff *skb, size_t icmp_len) | 272 | struct sk_buff *skb) |
265 | { | 273 | { |
266 | struct batadv_hard_iface *primary_if = NULL; | 274 | struct batadv_hard_iface *primary_if = NULL; |
267 | struct batadv_orig_node *orig_node = NULL; | 275 | struct batadv_orig_node *orig_node = NULL; |
268 | struct batadv_icmp_packet_rr *icmp_packet; | 276 | struct batadv_icmp_header *icmph; |
269 | int ret = NET_RX_DROP; | 277 | int res, ret = NET_RX_DROP; |
270 | 278 | ||
271 | icmp_packet = (struct batadv_icmp_packet_rr *)skb->data; | 279 | icmph = (struct batadv_icmp_header *)skb->data; |
272 | 280 | ||
273 | /* add data to device queue */ | 281 | switch (icmph->msg_type) { |
274 | if (icmp_packet->icmph.msg_type != BATADV_ECHO_REQUEST) { | 282 | case BATADV_ECHO_REPLY: |
275 | batadv_socket_receive_packet(icmp_packet, icmp_len); | 283 | case BATADV_DESTINATION_UNREACHABLE: |
276 | goto out; | 284 | case BATADV_TTL_EXCEEDED: |
277 | } | 285 | /* receive the packet */ |
286 | if (skb_linearize(skb) < 0) | ||
287 | break; | ||
278 | 288 | ||
279 | primary_if = batadv_primary_if_get_selected(bat_priv); | 289 | batadv_socket_receive_packet(icmph, skb->len); |
280 | if (!primary_if) | 290 | break; |
281 | goto out; | 291 | case BATADV_ECHO_REQUEST: |
292 | /* answer echo request (ping) */ | ||
293 | primary_if = batadv_primary_if_get_selected(bat_priv); | ||
294 | if (!primary_if) | ||
295 | goto out; | ||
282 | 296 | ||
283 | /* answer echo request (ping) */ | 297 | /* get routing information */ |
284 | /* get routing information */ | 298 | orig_node = batadv_orig_hash_find(bat_priv, icmph->orig); |
285 | orig_node = batadv_orig_hash_find(bat_priv, icmp_packet->icmph.orig); | 299 | if (!orig_node) |
286 | if (!orig_node) | 300 | goto out; |
287 | goto out; | ||
288 | 301 | ||
289 | /* create a copy of the skb, if needed, to modify it. */ | 302 | /* create a copy of the skb, if needed, to modify it. */ |
290 | if (skb_cow(skb, ETH_HLEN) < 0) | 303 | if (skb_cow(skb, ETH_HLEN) < 0) |
291 | goto out; | 304 | goto out; |
292 | 305 | ||
293 | icmp_packet = (struct batadv_icmp_packet_rr *)skb->data; | 306 | icmph = (struct batadv_icmp_header *)skb->data; |
294 | 307 | ||
295 | memcpy(icmp_packet->icmph.dst, icmp_packet->icmph.orig, ETH_ALEN); | 308 | memcpy(icmph->dst, icmph->orig, ETH_ALEN); |
296 | memcpy(icmp_packet->icmph.orig, primary_if->net_dev->dev_addr, | 309 | memcpy(icmph->orig, primary_if->net_dev->dev_addr, ETH_ALEN); |
297 | ETH_ALEN); | 310 | icmph->msg_type = BATADV_ECHO_REPLY; |
298 | icmp_packet->icmph.msg_type = BATADV_ECHO_REPLY; | 311 | icmph->header.ttl = BATADV_TTL; |
299 | icmp_packet->icmph.header.ttl = BATADV_TTL; | ||
300 | 312 | ||
301 | if (batadv_send_skb_to_orig(skb, orig_node, NULL) != NET_XMIT_DROP) | 313 | res = batadv_send_skb_to_orig(skb, orig_node, NULL); |
302 | ret = NET_RX_SUCCESS; | 314 | if (res != NET_XMIT_DROP) |
315 | ret = NET_RX_SUCCESS; | ||
303 | 316 | ||
317 | break; | ||
318 | default: | ||
319 | /* drop unknown type */ | ||
320 | goto out; | ||
321 | } | ||
304 | out: | 322 | out: |
305 | if (primary_if) | 323 | if (primary_if) |
306 | batadv_hardif_free_ref(primary_if); | 324 | batadv_hardif_free_ref(primary_if); |
@@ -363,16 +381,13 @@ int batadv_recv_icmp_packet(struct sk_buff *skb, | |||
363 | struct batadv_hard_iface *recv_if) | 381 | struct batadv_hard_iface *recv_if) |
364 | { | 382 | { |
365 | struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface); | 383 | struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface); |
366 | struct batadv_icmp_packet_rr *icmp_packet; | 384 | struct batadv_icmp_header *icmph; |
385 | struct batadv_icmp_packet_rr *icmp_packet_rr; | ||
367 | struct ethhdr *ethhdr; | 386 | struct ethhdr *ethhdr; |
368 | struct batadv_orig_node *orig_node = NULL; | 387 | struct batadv_orig_node *orig_node = NULL; |
369 | int hdr_size = sizeof(struct batadv_icmp_packet); | 388 | int hdr_size = sizeof(struct batadv_icmp_header); |
370 | int ret = NET_RX_DROP; | 389 | int ret = NET_RX_DROP; |
371 | 390 | ||
372 | /* we truncate all incoming icmp packets if they don't match our size */ | ||
373 | if (skb->len >= sizeof(struct batadv_icmp_packet_rr)) | ||
374 | hdr_size = sizeof(struct batadv_icmp_packet_rr); | ||
375 | |||
376 | /* drop packet if it has not necessary minimum size */ | 391 | /* drop packet if it has not necessary minimum size */ |
377 | if (unlikely(!pskb_may_pull(skb, hdr_size))) | 392 | if (unlikely(!pskb_may_pull(skb, hdr_size))) |
378 | goto out; | 393 | goto out; |
@@ -391,28 +406,39 @@ int batadv_recv_icmp_packet(struct sk_buff *skb, | |||
391 | if (!batadv_is_my_mac(bat_priv, ethhdr->h_dest)) | 406 | if (!batadv_is_my_mac(bat_priv, ethhdr->h_dest)) |
392 | goto out; | 407 | goto out; |
393 | 408 | ||
394 | icmp_packet = (struct batadv_icmp_packet_rr *)skb->data; | 409 | icmph = (struct batadv_icmp_header *)skb->data; |
395 | 410 | ||
396 | /* add record route information if not full */ | 411 | /* add record route information if not full */ |
397 | if ((icmp_packet->icmph.msg_type == BATADV_ECHO_REPLY || | 412 | if ((icmph->msg_type == BATADV_ECHO_REPLY || |
398 | icmp_packet->icmph.msg_type == BATADV_ECHO_REQUEST) && | 413 | icmph->msg_type == BATADV_ECHO_REQUEST) && |
399 | (hdr_size == sizeof(struct batadv_icmp_packet_rr)) && | 414 | (skb->len >= sizeof(struct batadv_icmp_packet_rr))) { |
400 | (icmp_packet->rr_cur < BATADV_RR_LEN)) { | 415 | if (skb_linearize(skb) < 0) |
401 | memcpy(&(icmp_packet->rr[icmp_packet->rr_cur]), | 416 | goto out; |
417 | |||
418 | /* create a copy of the skb, if needed, to modify it. */ | ||
419 | if (skb_cow(skb, ETH_HLEN) < 0) | ||
420 | goto out; | ||
421 | |||
422 | icmph = (struct batadv_icmp_header *)skb->data; | ||
423 | icmp_packet_rr = (struct batadv_icmp_packet_rr *)icmph; | ||
424 | if (icmp_packet_rr->rr_cur >= BATADV_RR_LEN) | ||
425 | goto out; | ||
426 | |||
427 | memcpy(&(icmp_packet_rr->rr[icmp_packet_rr->rr_cur]), | ||
402 | ethhdr->h_dest, ETH_ALEN); | 428 | ethhdr->h_dest, ETH_ALEN); |
403 | icmp_packet->rr_cur++; | 429 | icmp_packet_rr->rr_cur++; |
404 | } | 430 | } |
405 | 431 | ||
406 | /* packet for me */ | 432 | /* packet for me */ |
407 | if (batadv_is_my_mac(bat_priv, icmp_packet->icmph.dst)) | 433 | if (batadv_is_my_mac(bat_priv, icmph->dst)) |
408 | return batadv_recv_my_icmp_packet(bat_priv, skb, hdr_size); | 434 | return batadv_recv_my_icmp_packet(bat_priv, skb); |
409 | 435 | ||
410 | /* TTL exceeded */ | 436 | /* TTL exceeded */ |
411 | if (icmp_packet->icmph.header.ttl < 2) | 437 | if (icmph->header.ttl < 2) |
412 | return batadv_recv_icmp_ttl_exceeded(bat_priv, skb); | 438 | return batadv_recv_icmp_ttl_exceeded(bat_priv, skb); |
413 | 439 | ||
414 | /* get routing information */ | 440 | /* get routing information */ |
415 | orig_node = batadv_orig_hash_find(bat_priv, icmp_packet->icmph.dst); | 441 | orig_node = batadv_orig_hash_find(bat_priv, icmph->dst); |
416 | if (!orig_node) | 442 | if (!orig_node) |
417 | goto out; | 443 | goto out; |
418 | 444 | ||
@@ -420,10 +446,10 @@ int batadv_recv_icmp_packet(struct sk_buff *skb, | |||
420 | if (skb_cow(skb, ETH_HLEN) < 0) | 446 | if (skb_cow(skb, ETH_HLEN) < 0) |
421 | goto out; | 447 | goto out; |
422 | 448 | ||
423 | icmp_packet = (struct batadv_icmp_packet_rr *)skb->data; | 449 | icmph = (struct batadv_icmp_header *)skb->data; |
424 | 450 | ||
425 | /* decrement ttl */ | 451 | /* decrement ttl */ |
426 | icmp_packet->icmph.header.ttl--; | 452 | icmph->header.ttl--; |
427 | 453 | ||
428 | /* route it */ | 454 | /* route it */ |
429 | if (batadv_send_skb_to_orig(skb, orig_node, recv_if) != NET_XMIT_DROP) | 455 | if (batadv_send_skb_to_orig(skb, orig_node, recv_if) != NET_XMIT_DROP) |
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 3c2116274de2..91dd369b0ff2 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h | |||
@@ -749,7 +749,7 @@ struct batadv_socket_client { | |||
749 | struct batadv_socket_packet { | 749 | struct batadv_socket_packet { |
750 | struct list_head list; | 750 | struct list_head list; |
751 | size_t icmp_len; | 751 | size_t icmp_len; |
752 | struct batadv_icmp_packet_rr icmp_packet; | 752 | uint8_t icmp_packet[BATADV_ICMP_MAX_PACKET_SIZE]; |
753 | }; | 753 | }; |
754 | 754 | ||
755 | /** | 755 | /** |