diff options
| author | Linus Torvalds <torvalds@home.transmeta.com> | 2003-04-22 22:50:53 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.transmeta.com> | 2003-04-22 22:50:53 -0700 |
| commit | 70ced8bfb70ae687cd39c3ffc047cd345c4bb00f (patch) | |
| tree | bf3de613a67e818253a6415abe4d51606d70d3e8 | |
| parent | b3d4c0270080c88e41704740ff9f413ce4067715 (diff) | |
| parent | 6febb77650e96402767132b69b229fc3ae2f6ca4 (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.h | 8 | ||||
| -rw-r--r-- | include/linux/net.h | 3 | ||||
| -rw-r--r-- | include/net/ip6_route.h | 2 | ||||
| -rw-r--r-- | net/core/dev.c | 10 | ||||
| -rw-r--r-- | net/core/sock.c | 13 | ||||
| -rw-r--r-- | net/ipv4/igmp.c | 188 | ||||
| -rw-r--r-- | net/ipv4/ip_output.c | 2 | ||||
| -rw-r--r-- | net/ipv4/ip_sockglue.c | 165 | ||||
| -rw-r--r-- | net/ipv4/netfilter/Kconfig | 2 | ||||
| -rw-r--r-- | net/ipv6/ipv6_sockglue.c | 12 | ||||
| -rw-r--r-- | net/ipv6/mcast.c | 36 | ||||
| -rw-r--r-- | net/ipv6/ndisc.c | 6 | ||||
| -rw-r--r-- | net/ipv6/route.c | 18 | ||||
| -rw-r--r-- | net/netlink/af_netlink.c | 8 | ||||
| -rw-r--r-- | net/socket.c | 47 |
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 |
