diff options
Diffstat (limited to 'net/bridge')
| -rw-r--r-- | net/bridge/br_fdb.c | 5 | ||||
| -rw-r--r-- | net/bridge/br_forward.c | 10 | ||||
| -rw-r--r-- | net/bridge/br_multicast.c | 9 | ||||
| -rw-r--r-- | net/bridge/br_netfilter_hooks.c | 2 | ||||
| -rw-r--r-- | net/bridge/br_netfilter_ipv6.c | 1 | ||||
| -rw-r--r-- | net/bridge/br_private.h | 1 | ||||
| -rw-r--r-- | net/bridge/br_vlan.c | 26 | ||||
| -rw-r--r-- | net/bridge/netfilter/ebtables.c | 15 | ||||
| -rw-r--r-- | net/bridge/netfilter/nft_reject_bridge.c | 1 |
9 files changed, 38 insertions, 32 deletions
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index fe3c758791ca..9e14767500ea 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c | |||
| @@ -1128,6 +1128,8 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p, | |||
| 1128 | err = -ENOMEM; | 1128 | err = -ENOMEM; |
| 1129 | goto err_unlock; | 1129 | goto err_unlock; |
| 1130 | } | 1130 | } |
| 1131 | if (swdev_notify) | ||
| 1132 | fdb->added_by_user = 1; | ||
| 1131 | fdb->added_by_external_learn = 1; | 1133 | fdb->added_by_external_learn = 1; |
| 1132 | fdb_notify(br, fdb, RTM_NEWNEIGH, swdev_notify); | 1134 | fdb_notify(br, fdb, RTM_NEWNEIGH, swdev_notify); |
| 1133 | } else { | 1135 | } else { |
| @@ -1147,6 +1149,9 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p, | |||
| 1147 | modified = true; | 1149 | modified = true; |
| 1148 | } | 1150 | } |
| 1149 | 1151 | ||
| 1152 | if (swdev_notify) | ||
| 1153 | fdb->added_by_user = 1; | ||
| 1154 | |||
| 1150 | if (modified) | 1155 | if (modified) |
| 1151 | fdb_notify(br, fdb, RTM_NEWNEIGH, swdev_notify); | 1156 | fdb_notify(br, fdb, RTM_NEWNEIGH, swdev_notify); |
| 1152 | } | 1157 | } |
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c index 5372e2042adf..48ddc60b4fbd 100644 --- a/net/bridge/br_forward.c +++ b/net/bridge/br_forward.c | |||
| @@ -36,10 +36,10 @@ static inline int should_deliver(const struct net_bridge_port *p, | |||
| 36 | 36 | ||
| 37 | int br_dev_queue_push_xmit(struct net *net, struct sock *sk, struct sk_buff *skb) | 37 | int br_dev_queue_push_xmit(struct net *net, struct sock *sk, struct sk_buff *skb) |
| 38 | { | 38 | { |
| 39 | skb_push(skb, ETH_HLEN); | ||
| 39 | if (!is_skb_forwardable(skb->dev, skb)) | 40 | if (!is_skb_forwardable(skb->dev, skb)) |
| 40 | goto drop; | 41 | goto drop; |
| 41 | 42 | ||
| 42 | skb_push(skb, ETH_HLEN); | ||
| 43 | br_drop_fake_rtable(skb); | 43 | br_drop_fake_rtable(skb); |
| 44 | 44 | ||
| 45 | if (skb->ip_summed == CHECKSUM_PARTIAL && | 45 | if (skb->ip_summed == CHECKSUM_PARTIAL && |
| @@ -65,6 +65,7 @@ EXPORT_SYMBOL_GPL(br_dev_queue_push_xmit); | |||
| 65 | 65 | ||
| 66 | int br_forward_finish(struct net *net, struct sock *sk, struct sk_buff *skb) | 66 | int br_forward_finish(struct net *net, struct sock *sk, struct sk_buff *skb) |
| 67 | { | 67 | { |
| 68 | skb->tstamp = 0; | ||
| 68 | return NF_HOOK(NFPROTO_BRIDGE, NF_BR_POST_ROUTING, | 69 | return NF_HOOK(NFPROTO_BRIDGE, NF_BR_POST_ROUTING, |
| 69 | net, sk, skb, NULL, skb->dev, | 70 | net, sk, skb, NULL, skb->dev, |
| 70 | br_dev_queue_push_xmit); | 71 | br_dev_queue_push_xmit); |
| @@ -97,12 +98,11 @@ static void __br_forward(const struct net_bridge_port *to, | |||
| 97 | net = dev_net(indev); | 98 | net = dev_net(indev); |
| 98 | } else { | 99 | } else { |
| 99 | if (unlikely(netpoll_tx_running(to->br->dev))) { | 100 | if (unlikely(netpoll_tx_running(to->br->dev))) { |
| 100 | if (!is_skb_forwardable(skb->dev, skb)) { | 101 | skb_push(skb, ETH_HLEN); |
| 102 | if (!is_skb_forwardable(skb->dev, skb)) | ||
| 101 | kfree_skb(skb); | 103 | kfree_skb(skb); |
| 102 | } else { | 104 | else |
| 103 | skb_push(skb, ETH_HLEN); | ||
| 104 | br_netpoll_send_skb(to, skb); | 105 | br_netpoll_send_skb(to, skb); |
| 105 | } | ||
| 106 | return; | 106 | return; |
| 107 | } | 107 | } |
| 108 | br_hook = NF_BR_LOCAL_OUT; | 108 | br_hook = NF_BR_LOCAL_OUT; |
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 3aeff0895669..ac92b2eb32b1 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c | |||
| @@ -1204,14 +1204,7 @@ static void br_multicast_query_received(struct net_bridge *br, | |||
| 1204 | return; | 1204 | return; |
| 1205 | 1205 | ||
| 1206 | br_multicast_update_query_timer(br, query, max_delay); | 1206 | br_multicast_update_query_timer(br, query, max_delay); |
| 1207 | 1207 | br_multicast_mark_router(br, port); | |
| 1208 | /* Based on RFC4541, section 2.1.1 IGMP Forwarding Rules, | ||
| 1209 | * the arrival port for IGMP Queries where the source address | ||
| 1210 | * is 0.0.0.0 should not be added to router port list. | ||
| 1211 | */ | ||
| 1212 | if ((saddr->proto == htons(ETH_P_IP) && saddr->u.ip4) || | ||
| 1213 | saddr->proto == htons(ETH_P_IPV6)) | ||
| 1214 | br_multicast_mark_router(br, port); | ||
| 1215 | } | 1208 | } |
| 1216 | 1209 | ||
| 1217 | static void br_ip4_multicast_query(struct net_bridge *br, | 1210 | static void br_ip4_multicast_query(struct net_bridge *br, |
diff --git a/net/bridge/br_netfilter_hooks.c b/net/bridge/br_netfilter_hooks.c index d21a23698410..c93c35bb73dd 100644 --- a/net/bridge/br_netfilter_hooks.c +++ b/net/bridge/br_netfilter_hooks.c | |||
| @@ -265,7 +265,7 @@ int br_nf_pre_routing_finish_bridge(struct net *net, struct sock *sk, struct sk_ | |||
| 265 | struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb); | 265 | struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb); |
| 266 | int ret; | 266 | int ret; |
| 267 | 267 | ||
| 268 | if (neigh->hh.hh_len) { | 268 | if ((neigh->nud_state & NUD_CONNECTED) && neigh->hh.hh_len) { |
| 269 | neigh_hh_bridge(&neigh->hh, skb); | 269 | neigh_hh_bridge(&neigh->hh, skb); |
| 270 | skb->dev = nf_bridge->physindev; | 270 | skb->dev = nf_bridge->physindev; |
| 271 | ret = br_handle_frame_finish(net, sk, skb); | 271 | ret = br_handle_frame_finish(net, sk, skb); |
diff --git a/net/bridge/br_netfilter_ipv6.c b/net/bridge/br_netfilter_ipv6.c index 94039f588f1d..564710f88f93 100644 --- a/net/bridge/br_netfilter_ipv6.c +++ b/net/bridge/br_netfilter_ipv6.c | |||
| @@ -131,6 +131,7 @@ int br_validate_ipv6(struct net *net, struct sk_buff *skb) | |||
| 131 | IPSTATS_MIB_INDISCARDS); | 131 | IPSTATS_MIB_INDISCARDS); |
| 132 | goto drop; | 132 | goto drop; |
| 133 | } | 133 | } |
| 134 | hdr = ipv6_hdr(skb); | ||
| 134 | } | 135 | } |
| 135 | if (hdr->nexthdr == NEXTHDR_HOP && br_nf_check_hbh_len(skb)) | 136 | if (hdr->nexthdr == NEXTHDR_HOP && br_nf_check_hbh_len(skb)) |
| 136 | goto drop; | 137 | goto drop; |
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index d240b3e7919f..eabf8bf28a3f 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h | |||
| @@ -107,6 +107,7 @@ struct br_tunnel_info { | |||
| 107 | /* private vlan flags */ | 107 | /* private vlan flags */ |
| 108 | enum { | 108 | enum { |
| 109 | BR_VLFLAG_PER_PORT_STATS = BIT(0), | 109 | BR_VLFLAG_PER_PORT_STATS = BIT(0), |
| 110 | BR_VLFLAG_ADDED_BY_SWITCHDEV = BIT(1), | ||
| 110 | }; | 111 | }; |
| 111 | 112 | ||
| 112 | /** | 113 | /** |
diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index 4a2f31157ef5..96abf8feb9dc 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c | |||
| @@ -80,16 +80,18 @@ static bool __vlan_add_flags(struct net_bridge_vlan *v, u16 flags) | |||
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | static int __vlan_vid_add(struct net_device *dev, struct net_bridge *br, | 82 | static int __vlan_vid_add(struct net_device *dev, struct net_bridge *br, |
| 83 | u16 vid, u16 flags, struct netlink_ext_ack *extack) | 83 | struct net_bridge_vlan *v, u16 flags, |
| 84 | struct netlink_ext_ack *extack) | ||
| 84 | { | 85 | { |
| 85 | int err; | 86 | int err; |
| 86 | 87 | ||
| 87 | /* Try switchdev op first. In case it is not supported, fallback to | 88 | /* Try switchdev op first. In case it is not supported, fallback to |
| 88 | * 8021q add. | 89 | * 8021q add. |
| 89 | */ | 90 | */ |
| 90 | err = br_switchdev_port_vlan_add(dev, vid, flags, extack); | 91 | err = br_switchdev_port_vlan_add(dev, v->vid, flags, extack); |
| 91 | if (err == -EOPNOTSUPP) | 92 | if (err == -EOPNOTSUPP) |
| 92 | return vlan_vid_add(dev, br->vlan_proto, vid); | 93 | return vlan_vid_add(dev, br->vlan_proto, v->vid); |
| 94 | v->priv_flags |= BR_VLFLAG_ADDED_BY_SWITCHDEV; | ||
| 93 | return err; | 95 | return err; |
| 94 | } | 96 | } |
| 95 | 97 | ||
| @@ -121,19 +123,17 @@ static void __vlan_del_list(struct net_bridge_vlan *v) | |||
| 121 | } | 123 | } |
| 122 | 124 | ||
| 123 | static int __vlan_vid_del(struct net_device *dev, struct net_bridge *br, | 125 | static int __vlan_vid_del(struct net_device *dev, struct net_bridge *br, |
| 124 | u16 vid) | 126 | const struct net_bridge_vlan *v) |
| 125 | { | 127 | { |
| 126 | int err; | 128 | int err; |
| 127 | 129 | ||
| 128 | /* Try switchdev op first. In case it is not supported, fallback to | 130 | /* Try switchdev op first. In case it is not supported, fallback to |
| 129 | * 8021q del. | 131 | * 8021q del. |
| 130 | */ | 132 | */ |
| 131 | err = br_switchdev_port_vlan_del(dev, vid); | 133 | err = br_switchdev_port_vlan_del(dev, v->vid); |
| 132 | if (err == -EOPNOTSUPP) { | 134 | if (!(v->priv_flags & BR_VLFLAG_ADDED_BY_SWITCHDEV)) |
| 133 | vlan_vid_del(dev, br->vlan_proto, vid); | 135 | vlan_vid_del(dev, br->vlan_proto, v->vid); |
| 134 | return 0; | 136 | return err == -EOPNOTSUPP ? 0 : err; |
| 135 | } | ||
| 136 | return err; | ||
| 137 | } | 137 | } |
| 138 | 138 | ||
| 139 | /* Returns a master vlan, if it didn't exist it gets created. In all cases a | 139 | /* Returns a master vlan, if it didn't exist it gets created. In all cases a |
| @@ -242,7 +242,7 @@ static int __vlan_add(struct net_bridge_vlan *v, u16 flags, | |||
| 242 | * This ensures tagged traffic enters the bridge when | 242 | * This ensures tagged traffic enters the bridge when |
| 243 | * promiscuous mode is disabled by br_manage_promisc(). | 243 | * promiscuous mode is disabled by br_manage_promisc(). |
| 244 | */ | 244 | */ |
| 245 | err = __vlan_vid_add(dev, br, v->vid, flags, extack); | 245 | err = __vlan_vid_add(dev, br, v, flags, extack); |
| 246 | if (err) | 246 | if (err) |
| 247 | goto out; | 247 | goto out; |
| 248 | 248 | ||
| @@ -305,7 +305,7 @@ out_fdb_insert: | |||
| 305 | 305 | ||
| 306 | out_filt: | 306 | out_filt: |
| 307 | if (p) { | 307 | if (p) { |
| 308 | __vlan_vid_del(dev, br, v->vid); | 308 | __vlan_vid_del(dev, br, v); |
| 309 | if (masterv) { | 309 | if (masterv) { |
| 310 | if (v->stats && masterv->stats != v->stats) | 310 | if (v->stats && masterv->stats != v->stats) |
| 311 | free_percpu(v->stats); | 311 | free_percpu(v->stats); |
| @@ -338,7 +338,7 @@ static int __vlan_del(struct net_bridge_vlan *v) | |||
| 338 | 338 | ||
| 339 | __vlan_delete_pvid(vg, v->vid); | 339 | __vlan_delete_pvid(vg, v->vid); |
| 340 | if (p) { | 340 | if (p) { |
| 341 | err = __vlan_vid_del(p->dev, p->br, v->vid); | 341 | err = __vlan_vid_del(p->dev, p->br, v); |
| 342 | if (err) | 342 | if (err) |
| 343 | goto out; | 343 | goto out; |
| 344 | } else { | 344 | } else { |
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 491828713e0b..6693e209efe8 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c | |||
| @@ -1137,14 +1137,16 @@ static int do_replace(struct net *net, const void __user *user, | |||
| 1137 | tmp.name[sizeof(tmp.name) - 1] = 0; | 1137 | tmp.name[sizeof(tmp.name) - 1] = 0; |
| 1138 | 1138 | ||
| 1139 | countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids; | 1139 | countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids; |
| 1140 | newinfo = vmalloc(sizeof(*newinfo) + countersize); | 1140 | newinfo = __vmalloc(sizeof(*newinfo) + countersize, GFP_KERNEL_ACCOUNT, |
| 1141 | PAGE_KERNEL); | ||
| 1141 | if (!newinfo) | 1142 | if (!newinfo) |
| 1142 | return -ENOMEM; | 1143 | return -ENOMEM; |
| 1143 | 1144 | ||
| 1144 | if (countersize) | 1145 | if (countersize) |
| 1145 | memset(newinfo->counters, 0, countersize); | 1146 | memset(newinfo->counters, 0, countersize); |
| 1146 | 1147 | ||
| 1147 | newinfo->entries = vmalloc(tmp.entries_size); | 1148 | newinfo->entries = __vmalloc(tmp.entries_size, GFP_KERNEL_ACCOUNT, |
| 1149 | PAGE_KERNEL); | ||
| 1148 | if (!newinfo->entries) { | 1150 | if (!newinfo->entries) { |
| 1149 | ret = -ENOMEM; | 1151 | ret = -ENOMEM; |
| 1150 | goto free_newinfo; | 1152 | goto free_newinfo; |
| @@ -2291,9 +2293,12 @@ static int compat_do_replace(struct net *net, void __user *user, | |||
| 2291 | 2293 | ||
| 2292 | xt_compat_lock(NFPROTO_BRIDGE); | 2294 | xt_compat_lock(NFPROTO_BRIDGE); |
| 2293 | 2295 | ||
| 2294 | ret = xt_compat_init_offsets(NFPROTO_BRIDGE, tmp.nentries); | 2296 | if (tmp.nentries) { |
| 2295 | if (ret < 0) | 2297 | ret = xt_compat_init_offsets(NFPROTO_BRIDGE, tmp.nentries); |
| 2296 | goto out_unlock; | 2298 | if (ret < 0) |
| 2299 | goto out_unlock; | ||
| 2300 | } | ||
| 2301 | |||
| 2297 | ret = compat_copy_entries(entries_tmp, tmp.entries_size, &state); | 2302 | ret = compat_copy_entries(entries_tmp, tmp.entries_size, &state); |
| 2298 | if (ret < 0) | 2303 | if (ret < 0) |
| 2299 | goto out_unlock; | 2304 | goto out_unlock; |
diff --git a/net/bridge/netfilter/nft_reject_bridge.c b/net/bridge/netfilter/nft_reject_bridge.c index 08cbed7d940e..419e8edf23ba 100644 --- a/net/bridge/netfilter/nft_reject_bridge.c +++ b/net/bridge/netfilter/nft_reject_bridge.c | |||
| @@ -229,6 +229,7 @@ static bool reject6_br_csum_ok(struct sk_buff *skb, int hook) | |||
| 229 | pskb_trim_rcsum(skb, ntohs(ip6h->payload_len) + sizeof(*ip6h))) | 229 | pskb_trim_rcsum(skb, ntohs(ip6h->payload_len) + sizeof(*ip6h))) |
| 230 | return false; | 230 | return false; |
| 231 | 231 | ||
| 232 | ip6h = ipv6_hdr(skb); | ||
| 232 | thoff = ipv6_skip_exthdr(skb, ((u8*)(ip6h+1) - skb->data), &proto, &fo); | 233 | thoff = ipv6_skip_exthdr(skb, ((u8*)(ip6h+1) - skb->data), &proto, &fo); |
| 233 | if (thoff < 0 || thoff >= skb->len || (fo & htons(~0x7)) != 0) | 234 | if (thoff < 0 || thoff >= skb->len || (fo & htons(~0x7)) != 0) |
| 234 | return false; | 235 | return false; |
