Commit e5ac5da8 authored by David S. Miller's avatar David S. Miller

Merge tag 'batman-adv-fix-for-davem' of git://git.open-mesh.org/linux-merge

Included change:
- reassign pointers to data after skb reallocation to avoid kernel paging errors
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 4209423c 9d2c9488
...@@ -1529,6 +1529,8 @@ int batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb, ...@@ -1529,6 +1529,8 @@ int batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb,
* in these cases, the skb is further handled by this function and * in these cases, the skb is further handled by this function and
* returns 1, otherwise it returns 0 and the caller shall further * returns 1, otherwise it returns 0 and the caller shall further
* process the skb. * process the skb.
*
* This call might reallocate skb data.
*/ */
int batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb, int batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb,
unsigned short vid) unsigned short vid)
......
...@@ -508,6 +508,7 @@ int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset) ...@@ -508,6 +508,7 @@ int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset)
return 0; return 0;
} }
/* this call might reallocate skb data */
static bool batadv_is_type_dhcprequest(struct sk_buff *skb, int header_len) static bool batadv_is_type_dhcprequest(struct sk_buff *skb, int header_len)
{ {
int ret = false; int ret = false;
...@@ -568,6 +569,7 @@ static bool batadv_is_type_dhcprequest(struct sk_buff *skb, int header_len) ...@@ -568,6 +569,7 @@ static bool batadv_is_type_dhcprequest(struct sk_buff *skb, int header_len)
return ret; return ret;
} }
/* this call might reallocate skb data */
bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len) bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
{ {
struct ethhdr *ethhdr; struct ethhdr *ethhdr;
...@@ -619,6 +621,12 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len) ...@@ -619,6 +621,12 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
if (!pskb_may_pull(skb, *header_len + sizeof(*udphdr))) if (!pskb_may_pull(skb, *header_len + sizeof(*udphdr)))
return false; return false;
/* skb->data might have been reallocated by pskb_may_pull() */
ethhdr = (struct ethhdr *)skb->data;
if (ntohs(ethhdr->h_proto) == ETH_P_8021Q)
ethhdr = (struct ethhdr *)(skb->data + VLAN_HLEN);
udphdr = (struct udphdr *)(skb->data + *header_len); udphdr = (struct udphdr *)(skb->data + *header_len);
*header_len += sizeof(*udphdr); *header_len += sizeof(*udphdr);
...@@ -634,12 +642,14 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len) ...@@ -634,12 +642,14 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
return true; return true;
} }
/* this call might reallocate skb data */
bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
struct sk_buff *skb, struct ethhdr *ethhdr) struct sk_buff *skb)
{ {
struct batadv_neigh_node *neigh_curr = NULL, *neigh_old = NULL; struct batadv_neigh_node *neigh_curr = NULL, *neigh_old = NULL;
struct batadv_orig_node *orig_dst_node = NULL; struct batadv_orig_node *orig_dst_node = NULL;
struct batadv_gw_node *curr_gw = NULL; struct batadv_gw_node *curr_gw = NULL;
struct ethhdr *ethhdr;
bool ret, out_of_range = false; bool ret, out_of_range = false;
unsigned int header_len = 0; unsigned int header_len = 0;
uint8_t curr_tq_avg; uint8_t curr_tq_avg;
...@@ -648,6 +658,7 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, ...@@ -648,6 +658,7 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
if (!ret) if (!ret)
goto out; goto out;
ethhdr = (struct ethhdr *)skb->data;
orig_dst_node = batadv_transtable_search(bat_priv, ethhdr->h_source, orig_dst_node = batadv_transtable_search(bat_priv, ethhdr->h_source,
ethhdr->h_dest); ethhdr->h_dest);
if (!orig_dst_node) if (!orig_dst_node)
......
...@@ -34,7 +34,6 @@ void batadv_gw_node_delete(struct batadv_priv *bat_priv, ...@@ -34,7 +34,6 @@ void batadv_gw_node_delete(struct batadv_priv *bat_priv,
void batadv_gw_node_purge(struct batadv_priv *bat_priv); void batadv_gw_node_purge(struct batadv_priv *bat_priv);
int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset); int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset);
bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len); bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len);
bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, struct sk_buff *skb);
struct sk_buff *skb, struct ethhdr *ethhdr);
#endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */ #endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */
...@@ -180,6 +180,9 @@ static int batadv_interface_tx(struct sk_buff *skb, ...@@ -180,6 +180,9 @@ static int batadv_interface_tx(struct sk_buff *skb,
if (batadv_bla_tx(bat_priv, skb, vid)) if (batadv_bla_tx(bat_priv, skb, vid))
goto dropped; goto dropped;
/* skb->data might have been reallocated by batadv_bla_tx() */
ethhdr = (struct ethhdr *)skb->data;
/* Register the client MAC in the transtable */ /* Register the client MAC in the transtable */
if (!is_multicast_ether_addr(ethhdr->h_source)) if (!is_multicast_ether_addr(ethhdr->h_source))
batadv_tt_local_add(soft_iface, ethhdr->h_source, skb->skb_iif); batadv_tt_local_add(soft_iface, ethhdr->h_source, skb->skb_iif);
...@@ -220,6 +223,10 @@ static int batadv_interface_tx(struct sk_buff *skb, ...@@ -220,6 +223,10 @@ static int batadv_interface_tx(struct sk_buff *skb,
default: default:
break; break;
} }
/* reminder: ethhdr might have become unusable from here on
* (batadv_gw_is_dhcp_target() might have reallocated skb data)
*/
} }
/* ethernet packet should be broadcasted */ /* ethernet packet should be broadcasted */
...@@ -266,7 +273,7 @@ static int batadv_interface_tx(struct sk_buff *skb, ...@@ -266,7 +273,7 @@ static int batadv_interface_tx(struct sk_buff *skb,
/* unicast packet */ /* unicast packet */
} else { } else {
if (atomic_read(&bat_priv->gw_mode) != BATADV_GW_MODE_OFF) { if (atomic_read(&bat_priv->gw_mode) != BATADV_GW_MODE_OFF) {
ret = batadv_gw_out_of_range(bat_priv, skb, ethhdr); ret = batadv_gw_out_of_range(bat_priv, skb);
if (ret) if (ret)
goto dropped; goto dropped;
} }
......
...@@ -326,7 +326,9 @@ static bool batadv_unicast_push_and_fill_skb(struct sk_buff *skb, int hdr_size, ...@@ -326,7 +326,9 @@ static bool batadv_unicast_push_and_fill_skb(struct sk_buff *skb, int hdr_size,
* @skb: the skb containing the payload to encapsulate * @skb: the skb containing the payload to encapsulate
* @orig_node: the destination node * @orig_node: the destination node
* *
* Returns false if the payload could not be encapsulated or true otherwise * Returns false if the payload could not be encapsulated or true otherwise.
*
* This call might reallocate skb data.
*/ */
static bool batadv_unicast_prepare_skb(struct sk_buff *skb, static bool batadv_unicast_prepare_skb(struct sk_buff *skb,
struct batadv_orig_node *orig_node) struct batadv_orig_node *orig_node)
...@@ -343,7 +345,9 @@ static bool batadv_unicast_prepare_skb(struct sk_buff *skb, ...@@ -343,7 +345,9 @@ static bool batadv_unicast_prepare_skb(struct sk_buff *skb,
* @orig_node: the destination node * @orig_node: the destination node
* @packet_subtype: the batman 4addr packet subtype to use * @packet_subtype: the batman 4addr packet subtype to use
* *
* Returns false if the payload could not be encapsulated or true otherwise * Returns false if the payload could not be encapsulated or true otherwise.
*
* This call might reallocate skb data.
*/ */
bool batadv_unicast_4addr_prepare_skb(struct batadv_priv *bat_priv, bool batadv_unicast_4addr_prepare_skb(struct batadv_priv *bat_priv,
struct sk_buff *skb, struct sk_buff *skb,
...@@ -401,7 +405,7 @@ int batadv_unicast_generic_send_skb(struct batadv_priv *bat_priv, ...@@ -401,7 +405,7 @@ int batadv_unicast_generic_send_skb(struct batadv_priv *bat_priv,
struct batadv_neigh_node *neigh_node; struct batadv_neigh_node *neigh_node;
int data_len = skb->len; int data_len = skb->len;
int ret = NET_RX_DROP; int ret = NET_RX_DROP;
unsigned int dev_mtu; unsigned int dev_mtu, header_len;
/* get routing information */ /* get routing information */
if (is_multicast_ether_addr(ethhdr->h_dest)) { if (is_multicast_ether_addr(ethhdr->h_dest)) {
...@@ -429,10 +433,12 @@ int batadv_unicast_generic_send_skb(struct batadv_priv *bat_priv, ...@@ -429,10 +433,12 @@ int batadv_unicast_generic_send_skb(struct batadv_priv *bat_priv,
switch (packet_type) { switch (packet_type) {
case BATADV_UNICAST: case BATADV_UNICAST:
batadv_unicast_prepare_skb(skb, orig_node); batadv_unicast_prepare_skb(skb, orig_node);
header_len = sizeof(struct batadv_unicast_packet);
break; break;
case BATADV_UNICAST_4ADDR: case BATADV_UNICAST_4ADDR:
batadv_unicast_4addr_prepare_skb(bat_priv, skb, orig_node, batadv_unicast_4addr_prepare_skb(bat_priv, skb, orig_node,
packet_subtype); packet_subtype);
header_len = sizeof(struct batadv_unicast_4addr_packet);
break; break;
default: default:
/* this function supports UNICAST and UNICAST_4ADDR only. It /* this function supports UNICAST and UNICAST_4ADDR only. It
...@@ -441,6 +447,7 @@ int batadv_unicast_generic_send_skb(struct batadv_priv *bat_priv, ...@@ -441,6 +447,7 @@ int batadv_unicast_generic_send_skb(struct batadv_priv *bat_priv,
goto out; goto out;
} }
ethhdr = (struct ethhdr *)(skb->data + header_len);
unicast_packet = (struct batadv_unicast_packet *)skb->data; unicast_packet = (struct batadv_unicast_packet *)skb->data;
/* inform the destination node that we are still missing a correct route /* inform the destination node that we are still missing a correct route
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment