diff options
Diffstat (limited to 'net/batman-adv/soft-interface.c')
| -rw-r--r-- | net/batman-adv/soft-interface.c | 107 |
1 files changed, 64 insertions, 43 deletions
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index a8f99d1486c0..c50f64337f55 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c | |||
| @@ -12,9 +12,7 @@ | |||
| 12 | * General Public License for more details. | 12 | * General Public License for more details. |
| 13 | * | 13 | * |
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 17 | * 02110-1301, USA | ||
| 18 | */ | 16 | */ |
| 19 | 17 | ||
| 20 | #include "main.h" | 18 | #include "main.h" |
| @@ -121,7 +119,7 @@ static int batadv_interface_set_mac_addr(struct net_device *dev, void *p) | |||
| 121 | batadv_tt_local_remove(bat_priv, old_addr, BATADV_NO_FLAGS, | 119 | batadv_tt_local_remove(bat_priv, old_addr, BATADV_NO_FLAGS, |
| 122 | "mac address changed", false); | 120 | "mac address changed", false); |
| 123 | batadv_tt_local_add(dev, addr->sa_data, BATADV_NO_FLAGS, | 121 | batadv_tt_local_add(dev, addr->sa_data, BATADV_NO_FLAGS, |
| 124 | BATADV_NULL_IFINDEX); | 122 | BATADV_NULL_IFINDEX, BATADV_NO_MARK); |
| 125 | } | 123 | } |
| 126 | 124 | ||
| 127 | return 0; | 125 | return 0; |
| @@ -162,6 +160,8 @@ static int batadv_interface_tx(struct sk_buff *skb, | |||
| 162 | 0x00, 0x00}; | 160 | 0x00, 0x00}; |
| 163 | static const uint8_t ectp_addr[ETH_ALEN] = {0xCF, 0x00, 0x00, 0x00, | 161 | static const uint8_t ectp_addr[ETH_ALEN] = {0xCF, 0x00, 0x00, 0x00, |
| 164 | 0x00, 0x00}; | 162 | 0x00, 0x00}; |
| 163 | enum batadv_dhcp_recipient dhcp_rcp = BATADV_DHCP_NO; | ||
| 164 | uint8_t *dst_hint = NULL, chaddr[ETH_ALEN]; | ||
| 165 | struct vlan_ethhdr *vhdr; | 165 | struct vlan_ethhdr *vhdr; |
| 166 | unsigned int header_len = 0; | 166 | unsigned int header_len = 0; |
| 167 | int data_len = skb->len, ret; | 167 | int data_len = skb->len, ret; |
| @@ -169,6 +169,7 @@ static int batadv_interface_tx(struct sk_buff *skb, | |||
| 169 | bool do_bcast = false, client_added; | 169 | bool do_bcast = false, client_added; |
| 170 | unsigned short vid; | 170 | unsigned short vid; |
| 171 | uint32_t seqno; | 171 | uint32_t seqno; |
| 172 | int gw_mode; | ||
| 172 | 173 | ||
| 173 | if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) | 174 | if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) |
| 174 | goto dropped; | 175 | goto dropped; |
| @@ -198,7 +199,8 @@ static int batadv_interface_tx(struct sk_buff *skb, | |||
| 198 | /* Register the client MAC in the transtable */ | 199 | /* Register the client MAC in the transtable */ |
| 199 | if (!is_multicast_ether_addr(ethhdr->h_source)) { | 200 | if (!is_multicast_ether_addr(ethhdr->h_source)) { |
| 200 | client_added = batadv_tt_local_add(soft_iface, ethhdr->h_source, | 201 | client_added = batadv_tt_local_add(soft_iface, ethhdr->h_source, |
| 201 | vid, skb->skb_iif); | 202 | vid, skb->skb_iif, |
| 203 | skb->mark); | ||
| 202 | if (!client_added) | 204 | if (!client_added) |
| 203 | goto dropped; | 205 | goto dropped; |
| 204 | } | 206 | } |
| @@ -215,36 +217,39 @@ static int batadv_interface_tx(struct sk_buff *skb, | |||
| 215 | if (batadv_compare_eth(ethhdr->h_dest, ectp_addr)) | 217 | if (batadv_compare_eth(ethhdr->h_dest, ectp_addr)) |
| 216 | goto dropped; | 218 | goto dropped; |
| 217 | 219 | ||
| 220 | gw_mode = atomic_read(&bat_priv->gw_mode); | ||
| 218 | if (is_multicast_ether_addr(ethhdr->h_dest)) { | 221 | if (is_multicast_ether_addr(ethhdr->h_dest)) { |
| 219 | do_bcast = true; | 222 | /* if gw mode is off, broadcast every packet */ |
| 220 | 223 | if (gw_mode == BATADV_GW_MODE_OFF) { | |
| 221 | switch (atomic_read(&bat_priv->gw_mode)) { | 224 | do_bcast = true; |
| 222 | case BATADV_GW_MODE_SERVER: | 225 | goto send; |
| 223 | /* gateway servers should not send dhcp | ||
| 224 | * requests into the mesh | ||
| 225 | */ | ||
| 226 | ret = batadv_gw_is_dhcp_target(skb, &header_len); | ||
| 227 | if (ret) | ||
| 228 | goto dropped; | ||
| 229 | break; | ||
| 230 | case BATADV_GW_MODE_CLIENT: | ||
| 231 | /* gateway clients should send dhcp requests | ||
| 232 | * via unicast to their gateway | ||
| 233 | */ | ||
| 234 | ret = batadv_gw_is_dhcp_target(skb, &header_len); | ||
| 235 | if (ret) | ||
| 236 | do_bcast = false; | ||
| 237 | break; | ||
| 238 | case BATADV_GW_MODE_OFF: | ||
| 239 | default: | ||
| 240 | break; | ||
| 241 | } | 226 | } |
| 242 | 227 | ||
| 243 | /* reminder: ethhdr might have become unusable from here on | 228 | dhcp_rcp = batadv_gw_dhcp_recipient_get(skb, &header_len, |
| 244 | * (batadv_gw_is_dhcp_target() might have reallocated skb data) | 229 | chaddr); |
| 230 | /* skb->data may have been modified by | ||
| 231 | * batadv_gw_dhcp_recipient_get() | ||
| 245 | */ | 232 | */ |
| 233 | ethhdr = (struct ethhdr *)skb->data; | ||
| 234 | /* if gw_mode is on, broadcast any non-DHCP message. | ||
| 235 | * All the DHCP packets are going to be sent as unicast | ||
| 236 | */ | ||
| 237 | if (dhcp_rcp == BATADV_DHCP_NO) { | ||
| 238 | do_bcast = true; | ||
| 239 | goto send; | ||
| 240 | } | ||
| 241 | |||
| 242 | if (dhcp_rcp == BATADV_DHCP_TO_CLIENT) | ||
| 243 | dst_hint = chaddr; | ||
| 244 | else if ((gw_mode == BATADV_GW_MODE_SERVER) && | ||
| 245 | (dhcp_rcp == BATADV_DHCP_TO_SERVER)) | ||
| 246 | /* gateways should not forward any DHCP message if | ||
| 247 | * directed to a DHCP server | ||
| 248 | */ | ||
| 249 | goto dropped; | ||
| 246 | } | 250 | } |
| 247 | 251 | ||
| 252 | send: | ||
| 248 | batadv_skb_set_priority(skb, 0); | 253 | batadv_skb_set_priority(skb, 0); |
| 249 | 254 | ||
| 250 | /* ethernet packet should be broadcasted */ | 255 | /* ethernet packet should be broadcasted */ |
| @@ -290,22 +295,22 @@ static int batadv_interface_tx(struct sk_buff *skb, | |||
| 290 | 295 | ||
| 291 | /* unicast packet */ | 296 | /* unicast packet */ |
| 292 | } else { | 297 | } else { |
| 293 | if (atomic_read(&bat_priv->gw_mode) != BATADV_GW_MODE_OFF) { | 298 | /* DHCP packets going to a server will use the GW feature */ |
| 299 | if (dhcp_rcp == BATADV_DHCP_TO_SERVER) { | ||
| 294 | ret = batadv_gw_out_of_range(bat_priv, skb); | 300 | ret = batadv_gw_out_of_range(bat_priv, skb); |
| 295 | if (ret) | 301 | if (ret) |
| 296 | goto dropped; | 302 | goto dropped; |
| 297 | } | ||
| 298 | |||
| 299 | if (batadv_dat_snoop_outgoing_arp_request(bat_priv, skb)) | ||
| 300 | goto dropped; | ||
| 301 | |||
| 302 | batadv_dat_snoop_outgoing_arp_reply(bat_priv, skb); | ||
| 303 | |||
| 304 | if (is_multicast_ether_addr(ethhdr->h_dest)) | ||
| 305 | ret = batadv_send_skb_via_gw(bat_priv, skb, vid); | 303 | ret = batadv_send_skb_via_gw(bat_priv, skb, vid); |
| 306 | else | 304 | } else { |
| 307 | ret = batadv_send_skb_via_tt(bat_priv, skb, vid); | 305 | if (batadv_dat_snoop_outgoing_arp_request(bat_priv, |
| 306 | skb)) | ||
| 307 | goto dropped; | ||
| 308 | 308 | ||
| 309 | batadv_dat_snoop_outgoing_arp_reply(bat_priv, skb); | ||
| 310 | |||
| 311 | ret = batadv_send_skb_via_tt(bat_priv, skb, dst_hint, | ||
| 312 | vid); | ||
| 313 | } | ||
| 309 | if (ret == NET_XMIT_DROP) | 314 | if (ret == NET_XMIT_DROP) |
| 310 | goto dropped_freed; | 315 | goto dropped_freed; |
| 311 | } | 316 | } |
| @@ -394,9 +399,23 @@ void batadv_interface_rx(struct net_device *soft_iface, | |||
| 394 | batadv_tt_add_temporary_global_entry(bat_priv, orig_node, | 399 | batadv_tt_add_temporary_global_entry(bat_priv, orig_node, |
| 395 | ethhdr->h_source, vid); | 400 | ethhdr->h_source, vid); |
| 396 | 401 | ||
| 397 | if (batadv_is_ap_isolated(bat_priv, ethhdr->h_source, ethhdr->h_dest, | 402 | if (is_multicast_ether_addr(ethhdr->h_dest)) { |
| 398 | vid)) | 403 | /* set the mark on broadcast packets if AP isolation is ON and |
| 404 | * the packet is coming from an "isolated" client | ||
| 405 | */ | ||
| 406 | if (batadv_vlan_ap_isola_get(bat_priv, vid) && | ||
| 407 | batadv_tt_global_is_isolated(bat_priv, ethhdr->h_source, | ||
| 408 | vid)) { | ||
| 409 | /* save bits in skb->mark not covered by the mask and | ||
| 410 | * apply the mark on the rest | ||
| 411 | */ | ||
| 412 | skb->mark &= ~bat_priv->isolation_mark_mask; | ||
| 413 | skb->mark |= bat_priv->isolation_mark; | ||
| 414 | } | ||
| 415 | } else if (batadv_is_ap_isolated(bat_priv, ethhdr->h_source, | ||
| 416 | ethhdr->h_dest, vid)) { | ||
| 399 | goto dropped; | 417 | goto dropped; |
| 418 | } | ||
| 400 | 419 | ||
| 401 | netif_rx(skb); | 420 | netif_rx(skb); |
| 402 | goto out; | 421 | goto out; |
| @@ -485,7 +504,7 @@ int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid) | |||
| 485 | */ | 504 | */ |
| 486 | batadv_tt_local_add(bat_priv->soft_iface, | 505 | batadv_tt_local_add(bat_priv->soft_iface, |
| 487 | bat_priv->soft_iface->dev_addr, vid, | 506 | bat_priv->soft_iface->dev_addr, vid, |
| 488 | BATADV_NULL_IFINDEX); | 507 | BATADV_NULL_IFINDEX, BATADV_NO_MARK); |
| 489 | 508 | ||
| 490 | spin_lock_bh(&bat_priv->softif_vlan_list_lock); | 509 | spin_lock_bh(&bat_priv->softif_vlan_list_lock); |
| 491 | hlist_add_head_rcu(&vlan->list, &bat_priv->softif_vlan_list); | 510 | hlist_add_head_rcu(&vlan->list, &bat_priv->softif_vlan_list); |
| @@ -697,6 +716,8 @@ static int batadv_softif_init_late(struct net_device *dev) | |||
| 697 | #endif | 716 | #endif |
| 698 | bat_priv->tt.last_changeset = NULL; | 717 | bat_priv->tt.last_changeset = NULL; |
| 699 | bat_priv->tt.last_changeset_len = 0; | 718 | bat_priv->tt.last_changeset_len = 0; |
| 719 | bat_priv->isolation_mark = 0; | ||
| 720 | bat_priv->isolation_mark_mask = 0; | ||
| 700 | 721 | ||
| 701 | /* randomize initial seqno to avoid collision */ | 722 | /* randomize initial seqno to avoid collision */ |
| 702 | get_random_bytes(&random_seqno, sizeof(random_seqno)); | 723 | get_random_bytes(&random_seqno, sizeof(random_seqno)); |
