History

bridge: simplify ip_mc_check_igmp() and ipv6_mc_check_mld() calls

This patch refactors ip_mc_check_igmp(), ipv6_mc_check_mld() and their callers (more precisely, the Linux bridge) to not rely on the skb_trimmed parameter anymore. An skb with its tail trimmed to the IP packet length was initially introduced for the following three reasons: 1) To be able to verify the ICMPv6 checksum. 2) To be able to distinguish the version of an IGMP or MLD query. They are distinguishable only by their size. 3) To avoid parsing data for an IGMPv3 or MLDv2 report that is beyond the IP packet but still within the skb. The first case still uses a cloned and potentially trimmed skb to verfiy. However, there is no need to propagate it to the caller. For the second and third case explicit IP packet length checks were added. This hopefully makes ip_mc_check_igmp() and ipv6_mc_check_mld() easier to read and verfiy, as well as easier to use.

Linus Lüssing committed 7 years ago

Commit ba5ea611 parent 6679cf08 files · +70 −72Browse files

Unified · Split

8 files
  1. include/linux/igmp.h +10 −1
  2. include/linux/ip.h +5 −0
  3. include/linux/ipv6.h +6 −0
  4. include/net/addrconf.h +11 −1
  5. net/batman-adv/multicast.c +2 −2
  6. net/bridge/br_multicast.c +28 −29
  7. net/ipv4/igmp.c +4 −19
  8. net/ipv6/mcast_snoop.c +4 −20
include/linux/igmp.h+10−1
@@ -18,6 +18,7 @@ · 17 unmodified lines
18#include <linux/skbuff.h>18#include <linux/skbuff.h>
19#include <linux/timer.h>19#include <linux/timer.h>
20#include <linux/in.h>20#include <linux/in.h>
21#include <linux/ip.h>
21#include <linux/refcount.h>22#include <linux/refcount.h>
22#include <uapi/linux/igmp.h>23#include <uapi/linux/igmp.h>
23 24
@@ -106,6 +107,14 @@ struct ip_mc_list { · 82 unmodified lines
106#define IGMPV3_QQIC(value) IGMPV3_EXP(0x80, 4, 3, value)107#define IGMPV3_QQIC(value) IGMPV3_EXP(0x80, 4, 3, value)
107#define IGMPV3_MRC(value) IGMPV3_EXP(0x80, 4, 3, value)108#define IGMPV3_MRC(value) IGMPV3_EXP(0x80, 4, 3, value)
108 109
110static inline int ip_mc_may_pull(struct sk_buff *skb, unsigned int len)
111{
112 if (skb_transport_offset(skb) + ip_transport_len(skb) < len)
113 return -EINVAL;
114
115 return pskb_may_pull(skb, len);
116}
117
109extern int ip_check_mc_rcu(struct in_device *dev, __be32 mc_addr, __be32 src_addr, u8 proto);118extern int ip_check_mc_rcu(struct in_device *dev, __be32 mc_addr, __be32 src_addr, u8 proto);
110extern int igmp_rcv(struct sk_buff *);119extern int igmp_rcv(struct sk_buff *);
111extern int ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr);120extern int ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr);
@@ -130,6 +139,6 @@ extern void ip_mc_unmap(struct in_device *); · 18 unmodified lines
130extern void ip_mc_remap(struct in_device *);139extern void ip_mc_remap(struct in_device *);
131extern void ip_mc_dec_group(struct in_device *in_dev, __be32 addr);140extern void ip_mc_dec_group(struct in_device *in_dev, __be32 addr);
132extern void ip_mc_inc_group(struct in_device *in_dev, __be32 addr);141extern void ip_mc_inc_group(struct in_device *in_dev, __be32 addr);
133int ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed);142int ip_mc_check_igmp(struct sk_buff *skb);
134 143
135#endif144#endif
include/linux/ip.h+5−0
@@ -34,4 +34,9 @@ static inline struct iphdr *ipip_hdr(const struct sk_buff *skb) · 33 unmodified lines
34{34{
35 return (struct iphdr *)skb_transport_header(skb);35 return (struct iphdr *)skb_transport_header(skb);
36}36}
37
38static inline unsigned int ip_transport_len(const struct sk_buff *skb)
39{
40 return ntohs(ip_hdr(skb)->tot_len) - skb_network_header_len(skb);
41}
37#endif /* _LINUX_IP_H */42#endif /* _LINUX_IP_H */
include/linux/ipv6.h+6−0
@@ -104,6 +104,12 @@ static inline struct ipv6hdr *ipipv6_hdr(const struct sk_buff *skb) · 103 unmodified lines
104 return (struct ipv6hdr *)skb_transport_header(skb);104 return (struct ipv6hdr *)skb_transport_header(skb);
105}105}
106 106
107static inline unsigned int ipv6_transport_len(const struct sk_buff *skb)
108{
109 return ntohs(ipv6_hdr(skb)->payload_len) + sizeof(struct ipv6hdr) -
110 skb_network_header_len(skb);
111}
112
107/* 113/*
108 This structure contains results of exthdrs parsing114 This structure contains results of exthdrs parsing
109 as offsets from skb->nh.115 as offsets from skb->nh.
include/net/addrconf.h+11−1
@@ -49,6 +49,7 @@ struct prefix_info { · 48 unmodified lines
49 struct in6_addr prefix;49 struct in6_addr prefix;
50};50};
51 51
52#include <linux/ipv6.h>
52#include <linux/netdevice.h>53#include <linux/netdevice.h>
53#include <net/if_inet6.h>54#include <net/if_inet6.h>
54#include <net/ipv6.h>55#include <net/ipv6.h>
@@ -201,6 +202,15 @@ u32 ipv6_addr_label(struct net *net, const struct in6_addr *addr, · 146 unmodified lines
201/*202/*
202 * multicast prototypes (mcast.c)203 * multicast prototypes (mcast.c)
203 */204 */
205static inline int ipv6_mc_may_pull(struct sk_buff *skb,
206 unsigned int len)
207{
208 if (skb_transport_offset(skb) + ipv6_transport_len(skb) < len)
209 return -EINVAL;
210
211 return pskb_may_pull(skb, len);
212}
213
204int ipv6_sock_mc_join(struct sock *sk, int ifindex,214int ipv6_sock_mc_join(struct sock *sk, int ifindex,
205 const struct in6_addr *addr);215 const struct in6_addr *addr);
206int ipv6_sock_mc_drop(struct sock *sk, int ifindex,216int ipv6_sock_mc_drop(struct sock *sk, int ifindex,
@@ -219,7 +229,7 @@ void ipv6_mc_unmap(struct inet6_dev *idev); · 12 unmodified lines
219void ipv6_mc_remap(struct inet6_dev *idev);229void ipv6_mc_remap(struct inet6_dev *idev);
220void ipv6_mc_init_dev(struct inet6_dev *idev);230void ipv6_mc_init_dev(struct inet6_dev *idev);
221void ipv6_mc_destroy_dev(struct inet6_dev *idev);231void ipv6_mc_destroy_dev(struct inet6_dev *idev);
222int ipv6_mc_check_mld(struct sk_buff *skb, struct sk_buff **skb_trimmed);232int ipv6_mc_check_mld(struct sk_buff *skb);
223void addrconf_dad_failure(struct sk_buff *skb, struct inet6_ifaddr *ifp);233void addrconf_dad_failure(struct sk_buff *skb, struct inet6_ifaddr *ifp);
224 234
225bool ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group,235bool ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group,
net/batman-adv/multicast.c+2−2
@@ -674,7 +674,7 @@ static void batadv_mcast_mla_update(struct work_struct *work) · 673 unmodified lines
674 */674 */
675static bool batadv_mcast_is_report_ipv4(struct sk_buff *skb)675static bool batadv_mcast_is_report_ipv4(struct sk_buff *skb)
676{676{
677 if (ip_mc_check_igmp(skb, NULL) < 0)677 if (ip_mc_check_igmp(skb) < 0)
678 return false;678 return false;
679 679
680 switch (igmp_hdr(skb)->type) {680 switch (igmp_hdr(skb)->type) {
@@ -741,7 +741,7 @@ static int batadv_mcast_forw_mode_check_ipv4(struct batadv_priv *bat_priv, · 60 unmodified lines
741 */741 */
742static bool batadv_mcast_is_report_ipv6(struct sk_buff *skb)742static bool batadv_mcast_is_report_ipv6(struct sk_buff *skb)
743{743{
744 if (ipv6_mc_check_mld(skb, NULL) < 0)744 if (ipv6_mc_check_mld(skb) < 0)
745 return false;745 return false;
746 746
747 switch (icmp6_hdr(skb)->icmp6_type) {747 switch (icmp6_hdr(skb)->icmp6_type) {
net/bridge/br_multicast.c+28−29
@@ -938,7 +938,7 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge *br, · 937 unmodified lines
938 938
939 for (i = 0; i < num; i++) {939 for (i = 0; i < num; i++) {
940 len += sizeof(*grec);940 len += sizeof(*grec);
941 if (!pskb_may_pull(skb, len))941 if (!ip_mc_may_pull(skb, len))
942 return -EINVAL;942 return -EINVAL;
943 943
944 grec = (void *)(skb->data + len - sizeof(*grec));944 grec = (void *)(skb->data + len - sizeof(*grec));
@@ -946,7 +946,7 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge *br, · 1 unmodified line
946 type = grec->grec_type;946 type = grec->grec_type;
947 947
948 len += ntohs(grec->grec_nsrcs) * 4;948 len += ntohs(grec->grec_nsrcs) * 4;
949 if (!pskb_may_pull(skb, len))949 if (!ip_mc_may_pull(skb, len))
950 return -EINVAL;950 return -EINVAL;
951 951
952 /* We treat this as an IGMPv2 report for now. */952 /* We treat this as an IGMPv2 report for now. */
@@ -985,15 +985,17 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br, · 32 unmodified lines
985 struct sk_buff *skb,985 struct sk_buff *skb,
986 u16 vid)986 u16 vid)
987{987{
988 unsigned int nsrcs_offset;
988 const unsigned char *src;989 const unsigned char *src;
989 struct icmp6hdr *icmp6h;990 struct icmp6hdr *icmp6h;
990 struct mld2_grec *grec;991 struct mld2_grec *grec;
992 unsigned int grec_len;
991 int i;993 int i;
992 int len;994 int len;
993 int num;995 int num;
994 int err = 0;996 int err = 0;
995 997
996 if (!pskb_may_pull(skb, sizeof(*icmp6h)))998 if (!ipv6_mc_may_pull(skb, sizeof(*icmp6h)))
997 return -EINVAL;999 return -EINVAL;
998 1000
999 icmp6h = icmp6_hdr(skb);1001 icmp6h = icmp6_hdr(skb);
@@ -1003,21 +1005,25 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br, · 3 unmodified lines
1003 for (i = 0; i < num; i++) {1005 for (i = 0; i < num; i++) {
1004 __be16 *nsrcs, _nsrcs;1006 __be16 *nsrcs, _nsrcs;
1005 1007
1006 nsrcs = skb_header_pointer(skb,1008 nsrcs_offset = len + offsetof(struct mld2_grec, grec_nsrcs);
1007 len + offsetof(struct mld2_grec,1009
1008 grec_nsrcs),1010 if (skb_transport_offset(skb) + ipv6_transport_len(skb) <
1011 nsrcs_offset + sizeof(_nsrcs))
1012 return -EINVAL;
1013
1014 nsrcs = skb_header_pointer(skb, nsrcs_offset,
1009 sizeof(_nsrcs), &_nsrcs);1015 sizeof(_nsrcs), &_nsrcs);
1010 if (!nsrcs)1016 if (!nsrcs)
1011 return -EINVAL;1017 return -EINVAL;
1012 1018
1013 if (!pskb_may_pull(skb,1019 grec_len = sizeof(*grec) +
1014 len + sizeof(*grec) +1020 sizeof(struct in6_addr) * ntohs(*nsrcs);
1015 sizeof(struct in6_addr) * ntohs(*nsrcs)))1021
1022 if (!ipv6_mc_may_pull(skb, len + grec_len))
1016 return -EINVAL;1023 return -EINVAL;
1017 1024
1018 grec = (struct mld2_grec *)(skb->data + len);1025 grec = (struct mld2_grec *)(skb->data + len);
1019 len += sizeof(*grec) +1026 len += grec_len;
1020 sizeof(struct in6_addr) * ntohs(*nsrcs);
1021 1027
1022 /* We treat these as MLDv1 reports for now. */1028 /* We treat these as MLDv1 reports for now. */
1023 switch (grec->grec_type) {1029 switch (grec->grec_type) {
@@ -1219,6 +1225,7 @@ static void br_ip4_multicast_query(struct net_bridge *br, · 195 unmodified lines
1219 struct sk_buff *skb,1225 struct sk_buff *skb,
1220 u16 vid)1226 u16 vid)
1221{1227{
1228 unsigned int transport_len = ip_transport_len(skb);
1222 const struct iphdr *iph = ip_hdr(skb);1229 const struct iphdr *iph = ip_hdr(skb);
1223 struct igmphdr *ih = igmp_hdr(skb);1230 struct igmphdr *ih = igmp_hdr(skb);
1224 struct net_bridge_mdb_entry *mp;1231 struct net_bridge_mdb_entry *mp;
@@ -1228,7 +1235,6 @@ static void br_ip4_multicast_query(struct net_bridge *br, · 3 unmodified lines
1228 struct br_ip saddr;1235 struct br_ip saddr;
1229 unsigned long max_delay;1236 unsigned long max_delay;
1230 unsigned long now = jiffies;1237 unsigned long now = jiffies;
1231 unsigned int offset = skb_transport_offset(skb);
1232 __be32 group;1238 __be32 group;
1233 1239
1234 spin_lock(&br->multicast_lock);1240 spin_lock(&br->multicast_lock);
@@ -1238,14 +1244,14 @@ static void br_ip4_multicast_query(struct net_bridge *br, · 3 unmodified lines
1238 1244
1239 group = ih->group;1245 group = ih->group;
1240 1246
1241 if (skb->len == offset + sizeof(*ih)) {1247 if (transport_len == sizeof(*ih)) {
1242 max_delay = ih->code * (HZ / IGMP_TIMER_SCALE);1248 max_delay = ih->code * (HZ / IGMP_TIMER_SCALE);
1243 1249
1244 if (!max_delay) {1250 if (!max_delay) {
1245 max_delay = 10 * HZ;1251 max_delay = 10 * HZ;
1246 group = 0;1252 group = 0;
1247 }1253 }
1248 } else if (skb->len >= offset + sizeof(*ih3)) {1254 } else if (transport_len >= sizeof(*ih3)) {
1249 ih3 = igmpv3_query_hdr(skb);1255 ih3 = igmpv3_query_hdr(skb);
1250 if (ih3->nsrcs)1256 if (ih3->nsrcs)
1251 goto out;1257 goto out;
@@ -1296,6 +1302,7 @@ static int br_ip6_multicast_query(struct net_bridge *br, · 44 unmodified lines
1296 struct sk_buff *skb,1302 struct sk_buff *skb,
1297 u16 vid)1303 u16 vid)
1298{1304{
1305 unsigned int transport_len = ipv6_transport_len(skb);
1299 const struct ipv6hdr *ip6h = ipv6_hdr(skb);1306 const struct ipv6hdr *ip6h = ipv6_hdr(skb);
1300 struct mld_msg *mld;1307 struct mld_msg *mld;
1301 struct net_bridge_mdb_entry *mp;1308 struct net_bridge_mdb_entry *mp;
@@ -1315,7 +1322,7 @@ static int br_ip6_multicast_query(struct net_bridge *br, · 13 unmodified lines
1315 (port && port->state == BR_STATE_DISABLED))1322 (port && port->state == BR_STATE_DISABLED))
1316 goto out;1323 goto out;
1317 1324
1318 if (skb->len == offset + sizeof(*mld)) {1325 if (transport_len == sizeof(*mld)) {
1319 if (!pskb_may_pull(skb, offset + sizeof(*mld))) {1326 if (!pskb_may_pull(skb, offset + sizeof(*mld))) {
1320 err = -EINVAL;1327 err = -EINVAL;
1321 goto out;1328 goto out;
@@ -1581,12 +1588,11 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br, · 259 unmodified lines
1581 struct sk_buff *skb,1588 struct sk_buff *skb,
1582 u16 vid)1589 u16 vid)
1583{1590{
1584 struct sk_buff *skb_trimmed = NULL;
1585 const unsigned char *src;1591 const unsigned char *src;
1586 struct igmphdr *ih;1592 struct igmphdr *ih;
1587 int err;1593 int err;
1588 1594
1589 err = ip_mc_check_igmp(skb, &skb_trimmed);1595 err = ip_mc_check_igmp(skb);
1590 1596
1591 if (err == -ENOMSG) {1597 if (err == -ENOMSG) {
1592 if (!ipv4_is_local_multicast(ip_hdr(skb)->daddr)) {1598 if (!ipv4_is_local_multicast(ip_hdr(skb)->daddr)) {
@@ -1612,19 +1618,16 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br, · 19 unmodified lines
1612 err = br_ip4_multicast_add_group(br, port, ih->group, vid, src);1618 err = br_ip4_multicast_add_group(br, port, ih->group, vid, src);
1613 break;1619 break;
1614 case IGMPV3_HOST_MEMBERSHIP_REPORT:1620 case IGMPV3_HOST_MEMBERSHIP_REPORT:
1615 err = br_ip4_multicast_igmp3_report(br, port, skb_trimmed, vid);1621 err = br_ip4_multicast_igmp3_report(br, port, skb, vid);
1616 break;1622 break;
1617 case IGMP_HOST_MEMBERSHIP_QUERY:1623 case IGMP_HOST_MEMBERSHIP_QUERY:
1618 br_ip4_multicast_query(br, port, skb_trimmed, vid);1624 br_ip4_multicast_query(br, port, skb, vid);
1619 break;1625 break;
1620 case IGMP_HOST_LEAVE_MESSAGE:1626 case IGMP_HOST_LEAVE_MESSAGE:
1621 br_ip4_multicast_leave_group(br, port, ih->group, vid, src);1627 br_ip4_multicast_leave_group(br, port, ih->group, vid, src);
1622 break;1628 break;
1623 }1629 }
1624 1630
1625 if (skb_trimmed && skb_trimmed != skb)
1626 kfree_skb(skb_trimmed);
1627
1628 br_multicast_count(br, port, skb, BR_INPUT_SKB_CB(skb)->igmp,1631 br_multicast_count(br, port, skb, BR_INPUT_SKB_CB(skb)->igmp,
1629 BR_MCAST_DIR_RX);1632 BR_MCAST_DIR_RX);
1630 1633
@@ -1637,12 +1640,11 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br, · 6 unmodified lines
1637 struct sk_buff *skb,1640 struct sk_buff *skb,
1638 u16 vid)1641 u16 vid)
1639{1642{
1640 struct sk_buff *skb_trimmed = NULL;
1641 const unsigned char *src;1643 const unsigned char *src;
1642 struct mld_msg *mld;1644 struct mld_msg *mld;
1643 int err;1645 int err;
1644 1646
1645 err = ipv6_mc_check_mld(skb, &skb_trimmed);1647 err = ipv6_mc_check_mld(skb);
1646 1648
1647 if (err == -ENOMSG) {1649 if (err == -ENOMSG) {
1648 if (!ipv6_addr_is_ll_all_nodes(&ipv6_hdr(skb)->daddr))1650 if (!ipv6_addr_is_ll_all_nodes(&ipv6_hdr(skb)->daddr))
@@ -1664,10 +1666,10 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br, · 15 unmodified lines
1664 src);1666 src);
1665 break;1667 break;
1666 case ICMPV6_MLD2_REPORT:1668 case ICMPV6_MLD2_REPORT:
1667 err = br_ip6_multicast_mld2_report(br, port, skb_trimmed, vid);1669 err = br_ip6_multicast_mld2_report(br, port, skb, vid);
1668 break;1670 break;
1669 case ICMPV6_MGM_QUERY:1671 case ICMPV6_MGM_QUERY:
1670 err = br_ip6_multicast_query(br, port, skb_trimmed, vid);1672 err = br_ip6_multicast_query(br, port, skb, vid);
1671 break;1673 break;
1672 case ICMPV6_MGM_REDUCTION:1674 case ICMPV6_MGM_REDUCTION:
1673 src = eth_hdr(skb)->h_source;1675 src = eth_hdr(skb)->h_source;
@@ -1675,9 +1677,6 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br, · 1 unmodified line
1675 break;1677 break;
1676 }1678 }
1677 1679
1678 if (skb_trimmed && skb_trimmed != skb)
1679 kfree_skb(skb_trimmed);
1680
1681 br_multicast_count(br, port, skb, BR_INPUT_SKB_CB(skb)->igmp,1680 br_multicast_count(br, port, skb, BR_INPUT_SKB_CB(skb)->igmp,
1682 BR_MCAST_DIR_RX);1681 BR_MCAST_DIR_RX);
1683 1682
net/ipv4/igmp.c+4−19
@@ -1544,7 +1544,7 @@ static inline __sum16 ip_mc_validate_checksum(struct sk_buff *skb) · 1543 unmodified lines
1544 return skb_checksum_simple_validate(skb);1544 return skb_checksum_simple_validate(skb);
1545}1545}
1546 1546
1547static int __ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed)1547static int __ip_mc_check_igmp(struct sk_buff *skb)
1548 1548
1549{1549{
1550 struct sk_buff *skb_chk;1550 struct sk_buff *skb_chk;
@@ -1566,16 +1566,10 @@ static int __ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed) · 15 unmodified lines
1566 if (ret)1566 if (ret)
1567 goto err;1567 goto err;
1568 1568
1569 if (skb_trimmed)
1570 *skb_trimmed = skb_chk;
1571 /* free now unneeded clone */
1572 else if (skb_chk != skb)
1573 kfree_skb(skb_chk);
1574
1575 ret = 0;1569 ret = 0;
1576 1570
1577err:1571err:
1578 if (ret && skb_chk && skb_chk != skb)1572 if (skb_chk && skb_chk != skb)
1579 kfree_skb(skb_chk);1573 kfree_skb(skb_chk);
1580 1574
1581 return ret;1575 return ret;
@@ -1584,7 +1578,6 @@ err: · 2 unmodified lines
1584/**1578/**
1585 * ip_mc_check_igmp - checks whether this is a sane IGMP packet1579 * ip_mc_check_igmp - checks whether this is a sane IGMP packet
1586 * @skb: the skb to validate1580 * @skb: the skb to validate
1587 * @skb_trimmed: to store an skb pointer trimmed to IPv4 packet tail (optional)
1588 *1581 *
1589 * Checks whether an IPv4 packet is a valid IGMP packet. If so sets1582 * Checks whether an IPv4 packet is a valid IGMP packet. If so sets
1590 * skb transport header accordingly and returns zero.1583 * skb transport header accordingly and returns zero.
@@ -1594,18 +1587,10 @@ err: · 3 unmodified lines
1594 * -ENOMSG: IP header validation succeeded but it is not an IGMP packet.1587 * -ENOMSG: IP header validation succeeded but it is not an IGMP packet.
1595 * -ENOMEM: A memory allocation failure happened.1588 * -ENOMEM: A memory allocation failure happened.
1596 *1589 *
1597 * Optionally, an skb pointer might be provided via skb_trimmed (or set it
1598 * to NULL): After parsing an IGMP packet successfully it will point to
1599 * an skb which has its tail aligned to the IP packet end. This might
1600 * either be the originally provided skb or a trimmed, cloned version if
1601 * the skb frame had data beyond the IP packet. A cloned skb allows us
1602 * to leave the original skb and its full frame unchanged (which might be
1603 * desirable for layer 2 frame jugglers).
1604 *
1605 * Caller needs to set the skb network header and free any returned skb if it1590 * Caller needs to set the skb network header and free any returned skb if it
1606 * differs from the provided skb.1591 * differs from the provided skb.
1607 */1592 */
1608int ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed)1593int ip_mc_check_igmp(struct sk_buff *skb)
1609{1594{
1610 int ret = ip_mc_check_iphdr(skb);1595 int ret = ip_mc_check_iphdr(skb);
1611 1596
@@ -1615,7 +1600,7 @@ int ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed) · 3 unmodified lines
1615 if (ip_hdr(skb)->protocol != IPPROTO_IGMP)1600 if (ip_hdr(skb)->protocol != IPPROTO_IGMP)
1616 return -ENOMSG;1601 return -ENOMSG;
1617 1602
1618 return __ip_mc_check_igmp(skb, skb_trimmed);1603 return __ip_mc_check_igmp(skb);
1619}1604}
1620EXPORT_SYMBOL(ip_mc_check_igmp);1605EXPORT_SYMBOL(ip_mc_check_igmp);
1621 1606
net/ipv6/mcast_snoop.c+4−20
@@ -136,8 +136,7 @@ static inline __sum16 ipv6_mc_validate_checksum(struct sk_buff *skb) · 135 unmodified lines
136 return skb_checksum_validate(skb, IPPROTO_ICMPV6, ip6_compute_pseudo);136 return skb_checksum_validate(skb, IPPROTO_ICMPV6, ip6_compute_pseudo);
137}137}
138 138
139static int __ipv6_mc_check_mld(struct sk_buff *skb,139static int __ipv6_mc_check_mld(struct sk_buff *skb)
140 struct sk_buff **skb_trimmed)
141 140
142{141{
143 struct sk_buff *skb_chk = NULL;142 struct sk_buff *skb_chk = NULL;
@@ -160,16 +159,10 @@ static int __ipv6_mc_check_mld(struct sk_buff *skb, · 16 unmodified lines
160 if (ret)159 if (ret)
161 goto err;160 goto err;
162 161
163 if (skb_trimmed)
164 *skb_trimmed = skb_chk;
165 /* free now unneeded clone */
166 else if (skb_chk != skb)
167 kfree_skb(skb_chk);
168
169 ret = 0;162 ret = 0;
170 163
171err:164err:
172 if (ret && skb_chk && skb_chk != skb)165 if (skb_chk && skb_chk != skb)
173 kfree_skb(skb_chk);166 kfree_skb(skb_chk);
174 167
175 return ret;168 return ret;
@@ -178,7 +171,6 @@ err: · 2 unmodified lines
178/**171/**
179 * ipv6_mc_check_mld - checks whether this is a sane MLD packet172 * ipv6_mc_check_mld - checks whether this is a sane MLD packet
180 * @skb: the skb to validate173 * @skb: the skb to validate
181 * @skb_trimmed: to store an skb pointer trimmed to IPv6 packet tail (optional)
182 *174 *
183 * Checks whether an IPv6 packet is a valid MLD packet. If so sets175 * Checks whether an IPv6 packet is a valid MLD packet. If so sets
184 * skb transport header accordingly and returns zero.176 * skb transport header accordingly and returns zero.
@@ -188,18 +180,10 @@ err: · 3 unmodified lines
188 * -ENOMSG: IP header validation succeeded but it is not an MLD packet.180 * -ENOMSG: IP header validation succeeded but it is not an MLD packet.
189 * -ENOMEM: A memory allocation failure happened.181 * -ENOMEM: A memory allocation failure happened.
190 *182 *
191 * Optionally, an skb pointer might be provided via skb_trimmed (or set it
192 * to NULL): After parsing an MLD packet successfully it will point to
193 * an skb which has its tail aligned to the IP packet end. This might
194 * either be the originally provided skb or a trimmed, cloned version if
195 * the skb frame had data beyond the IP packet. A cloned skb allows us
196 * to leave the original skb and its full frame unchanged (which might be
197 * desirable for layer 2 frame jugglers).
198 *
199 * Caller needs to set the skb network header and free any returned skb if it183 * Caller needs to set the skb network header and free any returned skb if it
200 * differs from the provided skb.184 * differs from the provided skb.
201 */185 */
202int ipv6_mc_check_mld(struct sk_buff *skb, struct sk_buff **skb_trimmed)186int ipv6_mc_check_mld(struct sk_buff *skb)
203{187{
204 int ret;188 int ret;
205 189
@@ -211,6 +195,6 @@ int ipv6_mc_check_mld(struct sk_buff *skb, struct sk_buff **skb_trimmed) · 5 unmodified lines
211 if (ret < 0)195 if (ret < 0)
212 return ret;196 return ret;
213 197
214 return __ipv6_mc_check_mld(skb, skb_trimmed);198 return __ipv6_mc_check_mld(skb);
215}199}
216EXPORT_SYMBOL(ipv6_mc_check_mld);200EXPORT_SYMBOL(ipv6_mc_check_mld);