kernel: make the kernel 3.18 patches apply and boot on arm.
[openwrt.git] / target / linux / generic / patches-3.18 / 645-bridge_multicast_to_unicast.patch
1 --- a/net/bridge/br_multicast.c
2 +++ b/net/bridge/br_multicast.c
3 @@ -635,7 +635,8 @@ struct net_bridge_port_group *br_multica
4                         struct net_bridge_port *port,
5                         struct br_ip *group,
6                         struct net_bridge_port_group __rcu *next,
7 -                       unsigned char state)
8 +                       unsigned char state,
9 +                       const unsigned char *src)
10  {
11         struct net_bridge_port_group *p;
12  
13 @@ -650,12 +651,33 @@ struct net_bridge_port_group *br_multica
14         hlist_add_head(&p->mglist, &port->mglist);
15         setup_timer(&p->timer, br_multicast_port_group_expired,
16                     (unsigned long)p);
17 +       if ((port->flags & BR_MULTICAST_TO_UCAST) && src) {
18 +               memcpy(p->eth_addr, src, ETH_ALEN);
19 +               p->unicast = true;
20 +       }
21         return p;
22  }
23  
24 +static bool br_port_group_equal(struct net_bridge_port_group *p,
25 +                               struct net_bridge_port *port,
26 +                               const unsigned char *src)
27 +{
28 +       if (p->port != port)
29 +               return false;
30 +
31 +       if (!p->unicast)
32 +               return true;
33 +
34 +       if (!src)
35 +               return false;
36 +
37 +       return ether_addr_equal(src, p->eth_addr);
38 +}
39 +
40  static int br_multicast_add_group(struct net_bridge *br,
41                                   struct net_bridge_port *port,
42 -                                 struct br_ip *group)
43 +                                 struct br_ip *group,
44 +                                 const unsigned char *src)
45  {
46         struct net_bridge_mdb_entry *mp;
47         struct net_bridge_port_group *p;
48 @@ -682,13 +704,13 @@ static int br_multicast_add_group(struct
49         for (pp = &mp->ports;
50              (p = mlock_dereference(*pp, br)) != NULL;
51              pp = &p->next) {
52 -               if (p->port == port)
53 +               if (br_port_group_equal(p, port, src))
54                         goto found;
55                 if ((unsigned long)p->port < (unsigned long)port)
56                         break;
57         }
58  
59 -       p = br_multicast_new_port_group(port, group, *pp, MDB_TEMPORARY);
60 +       p = br_multicast_new_port_group(port, group, *pp, MDB_TEMPORARY, src);
61         if (unlikely(!p))
62                 goto err;
63         rcu_assign_pointer(*pp, p);
64 @@ -707,7 +729,7 @@ err:
65  static int br_ip4_multicast_add_group(struct net_bridge *br,
66                                       struct net_bridge_port *port,
67                                       __be32 group,
68 -                                     __u16 vid)
69 +                                     __u16 vid, const unsigned char *src)
70  {
71         struct br_ip br_group;
72  
73 @@ -718,14 +740,14 @@ static int br_ip4_multicast_add_group(st
74         br_group.proto = htons(ETH_P_IP);
75         br_group.vid = vid;
76  
77 -       return br_multicast_add_group(br, port, &br_group);
78 +       return br_multicast_add_group(br, port, &br_group, src);
79  }
80  
81  #if IS_ENABLED(CONFIG_IPV6)
82  static int br_ip6_multicast_add_group(struct net_bridge *br,
83                                       struct net_bridge_port *port,
84                                       const struct in6_addr *group,
85 -                                     __u16 vid)
86 +                                     __u16 vid, const unsigned char *src)
87  {
88         struct br_ip br_group;
89  
90 @@ -736,7 +758,7 @@ static int br_ip6_multicast_add_group(st
91         br_group.proto = htons(ETH_P_IPV6);
92         br_group.vid = vid;
93  
94 -       return br_multicast_add_group(br, port, &br_group);
95 +       return br_multicast_add_group(br, port, &br_group, src);
96  }
97  #endif
98  
99 @@ -966,6 +988,7 @@ static int br_ip4_multicast_igmp3_report
100                                          struct sk_buff *skb,
101                                          u16 vid)
102  {
103 +       const unsigned char *src = eth_hdr(skb)->h_source;
104         struct igmpv3_report *ih;
105         struct igmpv3_grec *grec;
106         int i;
107 @@ -1009,7 +1032,7 @@ static int br_ip4_multicast_igmp3_report
108                         continue;
109                 }
110  
111 -               err = br_ip4_multicast_add_group(br, port, group, vid);
112 +               err = br_ip4_multicast_add_group(br, port, group, vid, src);
113                 if (err)
114                         break;
115         }
116 @@ -1023,6 +1046,7 @@ static int br_ip6_multicast_mld2_report(
117                                         struct sk_buff *skb,
118                                         u16 vid)
119  {
120 +       const unsigned char *src = eth_hdr(skb)->h_source;
121         struct icmp6hdr *icmp6h;
122         struct mld2_grec *grec;
123         int i;
124 @@ -1071,7 +1095,7 @@ static int br_ip6_multicast_mld2_report(
125                 }
126  
127                 err = br_ip6_multicast_add_group(br, port, &grec->grec_mca,
128 -                                                vid);
129 +                                                vid, src);
130                 if (!err)
131                         break;
132         }
133 @@ -1408,7 +1432,8 @@ br_multicast_leave_group(struct net_brid
134                          struct net_bridge_port *port,
135                          struct br_ip *group,
136                          struct bridge_mcast_other_query *other_query,
137 -                        struct bridge_mcast_own_query *own_query)
138 +                        struct bridge_mcast_own_query *own_query,
139 +                        const unsigned char *src)
140  {
141         struct net_bridge_mdb_htable *mdb;
142         struct net_bridge_mdb_entry *mp;
143 @@ -1458,7 +1483,7 @@ br_multicast_leave_group(struct net_brid
144                 for (pp = &mp->ports;
145                      (p = mlock_dereference(*pp, br)) != NULL;
146                      pp = &p->next) {
147 -                       if (p->port != port)
148 +                       if (!br_port_group_equal(p, port, src))
149                                 continue;
150  
151                         rcu_assign_pointer(*pp, p->next);
152 @@ -1492,7 +1517,7 @@ br_multicast_leave_group(struct net_brid
153         for (p = mlock_dereference(mp->ports, br);
154              p != NULL;
155              p = mlock_dereference(p->next, br)) {
156 -               if (p->port != port)
157 +               if (!br_port_group_equal(p, port, src))
158                         continue;
159  
160                 if (!hlist_unhashed(&p->mglist) &&
161 @@ -1510,8 +1535,8 @@ out:
162  
163  static void br_ip4_multicast_leave_group(struct net_bridge *br,
164                                          struct net_bridge_port *port,
165 -                                        __be32 group,
166 -                                        __u16 vid)
167 +                                        __be32 group, __u16 vid,
168 +                                        const unsigned char *src)
169  {
170         struct br_ip br_group;
171         struct bridge_mcast_own_query *own_query;
172 @@ -1526,14 +1551,14 @@ static void br_ip4_multicast_leave_group
173         br_group.vid = vid;
174  
175         br_multicast_leave_group(br, port, &br_group, &br->ip4_other_query,
176 -                                own_query);
177 +                                own_query, src);
178  }
179  
180  #if IS_ENABLED(CONFIG_IPV6)
181  static void br_ip6_multicast_leave_group(struct net_bridge *br,
182                                          struct net_bridge_port *port,
183                                          const struct in6_addr *group,
184 -                                        __u16 vid)
185 +                                        __u16 vid, const unsigned char *src)
186  {
187         struct br_ip br_group;
188         struct bridge_mcast_own_query *own_query;
189 @@ -1548,7 +1573,7 @@ static void br_ip6_multicast_leave_group
190         br_group.vid = vid;
191  
192         br_multicast_leave_group(br, port, &br_group, &br->ip6_other_query,
193 -                                own_query);
194 +                                own_query, src);
195  }
196  #endif
197  
198 @@ -1557,6 +1582,7 @@ static int br_multicast_ipv4_rcv(struct
199                                  struct sk_buff *skb,
200                                  u16 vid)
201  {
202 +       const unsigned char *src = eth_hdr(skb)->h_source;
203         struct sk_buff *skb2 = skb;
204         const struct iphdr *iph;
205         struct igmphdr *ih;
206 @@ -1630,7 +1656,7 @@ static int br_multicast_ipv4_rcv(struct
207         case IGMP_HOST_MEMBERSHIP_REPORT:
208         case IGMPV2_HOST_MEMBERSHIP_REPORT:
209                 BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
210 -               err = br_ip4_multicast_add_group(br, port, ih->group, vid);
211 +               err = br_ip4_multicast_add_group(br, port, ih->group, vid, src);
212                 break;
213         case IGMPV3_HOST_MEMBERSHIP_REPORT:
214                 err = br_ip4_multicast_igmp3_report(br, port, skb2, vid);
215 @@ -1639,7 +1665,7 @@ static int br_multicast_ipv4_rcv(struct
216                 err = br_ip4_multicast_query(br, port, skb2, vid);
217                 break;
218         case IGMP_HOST_LEAVE_MESSAGE:
219 -               br_ip4_multicast_leave_group(br, port, ih->group, vid);
220 +               br_ip4_multicast_leave_group(br, port, ih->group, vid, src);
221                 break;
222         }
223  
224 @@ -1657,6 +1683,7 @@ static int br_multicast_ipv6_rcv(struct
225                                  struct sk_buff *skb,
226                                  u16 vid)
227  {
228 +       const unsigned char *src = eth_hdr(skb)->h_source;
229         struct sk_buff *skb2;
230         const struct ipv6hdr *ip6h;
231         u8 icmp6_type;
232 @@ -1766,7 +1793,8 @@ static int br_multicast_ipv6_rcv(struct
233                 }
234                 mld = (struct mld_msg *)skb_transport_header(skb2);
235                 BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
236 -               err = br_ip6_multicast_add_group(br, port, &mld->mld_mca, vid);
237 +               err = br_ip6_multicast_add_group(br, port, &mld->mld_mca, vid,
238 +                                                src);
239                 break;
240             }
241         case ICMPV6_MLD2_REPORT:
242 @@ -1783,7 +1811,7 @@ static int br_multicast_ipv6_rcv(struct
243                         goto out;
244                 }
245                 mld = (struct mld_msg *)skb_transport_header(skb2);
246 -               br_ip6_multicast_leave_group(br, port, &mld->mld_mca, vid);
247 +               br_ip6_multicast_leave_group(br, port, &mld->mld_mca, vid, src);
248             }
249         }
250  
251 --- a/net/bridge/br_private.h
252 +++ b/net/bridge/br_private.h
253 @@ -112,6 +112,9 @@ struct net_bridge_port_group {
254         struct timer_list               timer;
255         struct br_ip                    addr;
256         unsigned char                   state;
257 +
258 +       unsigned char                   eth_addr[ETH_ALEN];
259 +       bool                            unicast;
260  };
261  
262  struct net_bridge_mdb_entry
263 @@ -173,6 +176,7 @@ struct net_bridge_port
264  #define BR_AUTO_MASK (BR_FLOOD | BR_LEARNING)
265  #define BR_PROMISC             0x00000080
266  #define BR_ISOLATE_MODE                0x00000100
267 +#define BR_MULTICAST_TO_UCAST  0x00000200
268  
269  #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
270         struct bridge_mcast_own_query   ip4_own_query;
271 @@ -485,7 +489,8 @@ void br_multicast_free_pg(struct rcu_hea
272  struct net_bridge_port_group *
273  br_multicast_new_port_group(struct net_bridge_port *port, struct br_ip *group,
274                             struct net_bridge_port_group __rcu *next,
275 -                           unsigned char state);
276 +                           unsigned char state,
277 +                      const unsigned char *src);
278  void br_mdb_init(void);
279  void br_mdb_uninit(void);
280  void br_mdb_notify(struct net_device *dev, struct net_bridge_port *port,
281 --- a/net/bridge/br_mdb.c
282 +++ b/net/bridge/br_mdb.c
283 @@ -342,7 +342,7 @@ static int br_mdb_add_group(struct net_b
284                         break;
285         }
286  
287 -       p = br_multicast_new_port_group(port, group, *pp, state);
288 +       p = br_multicast_new_port_group(port, group, *pp, state, NULL);
289         if (unlikely(!p))
290                 return -ENOMEM;
291         rcu_assign_pointer(*pp, p);
292 --- a/net/bridge/br_forward.c
293 +++ b/net/bridge/br_forward.c
294 @@ -167,6 +167,29 @@ out:
295         return p;
296  }
297  
298 +static struct net_bridge_port *maybe_deliver_addr(
299 +       struct net_bridge_port *prev, struct net_bridge_port *p,
300 +       struct sk_buff *skb, const unsigned char *addr,
301 +       void (*__packet_hook)(const struct net_bridge_port *p,
302 +                             struct sk_buff *skb))
303 +{
304 +       struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
305 +
306 +       if (!should_deliver(p, skb))
307 +               return prev;
308 +
309 +       skb = skb_copy(skb, GFP_ATOMIC);
310 +       if (!skb) {
311 +               dev->stats.tx_dropped++;
312 +               return prev;
313 +       }
314 +
315 +       memcpy(eth_hdr(skb)->h_dest, addr, ETH_ALEN);
316 +       __packet_hook(p, skb);
317 +
318 +       return prev;
319 +}
320 +
321  /* called under bridge lock */
322  static void br_flood(struct net_bridge *br, struct sk_buff *skb,
323                      struct sk_buff *skb0,
324 @@ -231,6 +254,7 @@ static void br_multicast_flood(struct ne
325         struct net_bridge_port *prev = NULL;
326         struct net_bridge_port_group *p;
327         struct hlist_node *rp;
328 +       const unsigned char *addr;
329  
330         rp = rcu_dereference(hlist_first_rcu(&br->router_list));
331         p = mdst ? rcu_dereference(mdst->ports) : NULL;
332 @@ -241,10 +265,19 @@ static void br_multicast_flood(struct ne
333                 rport = rp ? hlist_entry(rp, struct net_bridge_port, rlist) :
334                              NULL;
335  
336 -               port = (unsigned long)lport > (unsigned long)rport ?
337 -                      lport : rport;
338 -
339 -               prev = maybe_deliver(prev, port, skb, __packet_hook);
340 +               if ((unsigned long)lport > (unsigned long)rport) {
341 +                       port = lport;
342 +                       addr = p->unicast ? p->eth_addr : NULL;
343 +               } else {
344 +                       port = rport;
345 +                       addr = NULL;
346 +               }
347 +
348 +               if (addr)
349 +                       prev = maybe_deliver_addr(prev, port, skb, addr,
350 +                                                 __packet_hook);
351 +               else
352 +                       prev = maybe_deliver(prev, port, skb, __packet_hook);
353                 if (IS_ERR(prev))
354                         goto out;
355  
356 --- a/net/bridge/br_sysfs_if.c
357 +++ b/net/bridge/br_sysfs_if.c
358 @@ -202,6 +202,7 @@ static BRPORT_ATTR(multicast_router, S_I
359                    store_multicast_router);
360  
361  BRPORT_ATTR_FLAG(multicast_fast_leave, BR_MULTICAST_FAST_LEAVE);
362 +BRPORT_ATTR_FLAG(multicast_to_unicast, BR_MULTICAST_TO_UCAST);
363  #endif
364  
365  static const struct brport_attribute *brport_attrs[] = {
366 @@ -228,6 +229,7 @@ static const struct brport_attribute *br
367  #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
368         &brport_attr_multicast_router,
369         &brport_attr_multicast_fast_leave,
370 +       &brport_attr_multicast_to_unicast,
371  #endif
372         &brport_attr_isolate_mode,
373         NULL