summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@home.transmeta.com>2003-04-22 22:50:53 -0700
committerLinus Torvalds <torvalds@home.transmeta.com>2003-04-22 22:50:53 -0700
commit70ced8bfb70ae687cd39c3ffc047cd345c4bb00f (patch)
treebf3de613a67e818253a6415abe4d51606d70d3e8
parentb3d4c0270080c88e41704740ff9f413ce4067715 (diff)
parent6febb77650e96402767132b69b229fc3ae2f6ca4 (diff)
Merge bk://kernel.bkbits.net/davem/net-2.5
into home.transmeta.com:/home/torvalds/v2.5/linux
-rw-r--r--include/linux/igmp.h8
-rw-r--r--include/linux/net.h3
-rw-r--r--include/net/ip6_route.h2
-rw-r--r--net/core/dev.c10
-rw-r--r--net/core/sock.c13
-rw-r--r--net/ipv4/igmp.c188
-rw-r--r--net/ipv4/ip_output.c2
-rw-r--r--net/ipv4/ip_sockglue.c165
-rw-r--r--net/ipv4/netfilter/Kconfig2
-rw-r--r--net/ipv6/ipv6_sockglue.c12
-rw-r--r--net/ipv6/mcast.c36
-rw-r--r--net/ipv6/ndisc.c6
-rw-r--r--net/ipv6/route.c18
-rw-r--r--net/netlink/af_netlink.c8
-rw-r--r--net/socket.c47
15 files changed, 385 insertions, 135 deletions
diff --git a/include/linux/igmp.h b/include/linux/igmp.h
index 2cc2472d2eb2..8144cabdad06 100644
--- a/include/linux/igmp.h
+++ b/include/linux/igmp.h
@@ -191,7 +191,7 @@ struct ip_mc_list
(IGMPV3_MASK((value) >> (nbmant), nbexp) + (nbexp))))
#define IGMPV3_QQIC(value) IGMPV3_EXP(0x80, 4, 3, value)
-#define IGMPV3_MRC(value) IGMPV3_EXP(0x8000, 12, 3, value)
+#define IGMPV3_MRC(value) IGMPV3_EXP(0x80, 4, 3, value)
extern int ip_check_mc(struct in_device *dev, u32 mc_addr, u32 src_addr, u16 proto);
extern int igmp_rcv(struct sk_buff *);
@@ -199,10 +199,12 @@ extern int ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr);
extern int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr);
extern void ip_mc_drop_socket(struct sock *sk);
extern int ip_mc_source(int add, int omode, struct sock *sk,
- struct ip_mreq_source *mreqs);
-extern int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf);
+ struct ip_mreq_source *mreqs, int ifindex);
+extern int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf,int ifindex);
extern int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf,
struct ip_msfilter *optval, int *optlen);
+extern int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf,
+ struct group_filter *optval, int *optlen);
extern int ip_mc_sf_allow(struct sock *sk, u32 local, u32 rmt, int dif);
extern void ip_mr_init(void);
extern void ip_mc_init_dev(struct in_device *);
diff --git a/include/linux/net.h b/include/linux/net.h
index fc6b655dcdc3..8b012430f49d 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -140,6 +140,9 @@ struct net_proto_family {
struct module *owner;
};
+extern int net_family_get(int family);
+extern void net_family_put(int family);
+
struct iovec;
extern int sock_wake_async(struct socket *sk, int how, int band);
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
index 1a5c99c5afa2..1af054ea6385 100644
--- a/include/net/ip6_route.h
+++ b/include/net/ip6_route.h
@@ -59,7 +59,7 @@ extern struct rt6_info *rt6_lookup(struct in6_addr *daddr,
struct in6_addr *saddr,
int oif, int flags);
-extern struct rt6_info *ndisc_get_dummy_rt(void);
+extern struct rt6_info *ip6_dst_alloc(void);
/*
* support functions for ND
diff --git a/net/core/dev.c b/net/core/dev.c
index b6f627be7b08..9c041e1be73e 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2582,6 +2582,16 @@ int register_netdevice(struct net_device *dev)
if ((ret = kobject_register(&dev->kobj)))
goto out_err;
+ /* Fix illegal SG+CSUM combinations. */
+ if ((dev->features & NETIF_F_SG) &&
+ !(dev->features & (NETIF_F_IP_CSUM |
+ NETIF_F_NO_CSUM |
+ NETIF_F_HW_CSUM))) {
+ printk("%s: Dropping NETIF_F_SG since no checksum feature.\n",
+ dev->name);
+ dev->features &= ~NETIF_F_SG;
+ }
+
/*
* nil rebuild_header routine,
* that should be never called and used as just bug trap.
diff --git a/net/core/sock.c b/net/core/sock.c
index 8c85f0d79a86..29fdc583abe3 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -589,8 +589,10 @@ static kmem_cache_t *sk_cachep;
*/
struct sock *sk_alloc(int family, int priority, int zero_it, kmem_cache_t *slab)
{
- struct sock *sk;
-
+ struct sock *sk = NULL;
+
+ if (!net_family_get(family))
+ goto out;
if (!slab)
slab = sk_cachep;
sk = kmem_cache_alloc(slab, priority);
@@ -602,14 +604,16 @@ struct sock *sk_alloc(int family, int priority, int zero_it, kmem_cache_t *slab)
sock_lock_init(sk);
}
sk->slab = slab;
- }
-
+ } else
+ net_family_put(family);
+out:
return sk;
}
void sk_free(struct sock *sk)
{
struct sk_filter *filter;
+ const int family = sk->family;
if (sk->destruct)
sk->destruct(sk);
@@ -624,6 +628,7 @@ void sk_free(struct sock *sk)
printk(KERN_DEBUG "sk_free: optmem leakage (%d bytes) detected.\n", atomic_read(&sk->omem_alloc));
kmem_cache_free(sk->slab, sk);
+ net_family_put(family);
}
void __init sk_init(void)
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 265eb0604436..680ab028ad69 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -103,6 +103,7 @@
#define IP_MAX_MEMBERSHIPS 20
+#ifdef CONFIG_IP_MULTICAST
/* Parameter names and values are taken from igmp-v2-06 draft */
#define IGMP_V1_Router_Present_Timeout (400*HZ)
@@ -126,13 +127,12 @@
#define IGMP_V2_SEEN(in_dev) ((in_dev)->mr_v2_seen && \
time_before(jiffies, (in_dev)->mr_v2_seen))
-#ifdef CONFIG_MULTICAST
static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im);
-#endif
static void igmpv3_del_delrec(struct in_device *in_dev, __u32 multiaddr);
static void igmpv3_clear_delrec(struct in_device *in_dev);
static int sf_setstate(struct ip_mc_list *pmc);
static void sf_markstate(struct ip_mc_list *pmc);
+#endif
static void ip_mc_clear_src(struct ip_mc_list *pmc);
int ip_mc_add_src(struct in_device *in_dev, __u32 *pmca, int sfmode,
int sfcount, __u32 *psfsrc, int delta);
@@ -770,11 +770,18 @@ static void igmp_heard_query(struct in_device *in_dev, struct igmphdr *ih,
in_dev->mr_v2_seen = jiffies +
IGMP_V2_Router_Present_Timeout;
}
+ /* cancel the interface change timer */
+ in_dev->mr_ifc_count = 0;
+ if (del_timer(&in_dev->mr_ifc_timer))
+ atomic_dec(&in_dev->refcnt);
+ /* clear deleted report items */
igmpv3_clear_delrec(in_dev);
} else if (len < 12) {
return; /* ignore bogus packet; freed by caller */
} else { /* v3 */
max_delay = IGMPV3_MRC(ih3->code)*(HZ/IGMP_TIMER_SCALE);
+ if (!max_delay)
+ max_delay = 1; /* can't mod w/ 0 */
in_dev->mr_maxdelay = max_delay;
if (ih3->qrv)
in_dev->mr_qrv = ih3->qrv;
@@ -951,7 +958,6 @@ static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im)
in_dev->mc_tomb = pmc;
write_unlock_bh(&in_dev->mc_lock);
}
-#endif
static void igmpv3_del_delrec(struct in_device *in_dev, __u32 multiaddr)
{
@@ -997,7 +1003,23 @@ static void igmpv3_clear_delrec(struct in_device *in_dev)
in_dev_put(pmc->interface);
kfree(pmc);
}
+ /* clear dead sources, too */
+ read_lock(&in_dev->lock);
+ for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) {
+ struct ip_sf_list *psf, *psf_next;
+
+ spin_lock_bh(&pmc->lock);
+ psf = pmc->tomb;
+ pmc->tomb = 0;
+ spin_unlock_bh(&pmc->lock);
+ for (; psf; psf=psf_next) {
+ psf_next = psf->sf_next;
+ kfree(psf);
+ }
+ }
+ read_unlock(&in_dev->lock);
}
+#endif
static void igmp_group_dropped(struct ip_mc_list *im)
{
@@ -1030,8 +1052,8 @@ static void igmp_group_dropped(struct ip_mc_list *im)
igmp_ifc_event(in_dev);
done:
- ip_mc_clear_src(im);
#endif
+ ip_mc_clear_src(im);
}
static void igmp_group_added(struct ip_mc_list *im)
@@ -1102,7 +1124,7 @@ void ip_mc_inc_group(struct in_device *in_dev, u32 addr)
im->crcount = 0;
atomic_set(&im->refcnt, 1);
spin_lock_init(&im->lock);
-#ifdef CONFIG_IP_MULTICAST
+#ifdef CONFIG_IP_MULTICAST
im->tm_running=0;
init_timer(&im->timer);
im->timer.data=(unsigned long)im;
@@ -1116,7 +1138,9 @@ void ip_mc_inc_group(struct in_device *in_dev, u32 addr)
im->next=in_dev->mc_list;
in_dev->mc_list=im;
write_unlock_bh(&in_dev->lock);
+#ifdef CONFIG_IP_MULTICAST
igmpv3_del_delrec(in_dev, im->multiaddr);
+#endif
igmp_group_added(im);
if (in_dev->dev->flags & IFF_UP)
ip_rt_multicast_event(in_dev);
@@ -1173,7 +1197,9 @@ void ip_mc_down(struct in_device *in_dev)
for (i=in_dev->mc_list; i; i=i->next)
igmp_group_dropped(i);
+#ifdef CONFIG_IP_MULTICAST
igmpv3_clear_delrec(in_dev);
+#endif
ip_mc_dec_group(in_dev, IGMP_ALL_HOSTS);
}
@@ -1186,12 +1212,12 @@ void ip_mc_up(struct in_device *in_dev)
ASSERT_RTNL();
+ in_dev->mc_tomb = 0;
#ifdef CONFIG_IP_MULTICAST
in_dev->mr_gq_running = 0;
init_timer(&in_dev->mr_gq_timer);
in_dev->mr_gq_timer.data=(unsigned long) in_dev;
in_dev->mr_gq_timer.function=&igmp_gq_timer_expire;
- in_dev->mc_tomb = 0;
in_dev->mr_ifc_count = 0;
init_timer(&in_dev->mr_ifc_timer);
in_dev->mr_ifc_timer.data=(unsigned long) in_dev;
@@ -1237,6 +1263,12 @@ static struct in_device * ip_mc_find_dev(struct ip_mreqn *imr)
struct net_device *dev = NULL;
struct in_device *idev = NULL;
+ if (imr->imr_ifindex) {
+ idev = inetdev_by_index(imr->imr_ifindex);
+ if (idev)
+ __in_dev_put(idev);
+ return idev;
+ }
if (imr->imr_address.s_addr) {
dev = ip_dev_find(imr->imr_address.s_addr);
if (!dev)
@@ -1282,13 +1314,16 @@ static int ip_mc_del1_src(struct ip_mc_list *pmc, int sfmode,
ip_rt_multicast_event(pmc->interface);
}
if (!psf->sf_count[MCAST_INCLUDE] && !psf->sf_count[MCAST_EXCLUDE]) {
+#ifdef CONFIG_IP_MULTICAST
struct in_device *in_dev = pmc->interface;
+#endif
/* no more filters for this source */
if (psf_prev)
psf_prev->sf_next = psf->sf_next;
else
pmc->sources = psf->sf_next;
+#ifdef CONFIG_IP_MULTICAST
if (psf->sf_oldin &&
!IGMP_V1_SEEN(in_dev) && !IGMP_V2_SEEN(in_dev)) {
psf->sf_crcount = in_dev->mr_qrv ? in_dev->mr_qrv :
@@ -1297,6 +1332,7 @@ static int ip_mc_del1_src(struct ip_mc_list *pmc, int sfmode,
pmc->tomb = psf;
rv = 1;
} else
+#endif
kfree(psf);
}
return rv;
@@ -1327,7 +1363,9 @@ int ip_mc_del_src(struct in_device *in_dev, __u32 *pmca, int sfmode,
}
spin_lock_bh(&pmc->lock);
read_unlock(&in_dev->lock);
+#ifdef CONFIG_IP_MULTICAST
sf_markstate(pmc);
+#endif
if (!delta) {
if (!pmc->sfcount[sfmode])
return -EINVAL;
@@ -1344,10 +1382,13 @@ int ip_mc_del_src(struct in_device *in_dev, __u32 *pmca, int sfmode,
if (pmc->sfmode == MCAST_EXCLUDE &&
pmc->sfcount[MCAST_EXCLUDE] == 0 &&
pmc->sfcount[MCAST_INCLUDE]) {
+#ifdef CONFIG_IP_MULTICAST
struct ip_sf_list *psf;
+#endif
/* filter mode change */
pmc->sfmode = MCAST_INCLUDE;
+#ifdef CONFIG_IP_MULTICAST
pmc->crcount = in_dev->mr_qrv ? in_dev->mr_qrv :
IGMP_Unsolicited_Report_Count;
in_dev->mr_ifc_count = pmc->crcount;
@@ -1356,6 +1397,7 @@ int ip_mc_del_src(struct in_device *in_dev, __u32 *pmca, int sfmode,
igmp_ifc_event(pmc->interface);
} else if (sf_setstate(pmc) || changerec) {
igmp_ifc_event(pmc->interface);
+#endif
}
spin_unlock_bh(&pmc->lock);
return err;
@@ -1393,6 +1435,7 @@ static int ip_mc_add1_src(struct ip_mc_list *pmc, int sfmode,
return 0;
}
+#ifdef CONFIG_IP_MULTICAST
static void sf_markstate(struct ip_mc_list *pmc)
{
struct ip_sf_list *psf;
@@ -1428,6 +1471,7 @@ static int sf_setstate(struct ip_mc_list *pmc)
}
return rv;
}
+#endif
/*
* Add multicast source filter list to the interface list
@@ -1454,7 +1498,9 @@ int ip_mc_add_src(struct in_device *in_dev, __u32 *pmca, int sfmode,
spin_lock_bh(&pmc->lock);
read_unlock(&in_dev->lock);
+#ifdef CONFIG_IP_MULTICAST
sf_markstate(pmc);
+#endif
isexclude = pmc->sfmode == MCAST_EXCLUDE;
if (!delta)
pmc->sfcount[sfmode]++;
@@ -1471,14 +1517,17 @@ int ip_mc_add_src(struct in_device *in_dev, __u32 *pmca, int sfmode,
for (j=0; j<i; j++)
(void) ip_mc_del1_src(pmc, sfmode, &psfsrc[i]);
} else if (isexclude != (pmc->sfcount[MCAST_EXCLUDE] != 0)) {
+#ifdef CONFIG_IP_MULTICAST
struct in_device *in_dev = pmc->interface;
struct ip_sf_list *psf;
+#endif
/* filter mode change */
if (pmc->sfcount[MCAST_EXCLUDE])
pmc->sfmode = MCAST_EXCLUDE;
else if (pmc->sfcount[MCAST_INCLUDE])
pmc->sfmode = MCAST_INCLUDE;
+#ifdef CONFIG_IP_MULTICAST
/* else no filters; keep old mode for reports */
pmc->crcount = in_dev->mr_qrv ? in_dev->mr_qrv :
@@ -1487,8 +1536,10 @@ int ip_mc_add_src(struct in_device *in_dev, __u32 *pmca, int sfmode,
for (psf=pmc->sources; psf; psf = psf->sf_next)
psf->sf_crcount = 0;
igmp_ifc_event(in_dev);
- } else if (sf_setstate(pmc))
+ } else if (sf_setstate(pmc)) {
igmp_ifc_event(in_dev);
+#endif
+ }
spin_unlock_bh(&pmc->lock);
return err;
}
@@ -1530,13 +1581,7 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr)
rtnl_shlock();
- if (!imr->imr_ifindex)
- in_dev = ip_mc_find_dev(imr);
- else {
- in_dev = inetdev_by_index(imr->imr_ifindex);
- if (in_dev)
- __in_dev_put(in_dev);
- }
+ in_dev = ip_mc_find_dev(imr);
if (!in_dev) {
iml = NULL;
@@ -1638,13 +1683,13 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr)
}
int ip_mc_source(int add, int omode, struct sock *sk, struct
- ip_mreq_source *mreqs)
+ ip_mreq_source *mreqs, int ifindex)
{
int err;
- struct ip_mreqn imr;
+ struct ip_mreqn imr;
u32 addr = mreqs->imr_multiaddr;
struct ip_mc_socklist *pmc;
- struct in_device *in_dev;
+ struct in_device *in_dev = 0;
struct inet_opt *inet = inet_sk(sk);
struct ip_sf_socklist *psl;
int i, j, rv;
@@ -1656,7 +1701,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
imr.imr_multiaddr.s_addr = mreqs->imr_multiaddr;
imr.imr_address.s_addr = mreqs->imr_interface;
- imr.imr_ifindex = 0;
+ imr.imr_ifindex = ifindex;
in_dev = ip_mc_find_dev(&imr);
if (!in_dev) {
@@ -1753,7 +1798,7 @@ done:
return err;
}
-int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf)
+int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex)
{
int err;
struct ip_mreqn imr;
@@ -1773,7 +1818,7 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf)
imr.imr_multiaddr.s_addr = msf->imsf_multiaddr;
imr.imr_address.s_addr = msf->imsf_interface;
- imr.imr_ifindex = 0;
+ imr.imr_ifindex = ifindex;
in_dev = ip_mc_find_dev(&imr);
if (!in_dev) {
@@ -1783,7 +1828,8 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf)
err = -EADDRNOTAVAIL;
for (pmc=inet->mc_list; pmc; pmc=pmc->next) {
- if (memcmp(&pmc->multi, &imr, sizeof(imr)) == 0)
+ if (pmc->multi.imr_multiaddr.s_addr == msf->imsf_multiaddr &&
+ pmc->multi.imr_ifindex == imr.imr_ifindex)
break;
}
if (!pmc) /* must have a prior join */
@@ -1834,9 +1880,6 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf,
if (!MULTICAST(addr))
return -EINVAL;
- if (msf->imsf_fmode != MCAST_INCLUDE &&
- msf->imsf_fmode != MCAST_EXCLUDE)
- return -EINVAL;
rtnl_shlock();
@@ -1852,7 +1895,8 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf,
err = -EADDRNOTAVAIL;
for (pmc=inet->mc_list; pmc; pmc=pmc->next) {
- if (memcmp(&pmc->multi, &imr, sizeof(imr)) == 0)
+ if (pmc->multi.imr_multiaddr.s_addr == msf->imsf_multiaddr &&
+ pmc->multi.imr_ifindex == imr.imr_ifindex)
break;
}
if (!pmc) /* must have a prior join */
@@ -1882,6 +1926,61 @@ done:
return err;
}
+int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf,
+ struct group_filter *optval, int *optlen)
+{
+ int err, i, count, copycount;
+ struct sockaddr_in *psin;
+ u32 addr;
+ struct ip_mc_socklist *pmc;
+ struct inet_opt *inet = inet_sk(sk);
+ struct ip_sf_socklist *psl;
+
+ psin = (struct sockaddr_in *)&gsf->gf_group;
+ if (psin->sin_family != AF_INET)
+ return -EINVAL;
+ addr = psin->sin_addr.s_addr;
+ if (!MULTICAST(addr))
+ return -EINVAL;
+
+ rtnl_shlock();
+
+ err = -EADDRNOTAVAIL;
+
+ for (pmc=inet->mc_list; pmc; pmc=pmc->next) {
+ if (pmc->multi.imr_multiaddr.s_addr == addr &&
+ pmc->multi.imr_ifindex == gsf->gf_interface)
+ break;
+ }
+ if (!pmc) /* must have a prior join */
+ goto done;
+ gsf->gf_fmode = pmc->sfmode;
+ psl = pmc->sflist;
+ rtnl_shunlock();
+ count = psl ? psl->sl_count : 0;
+ copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc;
+ gsf->gf_numsrc = count;
+ if (put_user(GROUP_FILTER_SIZE(copycount), optlen) ||
+ copy_to_user((void *)optval, gsf, GROUP_FILTER_SIZE(0))) {
+ return -EFAULT;
+ }
+ for (i=0; i<copycount; i++) {
+ struct sockaddr_in *psin;
+ struct sockaddr_storage ss;
+
+ psin = (struct sockaddr_in *)&ss;
+ memset(&ss, 0, sizeof(ss));
+ psin->sin_family = AF_INET;
+ psin->sin_addr.s_addr = psl->sl_addr[i];
+ if (copy_to_user((void *)&optval->gf_slist[i], &ss, sizeof(ss)))
+ return -EFAULT;
+ }
+ return 0;
+done:
+ rtnl_shunlock();
+ return err;
+}
+
/*
* check if a multicast source filter allows delivery for a given <src,dst,intf>
*/
@@ -1892,6 +1991,9 @@ int ip_mc_sf_allow(struct sock *sk, u32 loc_addr, u32 rmt_addr, int dif)
struct ip_sf_socklist *psl;
int i;
+ if (!MULTICAST(loc_addr))
+ return 1;
+
for (pmc=inet->mc_list; pmc; pmc=pmc->next) {
if (pmc->multi.imr_multiaddr.s_addr == loc_addr &&
pmc->multi.imr_ifindex == dif)
@@ -1972,8 +2074,6 @@ int ip_check_mc(struct in_device *in_dev, u32 mc_addr, u32 src_addr, u16 proto)
}
-#ifdef CONFIG_IP_MULTICAST
-
int ip_mc_procinfo(char *buffer, char **start, off_t offset, int length)
{
off_t pos=0, begin=0;
@@ -1991,7 +2091,9 @@ int ip_mc_procinfo(char *buffer, char **start, off_t offset, int length)
if (in_dev == NULL)
continue;
+#ifdef CONFIG_IP_MULTICAST
querier = IGMP_V1_SEEN(in_dev) ? "V1" : "V2";
+#endif
len+=sprintf(buffer+len,"%d\t%-10s: %5d %7s\n",
dev->ifindex, dev->name, dev->mc_count, querier);
@@ -2049,11 +2151,8 @@ int ip_mcf_procinfo(char *buffer, char **start, off_t offset, int length)
for (imc=in_dev->mc_list; imc; imc=imc->next) {
struct ip_sf_list *psf;
- unsigned long icount, xcount;
spin_lock_bh(&imc->lock);
- icount = imc->sfcount[MCAST_INCLUDE];
- xcount = imc->sfcount[MCAST_EXCLUDE];
for (psf=imc->sources; psf; psf=psf->sf_next) {
if (first) {
len += sprintf(buffer+len, "%3s %6s "
@@ -2080,33 +2179,6 @@ int ip_mcf_procinfo(char *buffer, char **start, off_t offset, int length)
in_dev_put(in_dev);
goto done;
}
- icount -= psf->sf_count[MCAST_INCLUDE];
- xcount -= psf->sf_count[MCAST_EXCLUDE];
- }
- if (icount > 0 || xcount > 0) {
- if (first) {
- len += sprintf(buffer+len, "%3s %6s "
- "%10s %10s %6s %6s\n", "Idx",
- "Device", "MCA", "SRC", "INC",
- "EXC");
- first = 0;
- }
- len += sprintf(buffer+len, "%3d %6.6s 0x%08x "
- "%10s %6lu %6lu\n", dev->ifindex,
- dev->name, ntohl(imc->multiaddr),
- "NONE", icount, xcount);
- pos=begin+len;
- if(pos<offset)
- {
- len=0;
- begin=pos;
- }
- if(pos>offset+length) {
- spin_unlock_bh(&imc->lock);
- read_unlock(&in_dev->lock);
- in_dev_put(in_dev);
- goto done;
- }
}
spin_unlock_bh(&imc->lock);
}
@@ -2125,5 +2197,3 @@ done:
return len;
}
-#endif
-
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 9a4db884dc1f..3f657dcde315 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -1312,6 +1312,6 @@ void __init ip_init(void)
#ifdef CONFIG_IP_MULTICAST
proc_net_create("igmp", 0, ip_mc_procinfo);
- proc_net_create("mcfilter", 0, ip_mcf_procinfo);
#endif
+ proc_net_create("mcfilter", 0, ip_mcf_procinfo);
}
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index a8a561411dea..82ab1fc2faa3 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -631,7 +631,7 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt
kfree(msf);
break;
}
- err = ip_mc_msfilter(sk, msf);
+ err = ip_mc_msfilter(sk, msf, 0);
kfree(msf);
break;
}
@@ -670,7 +670,142 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt
omode = MCAST_INCLUDE;
add = 0;
}
- err = ip_mc_source(add, omode, sk, &mreqs);
+ err = ip_mc_source(add, omode, sk, &mreqs, 0);
+ break;
+ }
+ case MCAST_JOIN_GROUP:
+ case MCAST_LEAVE_GROUP:
+ {
+ struct group_req greq;
+ struct sockaddr_in *psin;
+ struct ip_mreqn mreq;
+
+ if (optlen < sizeof(struct group_req))
+ goto e_inval;
+ err = -EFAULT;
+ if(copy_from_user(&greq, optval, sizeof(greq)))
+ break;
+ psin = (struct sockaddr_in *)&greq.gr_group;
+ if (psin->sin_family != AF_INET)
+ goto e_inval;
+ memset(&mreq, 0, sizeof(mreq));
+ mreq.imr_multiaddr = psin->sin_addr;
+ mreq.imr_ifindex = greq.gr_interface;
+
+ if (optname == MCAST_JOIN_GROUP)
+ err = ip_mc_join_group(sk, &mreq);
+ else
+ err = ip_mc_leave_group(sk, &mreq);
+ break;
+ }
+ case MCAST_JOIN_SOURCE_GROUP:
+ case MCAST_LEAVE_SOURCE_GROUP:
+ case MCAST_BLOCK_SOURCE:
+ case MCAST_UNBLOCK_SOURCE:
+ {
+ struct group_source_req greqs;
+ struct ip_mreq_source mreqs;
+ struct sockaddr_in *psin;
+ int omode, add;
+
+ if (optlen != sizeof(struct group_source_req))
+ goto e_inval;
+ if (copy_from_user(&greqs, optval, sizeof(greqs))) {
+ err = -EFAULT;
+ break;
+ }
+ if (greqs.gsr_group.ss_family != AF_INET ||
+ greqs.gsr_source.ss_family != AF_INET) {
+ err = -EADDRNOTAVAIL;
+ break;
+ }
+ psin = (struct sockaddr_in *)&greqs.gsr_group;
+ mreqs.imr_multiaddr = psin->sin_addr.s_addr;
+ psin = (struct sockaddr_in *)&greqs.gsr_source;
+ mreqs.imr_sourceaddr = psin->sin_addr.s_addr;
+ mreqs.imr_interface = 0; /* use index for mc_source */
+
+ if (optname == MCAST_BLOCK_SOURCE) {
+ omode = MCAST_EXCLUDE;
+ add = 1;
+ } else if (optname == MCAST_UNBLOCK_SOURCE) {
+ omode = MCAST_EXCLUDE;
+ add = 0;
+ } else if (optname == MCAST_JOIN_SOURCE_GROUP) {
+ struct ip_mreqn mreq;
+
+ psin = (struct sockaddr_in *)&greqs.gsr_group;
+ mreq.imr_multiaddr = psin->sin_addr;
+ mreq.imr_address.s_addr = 0;
+ mreq.imr_ifindex = greqs.gsr_interface;
+ err = ip_mc_join_group(sk, &mreq);
+ if (err)
+ break;
+ omode = MCAST_INCLUDE;
+ add = 1;
+ } else /* MCAST_LEAVE_SOURCE_GROUP */ {
+ omode = MCAST_INCLUDE;
+ add = 0;
+ }
+ err = ip_mc_source(add, omode, sk, &mreqs,
+ greqs.gsr_interface);
+ break;
+ }
+ case MCAST_MSFILTER:
+ {
+ struct sockaddr_in *psin;
+ struct ip_msfilter *msf = 0;
+ struct group_filter *gsf = 0;
+ int msize, i, ifindex;
+
+ if (optlen < GROUP_FILTER_SIZE(0))
+ goto e_inval;
+ gsf = (struct group_filter *)kmalloc(optlen,GFP_KERNEL);
+ if (gsf == 0) {
+ err = -ENOBUFS;
+ break;
+ }
+ err = -EFAULT;
+ if (copy_from_user(gsf, optval, optlen)) {
+ goto mc_msf_out;
+ }
+ if (GROUP_FILTER_SIZE(gsf->gf_numsrc) < optlen) {
+ err = EINVAL;
+ goto mc_msf_out;
+ }
+ msize = IP_MSFILTER_SIZE(gsf->gf_numsrc);
+ msf = (struct ip_msfilter *)kmalloc(msize,GFP_KERNEL);
+ if (msf == 0) {
+ err = -ENOBUFS;
+ goto mc_msf_out;
+ }
+ ifindex = gsf->gf_interface;
+ psin = (struct sockaddr_in *)&gsf->gf_group;
+ if (psin->sin_family != AF_INET) {
+ err = -EADDRNOTAVAIL;
+ goto mc_msf_out;
+ }
+ msf->imsf_multiaddr = psin->sin_addr.s_addr;
+ msf->imsf_interface = 0;
+ msf->imsf_fmode = gsf->gf_fmode;
+ msf->imsf_numsrc = gsf->gf_numsrc;
+ err = -EADDRNOTAVAIL;
+ for (i=0; i<gsf->gf_numsrc; ++i) {
+ psin = (struct sockaddr_in *)&gsf->gf_slist[i];
+
+ if (psin->sin_family != AF_INET)
+ goto mc_msf_out;
+ msf->imsf_slist[i] = psin->sin_addr.s_addr;
+ }
+ kfree(gsf);
+ gsf = 0;
+
+ err = ip_mc_msfilter(sk, msf, ifindex);
+mc_msf_out:
+ if (msf)
+ kfree(msf);
+ if (gsf)
+ kfree(gsf);
break;
}
case IP_ROUTER_ALERT:
@@ -826,15 +961,37 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *op
struct ip_msfilter msf;
int err;
- if (len < IP_MSFILTER_SIZE(0))
+ if (len < IP_MSFILTER_SIZE(0)) {
+ release_sock(sk);
return -EINVAL;
- if (copy_from_user(&msf, optval, IP_MSFILTER_SIZE(0)))
+ }
+ if (copy_from_user(&msf, optval, IP_MSFILTER_SIZE(0))) {
+ release_sock(sk);
return -EFAULT;
+ }
err = ip_mc_msfget(sk, &msf,
(struct ip_msfilter *)optval, optlen);
release_sock(sk);
return err;
}
+ case MCAST_MSFILTER:
+ {
+ struct group_filter gsf;
+ int err;
+
+ if (len < GROUP_FILTER_SIZE(0)) {
+ release_sock(sk);
+ return -EINVAL;
+ }
+ if (copy_from_user(&gsf, optval, GROUP_FILTER_SIZE(0))) {
+ release_sock(sk);
+ return -EFAULT;
+ }
+ err = ip_mc_gsfget(sk, &gsf,
+ (struct group_filter *)optval, optlen);
+ release_sock(sk);
+ return err;
+ }
case IP_PKTOPTIONS:
{
struct msghdr msg;
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 6ac0225988fd..d7c44f39a180 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -48,7 +48,7 @@ config IP_NF_IRC
<file:Documentation/modules.txt>. If unsure, say `Y'.
config IP_NF_TFTP
- tristate "TFTP prtocol support"
+ tristate "TFTP protocol support"
depends on IP_NF_CONNTRACK
help
TFTP connection tracking helper, this is required depending
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 4ab428df1864..681416c6045b 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -120,6 +120,12 @@ int ip6_ra_control(struct sock *sk, int sel, void (*destructor)(struct sock *))
return 0;
}
+extern int ip6_mc_source(int add, int omode, struct sock *sk,
+ struct group_source_req *pgsr);
+extern int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf);
+extern int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
+ struct group_filter *optval, int *optlen);
+
int ipv6_setsockopt(struct sock *sk, int level, int optname, char *optval,
int optlen)
@@ -393,12 +399,13 @@ done:
break;
}
psin6 = (struct sockaddr_in6 *)&greq.gr_group;
- if (optname == IPV6_ADD_MEMBERSHIP)
+ if (optname == MCAST_JOIN_GROUP)
retv = ipv6_sock_mc_join(sk, greq.gr_interface,
&psin6->sin6_addr);
else
retv = ipv6_sock_mc_drop(sk, greq.gr_interface,
&psin6->sin6_addr);
+ break;
}
case MCAST_JOIN_SOURCE_GROUP:
case MCAST_LEAVE_SOURCE_GROUP:
@@ -414,7 +421,8 @@ done:
retv = -EFAULT;
break;
}
- if (greqs.gsr_group.ss_family != AF_INET6) {
+ if (greqs.gsr_group.ss_family != AF_INET6 ||
+ greqs.gsr_source.ss_family != AF_INET6) {
retv = -EADDRNOTAVAIL;
break;
}
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 176963371c72..57877738d350 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -768,7 +768,7 @@ static void mld_clear_delrec(struct inet6_dev *idev)
psf = pmc->mca_tomb;
pmc->mca_tomb = 0;
spin_unlock_bh(&pmc->mca_lock);
- for (psf=pmc->mca_tomb; psf; psf=psf_next) {
+ for (; psf; psf=psf_next) {
psf_next = psf->sf_next;
kfree(psf);
}
@@ -1042,6 +1042,8 @@ int igmp6_event_query(struct sk_buff *skb)
mld_clear_delrec(idev);
} else if (len >= 28) {
max_delay = MLDV2_MRC(ntohs(mlh2->mrc))*(HZ/10);
+ if (!max_delay)
+ max_delay = 1;
idev->mc_maxdelay = max_delay;
if (mlh2->qrv)
idev->mc_qrv = mlh2->qrv;
@@ -2096,8 +2098,6 @@ static int ip6_mcf_read_proc(char *buffer, char **start, off_t offset,
unsigned long icount, xcount, i;
spin_lock_bh(&imc->mca_lock);
- icount = imc->mca_sfcount[MCAST_INCLUDE];
- xcount = imc->mca_sfcount[MCAST_EXCLUDE];
for (psf=imc->mca_sources; psf; psf=psf->sf_next) {
if (first) {
len += sprintf(buffer+len, "%3s %6s "
@@ -2130,36 +2130,6 @@ static int ip6_mcf_read_proc(char *buffer, char **start, off_t offset,
in6_dev_put(idev);
goto done;
}
- icount -= psf->sf_count[MCAST_INCLUDE];
- xcount -= psf->sf_count[MCAST_EXCLUDE];
- }
- if (icount > 0 || xcount > 0) {
- if (first) {
- len += sprintf(buffer+len, "%3s %6s "
- "%32s %32s %6s %6s\n", "Idx",
- "Device", "Multicast Address",
- "Source Address", "INC", "EXC");
- first = 0;
- }
- len += sprintf(buffer+len,"%3d %6.6s ",
- dev->ifindex, dev->name);
-
- for (i=0; i<16; i++)
- len += sprintf(buffer+len, "%02x",
- imc->mca_addr.s6_addr[i]);
- len += sprintf(buffer+len, " %32s %6lu %6lu\n",
- "NONE", icount, xcount);
- pos = begin+len;
- if (pos < offset) {
- len=0;
- begin=pos;
- }
- if (pos > offset+length) {
- spin_unlock_bh(&imc->mca_lock);
- read_unlock_bh(&idev->lock);
- in6_dev_put(idev);
- goto done;
- }
}
spin_unlock_bh(&imc->mca_lock);
}
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index c5b38160717d..7688f0ce1e5b 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -427,7 +427,7 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
- rt = ndisc_get_dummy_rt();
+ rt = ip6_dst_alloc();
if (!rt)
return;
@@ -524,7 +524,7 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
saddr = &addr_buf;
}
- rt = ndisc_get_dummy_rt();
+ rt = ip6_dst_alloc();
if (!rt)
return;
@@ -595,7 +595,7 @@ void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr,
int len;
int err;
- rt = ndisc_get_dummy_rt();
+ rt = ip6_dst_alloc();
if (!rt)
return;
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index c855580c278a..67eae08db2ca 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -130,12 +130,17 @@ struct fib6_node ip6_routing_table = {
rwlock_t rt6_lock = RW_LOCK_UNLOCKED;
-/* Dummy rt for ndisc */
-struct rt6_info *ndisc_get_dummy_rt()
+/* allocate dst with ip6_dst_ops */
+static __inline__ struct rt6_info *__ip6_dst_alloc(void)
{
return dst_alloc(&ip6_dst_ops);
}
+struct rt6_info *ip6_dst_alloc(void)
+{
+ return __ip6_dst_alloc();
+}
+
/*
* Route lookup. Any rt6_lock is implied.
*/
@@ -640,7 +645,7 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh)
if (rtmsg->rtmsg_metric == 0)
rtmsg->rtmsg_metric = IP6_RT_PRIO_USER;
- rt = dst_alloc(&ip6_dst_ops);
+ rt = __ip6_dst_alloc();
if (rt == NULL)
return -ENOMEM;
@@ -1035,9 +1040,7 @@ out:
static struct rt6_info * ip6_rt_copy(struct rt6_info *ort)
{
- struct rt6_info *rt;
-
- rt = dst_alloc(&ip6_dst_ops);
+ struct rt6_info *rt = __ip6_dst_alloc();
if (rt) {
rt->u.dst.input = ort->u.dst.input;
@@ -1181,9 +1184,8 @@ int ip6_pkt_discard(struct sk_buff *skb)
int ip6_rt_addr_add(struct in6_addr *addr, struct net_device *dev)
{
- struct rt6_info *rt;
+ struct rt6_info *rt = __ip6_dst_alloc();
- rt = dst_alloc(&ip6_dst_ops);
if (rt == NULL)
return -ENOMEM;
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index d77a9689004b..e972bef42859 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -1052,6 +1052,7 @@ struct proto_ops netlink_ops = {
struct net_proto_family netlink_family_ops = {
.family = PF_NETLINK,
.create = netlink_create,
+ .owner = THIS_MODULE, /* for consistency 8) */
};
static int __init netlink_proto_init(void)
@@ -1066,6 +1067,11 @@ static int __init netlink_proto_init(void)
#ifdef CONFIG_PROC_FS
create_proc_read_entry("net/netlink", 0, 0, netlink_read_proc, NULL);
#endif
+ /* The netlink device handler may be needed early. */
+ rtnetlink_init();
+#ifdef CONFIG_NETLINK_DEV
+ init_netlink();
+#endif
return 0;
}
@@ -1075,7 +1081,7 @@ static void __exit netlink_proto_exit(void)
remove_proc_entry("net/netlink", NULL);
}
-module_init(netlink_proto_init);
+subsys_initcall(netlink_proto_init);
module_exit(netlink_proto_exit);
MODULE_LICENSE("GPL");
diff --git a/net/socket.c b/net/socket.c
index 0d8a2e9d5a04..39a558da28ca 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -69,8 +69,6 @@
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/wanrouter.h>
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
#include <linux/if_bridge.h>
#include <linux/init.h>
#include <linux/poll.h>
@@ -143,6 +141,36 @@ static struct file_operations socket_file_ops = {
static struct net_proto_family *net_families[NPROTO];
+static __inline__ void net_family_bug(int family)
+{
+ printk(KERN_ERR "%d is not yet sock_registered!\n", family);
+ BUG();
+}
+
+int net_family_get(int family)
+{
+ struct net_proto_family *prot = net_families[family];
+ int rc = 1;
+
+ barrier();
+ if (likely(prot != NULL))
+ rc = try_module_get(prot->owner);
+ else
+ net_family_bug(family);
+ return rc;
+}
+
+void net_family_put(int family)
+{
+ struct net_proto_family *prot = net_families[family];
+
+ barrier();
+ if (likely(prot != NULL))
+ module_put(prot->owner);
+ else
+ net_family_bug(family);
+}
+
#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
static atomic_t net_family_lockct = ATOMIC_INIT(0);
static spinlock_t net_family_lock = SPIN_LOCK_UNLOCKED;
@@ -511,7 +539,7 @@ void sock_release(struct socket *sock)
sock->ops->release(sock);
sock->ops = NULL;
- module_put(net_families[family]->owner);
+ net_family_put(family);
}
if (sock->fasync_list)
@@ -1064,7 +1092,7 @@ int sock_create(int family, int type, int protocol, struct socket **res)
sock->type = type;
i = -EBUSY;
- if (!try_module_get(net_families[family]->owner))
+ if (!net_family_get(family))
goto out_release;
if ((i = net_families[family]->create(sock, protocol)) < 0)
@@ -1953,17 +1981,6 @@ void __init sock_init(void)
* do_initcalls is run.
*/
-
- /*
- * The netlink device handler may be needed early.
- */
-
-#ifdef CONFIG_NET
- rtnetlink_init();
-#endif
-#ifdef CONFIG_NETLINK_DEV
- init_netlink();
-#endif
#ifdef CONFIG_NETFILTER
netfilter_init();
#endif