--- //depot/vendor/freebsd/src/UPDATING 2007/04/03 13:43:12 +++ //depot/user/bms/netdev/UPDATING 2007/04/10 00:36:30 @@ -21,6 +21,25 @@ developers choose to disable these features on build machines to maximize performance. +20070410: + The IPv4 multicast socket code has been considerably modified, and + moved to the file sys/netinet/in_mcast.c. Initial support for the + RFC 3678 Source-Specific Multicast Socket API has been added to + the IPv4 network stack. + + Strict multicast and broadcast reception is now the default for + UDP/IPv4 sockets; the net.inet.udp.strict_mcast_mship sysctl variable + has now been removed. + + The RFC 1724 hack for interface selection has been removed; the use + of the Linux-derived ip_mreqn structure with IP_MULTICAST_IF has + been added to replace it. Consumers such as routed will soon be + updated to reflect this. + + These changes affect users who are running routed(8) or rdisc(8) + from the FreeBSD base system on point-to-point or unnumbered + interfaces. + 20070302: Firmwares for ipw(4) and iwi(4) are now included in the base tree. In order to use them one must agree to the respective LICENSE in --- //depot/vendor/freebsd/src/lib/libc/net/Makefile.inc 2007/03/01 02:41:14 +++ //depot/user/bms/netdev/lib/libc/net/Makefile.inc 2007/04/04 18:35:48 @@ -14,7 +14,7 @@ ip6opt.c linkaddr.c map_v4v6.c name6.c ntoh.c \ nsdispatch.c nslexer.c nsparser.c nss_compat.c \ rcmd.c rcmdsh.c recv.c rthdr.c sctp_sys_calls.c send.c \ - sockatmark.c vars.c + sockatmark.c sourcefilter.c vars.c .if ${MK_NS_CACHING} != "no" SRCS+= nscache.c nscachedcli.c @@ -52,6 +52,7 @@ inet6_opt_init.3 inet6_option_space.3 inet6_rth_space.3 \ inet6_rthdr_space.3 linkaddr.3 \ nsdispatch.3 rcmd.3 rcmdsh.3 resolver.3 sockatmark.3 \ + setsourcefilter.3 \ sctp_bindx.3 sctp_connectx.3 sctp_freepaddrs.3 \ sctp_getaddrlen.3 sctp_getassocid.3 sctp_getpaddrs.3 \ sctp_opt_info.3 sctp_recvmsg.3 sctp_send.3 sctp_sendmsg.3 \ @@ -121,6 +122,8 @@ resolver.3 res_search.3 resolver.3 res_send.3 resolver.3 dn_skipname.3 \ resolver.3 ns_get16.3 resolver.3 ns_get32.3 \ resolver.3 ns_put16.3 resolver.3 ns_put32.3 +MLINKS+=sourcefilter.3 setipv4sourcefilter.3 getipv4sourcefilter.3 \ + sourcefilter.3 setsourcefilter.3 getsourcefilter.3 .if ${MK_HESIOD} != "no" SRCS+= hesiod.c --- //depot/vendor/freebsd/src/lib/libc/net/Symbol.map 2007/03/01 02:41:14 +++ //depot/user/bms/netdev/lib/libc/net/Symbol.map 2007/04/04 18:35:48 @@ -120,6 +120,10 @@ in6addr_loopback; in6addr_nodelocal_allnodes; in6addr_linklocal_allnodes; + setipv4sourcefilter; + getipv4sourcefilter; + getsourcefilter; + setsourcefilter; }; FBSDprivate { --- //depot/vendor/freebsd/src/share/man/man4/ip.4 2007/03/19 06:40:14 +++ //depot/user/bms/netdev/share/man/man4/ip.4 2007/04/14 01:48:13 @@ -32,7 +32,7 @@ .\" @(#)ip.4 8.2 (Berkeley) 11/30/93 .\" $FreeBSD: src/share/man/man4/ip.4,v 1.48 2007/03/18 15:31:06 bms Exp $ .\" -.Dd March 18, 2007 +.Dd April 9, 2007 .Dt IP 4 .Os .Sh NAME @@ -420,6 +420,16 @@ address of the desired interface or .Dv INADDR_ANY to specify the default interface. +.Pp +To specify an interface by index, an instance of +.Vt ip_mreqn +should be passed instead. +The +.Vt imr_ifindex +member should be set to the index of the desired interface, +or 0 to specify the default interface. +The kernel differentiates between these two structures by their size. +.\" An interface's local IP address and multicast capability can be obtained via the .Dv SIOCGIFCONF @@ -672,3 +682,7 @@ .Nm protocol appeared in .Bx 4.2 . +The +.Vt ip_mreqn +structure appeared in +.Tn Linux 2.4 . --- //depot/vendor/freebsd/src/sys/conf/files 2007/04/10 00:41:38 +++ //depot/user/bms/netdev/sys/conf/files 2007/04/10 00:55:03 @@ -1758,6 +1758,7 @@ netinet/in_gif.c optional gif inet netinet/ip_gre.c optional gre inet netinet/ip_id.c optional inet +netinet/in_mcast.c optional inet netinet/in_pcb.c optional inet netinet/in_proto.c optional inet \ compile-with "${NORMAL_C} -I$S/contrib/pf" --- //depot/vendor/freebsd/src/sys/contrib/pf/net/if_pfsync.c 2007/04/14 01:07:38 +++ //depot/user/bms/netdev/sys/contrib/pf/net/if_pfsync.c 2007/04/12 12:59:57 @@ -1,4 +1,4 @@ -/* $FreeBSD: src/sys/contrib/pf/net/if_pfsync.c,v 1.34 2007/04/14 01:01:46 bms Exp $ */ +/* $FreeBSD: src/sys/contrib/pf/net/if_pfsync.c,v 1.33 2007/03/19 17:52:15 bms Exp $ */ /* $OpenBSD: if_pfsync.c,v 1.46 2005/02/20 15:58:38 mcbride Exp $ */ /* @@ -209,6 +209,8 @@ if_detach(ifp); if_free(ifp); LIST_REMOVE(sc, sc_next); + KASSERT(sc->sc_imo.imo_mfilters == NULL, + ("%s: imo_mfilters != NULL", __func__)); free(sc->sc_imo.imo_membership, M_PFSYNC); free(sc, M_PFSYNC); } @@ -255,6 +257,7 @@ (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_PFSYNC, M_WAITOK); sc->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS; + sc->sc_imo.imo_mfilters = NULL; ifp = SCP2IFP(sc); if_initname(ifp, ifc->ifc_name, unit); --- //depot/vendor/freebsd/src/sys/netinet/igmp.h 2005/01/07 01:52:23 +++ //depot/user/bms/netdev/sys/netinet/igmp.h 2007/03/23 00:50:16 @@ -55,7 +55,42 @@ struct in_addr igmp_group; /* group address being reported */ }; /* (zero for queries) */ -#define IGMP_MINLEN 8 +struct igmpv3 { + u_char igmp_type; /* version & type of IGMP message */ + u_char igmp_code; /* subtype for routing msgs */ + u_short igmp_cksum; /* IP-style checksum */ + struct in_addr igmp_group; /* group address being reported */ + /* (zero for queries) */ + u_char igmp_misc; /* reserved/suppress/robustness */ + u_char igmp_qqi; /* querier's query interval */ + u_short igmp_numsrc; /* number of sources */ + /*struct in_addr igmp_sources[1];*/ /* source addresses */ +}; + +struct igmp_grouprec { + u_char ig_type; /* record type */ + u_char ig_datalen; /* length of auxiliary data */ + u_short ig_numsrc; /* number of sources */ + struct in_addr ig_group; /* group address being reported */ + /*struct in_addr ig_sources[1];*/ /* source addresses */ +}; + +struct igmp_report { + u_char ir_type; /* record type */ + u_char ir_rsv1; /* reserved */ + u_short ir_cksum; /* checksum */ + u_short ir_rsv2; /* reserved */ + u_short ir_numgrps; /* number of group records */ + struct igmp_grouprec ir_groups[1]; /* group records */ +}; + +#define IGMP_MINLEN 8 +#define IGMP_HDRLEN 8 +#define IGMP_GRPREC_HDRLEN 8 +#define IGMP_PREPEND 0 + +#define IGMP_QRV(pigmp) ((pigmp)->igmp_misc & (0x07)) /* XXX */ +#define IGMP_MAXSOURCES(len) (((len) - 12) >> 2) /* XXX */ /* * Message types, including version number. @@ -71,6 +106,8 @@ #define IGMP_MTRACE_RESP 0x1e /* traceroute resp.(to sender)*/ #define IGMP_MTRACE 0x1f /* mcast traceroute messages */ +#define IGMP_V3_MEMBERSHIP_REPORT 0x22 /* Ver. 3 membership report */ + #define IGMP_MAX_HOST_REPORT_DELAY 10 /* max delay for response to */ /* query (in seconds) according */ /* to RFC1112 */ --- //depot/vendor/freebsd/src/sys/netinet/igmp_var.h 2005/01/07 01:52:23 +++ //depot/user/bms/netdev/sys/netinet/igmp_var.h 2007/04/14 01:44:00 @@ -56,6 +56,7 @@ u_int igps_rcv_badreports; /* received invalid reports */ u_int igps_rcv_ourreports; /* received reports for our groups */ u_int igps_snd_reports; /* sent membership reports */ + u_int igps_rcv_toolong; /* received with too many bytes */ }; #ifdef _KERNEL @@ -68,12 +69,20 @@ #define IGMP_IREPORTEDLAST 1 /* + * State masks for IGMPv3 + */ +#define IGMP_V3_NONEXISTENT 0x01 +#define IGMP_V3_OTHERMEMBER 0x02 +#define IGMP_V3_IREPORTEDLAST 0x04 + +/* * We must remember what version the subnet's querier is. * We conveniently use the IGMP message type for the proper * membership report to keep this state. */ #define IGMP_V1_ROUTER IGMP_V1_MEMBERSHIP_REPORT #define IGMP_V2_ROUTER IGMP_V2_MEMBERSHIP_REPORT +#define IGMP_V3_ROUTER IGMP_V3_MEMBERSHIP_REPORT /* * Revert to new router if we haven't heard from an old router in @@ -81,6 +90,51 @@ */ #define IGMP_AGE_THRESHOLD 540 +/* + * IGMPv3 protocol defaults + */ +#define IGMP_INIT_ROBVAR 2 /* Robustness */ +#define IGMP_MAX_ROBVAR 7 +#define IGMP_INIT_QRYINT 125 /* Querier's Query interval */ +#define IGMP_MAX_QRYINT 255 +#define IGMP_INIT_QRYRSP 10 /* Query Response interval */ +#define IGMP_DEF_QRYMRT 10 +#define IGMP_UNSOL_INT 1 /* Unsolicited Report interval */ + +/* + * IGMPv3 report types + */ +#define IGMP_REPORT_MODE_IN 1 /* mode-is-include */ +#define IGMP_REPORT_MODE_EX 2 /* mode-is-exclude */ +#define IGMP_REPORT_TO_IN 3 /* change-to-include */ +#define IGMP_REPORT_TO_EX 4 /* change-to-exclude */ +#define IGMP_REPORT_ALLOW_NEW 5 /* allow-new-sources */ +#define IGMP_REPORT_BLOCK_OLD 6 /* block-old-sources */ + +/* + * Report types + */ +#define IGMP_MASK_CUR_STATE 0x01 /* Report current-state */ +#define IGMP_MASK_ALLOW_NEW 0x02 /* Report source as allow-new */ +#define IGMP_MASK_BLOCK_OLD 0x04 /* Report source as block-old */ +#define IGMP_MASK_TO_IN 0x08 /* Report source as to_in */ +#define IGMP_MASK_TO_EX 0x10 /* Report source as to_ex */ +#define IGMP_MASK_STATE_T1 0x20 /* State at T1 */ +#define IGMP_MASK_STATE_T2 0x40 /* State at T2 */ +#define IGMP_MASK_IF_STATE 0x80 /* Report current-state per interface */ + +#define IGMP_MASK_STATE_TX (IGMP_MASK_STATE_T1 | IGMP_MASK_STATE_T2) +#define IGMP_MASK_PENDING (IGMP_MASK_CUR_STATE | \ + IGMP_MASK_ALLOW_NEW | \ + IGMP_MASK_BLOCK_OLD) + +/* + * List identifiers + */ +#define IGMP_EXCLUDE_LIST 1 /* exclude list used to tag report */ +#define IGMP_INCLUDE_LIST 2 /* include list used to tag report */ +#define IGMP_RECORDED_LIST 3 /* recorded list used to tag report */ + void igmp_init(void); void igmp_input(struct mbuf *, int); void igmp_joingroup(struct in_multi *); @@ -100,6 +154,6 @@ #define IGMPCTL_NAMES { \ { 0, 0 }, \ - { "stats", CTLTYPE_STRUCT }, \ + { "stats", CTLTYPE_STRUCT } \ } #endif --- //depot/vendor/freebsd/src/sys/netinet/in.c 2007/03/29 21:42:52 +++ //depot/user/bms/netdev/sys/netinet/in.c 2007/04/09 20:23:13 @@ -49,11 +49,8 @@ #include #include #include - -#include +#include -static MALLOC_DEFINE(M_IPMADDR, "in_multi", "internet multicast address"); - static int in_mask2len(struct in_addr *); static void in_len2mask(struct in_addr *, int); static int in_lifaddr_ioctl(struct socket *, u_long, caddr_t, @@ -74,17 +71,6 @@ &sameprefixcarponly, 0, "Refuse to create same prefixes on different interfaces"); -/* - * The IPv4 multicast list (in_multihead and associated structures) are - * protected by the global in_multi_mtx. See in_var.h for more details. For - * now, in_multi_mtx is marked as recursible due to IGMP's calling back into - * ip_output() to send IGMP packets while holding the lock; this probably is - * not quite desirable. - */ -struct in_multihead in_multihead; /* XXX BSS initialization */ -struct mtx in_multi_mtx; -MTX_SYSINIT(in_multi_mtx, &in_multi_mtx, "in_multi_mtx", MTX_DEF | MTX_RECURSE); - extern struct inpcbinfo ripcbinfo; extern struct inpcbinfo udbinfo; @@ -1000,155 +986,6 @@ } /* - * Add an address to the list of IP multicast addresses for a given interface. - */ -struct in_multi * -in_addmulti(struct in_addr *ap, struct ifnet *ifp) -{ - struct in_multi *inm; - - inm = NULL; - - IFF_LOCKGIANT(ifp); - IN_MULTI_LOCK(); - - IN_LOOKUP_MULTI(*ap, ifp, inm); - if (inm != NULL) { - /* - * If we already joined this group, just bump the - * refcount and return it. - */ - KASSERT(inm->inm_refcount >= 1, - ("%s: bad refcount %d", __func__, inm->inm_refcount)); - ++inm->inm_refcount; - } else do { - struct sockaddr_in sin; - struct ifmultiaddr *ifma; - struct in_multi *ninm; - int error; - - bzero(&sin, sizeof sin); - sin.sin_family = AF_INET; - sin.sin_len = sizeof(struct sockaddr_in); - sin.sin_addr = *ap; - - /* - * Check if a link-layer group is already associated - * with this network-layer group on the given ifnet. - * If so, bump the refcount on the existing network-layer - * group association and return it. - */ - error = if_addmulti(ifp, (struct sockaddr *)&sin, &ifma); - if (error) - break; - if (ifma->ifma_protospec != NULL) { - inm = (struct in_multi *)ifma->ifma_protospec; -#ifdef INVARIANTS - if (inm->inm_ifma != ifma || inm->inm_ifp != ifp || - inm->inm_addr.s_addr != ap->s_addr) - panic("%s: ifma is inconsistent", __func__); -#endif - ++inm->inm_refcount; - break; - } - - /* - * A new membership is needed; construct it and - * perform the IGMP join. - */ - ninm = malloc(sizeof(*ninm), M_IPMADDR, M_NOWAIT | M_ZERO); - if (ninm == NULL) { - if_delmulti_ifma(ifma); - break; - } - ninm->inm_addr = *ap; - ninm->inm_ifp = ifp; - ninm->inm_ifma = ifma; - ninm->inm_refcount = 1; - ifma->ifma_protospec = ninm; - LIST_INSERT_HEAD(&in_multihead, ninm, inm_link); - - igmp_joingroup(ninm); - - inm = ninm; - } while (0); - - IN_MULTI_UNLOCK(); - IFF_UNLOCKGIANT(ifp); - - return (inm); -} - -/* - * Delete a multicast address record. - * It is OK to call this routine if the underlying ifnet went away. - * - * XXX: To deal with the ifp going away, we cheat; the link-layer code in net - * will set ifma_ifp to NULL when the associated ifnet instance is detached - * from the system. - * The only reason we need to violate layers and check ifma_ifp here at all - * is because certain hardware drivers still require Giant to be held, - * and it must always be taken before other locks. - */ -void -in_delmulti(struct in_multi *inm) -{ - struct ifnet *ifp; - - KASSERT(inm->inm_ifma != NULL, ("%s: no ifma", __func__)); - ifp = inm->inm_ifma->ifma_ifp; - - if (ifp != NULL) { - /* - * Sanity check that netinet's notion of ifp is the - * same as net's. - */ - KASSERT(inm->inm_ifp == ifp, ("%s: bad ifp", __func__)); - IFF_LOCKGIANT(ifp); - } - - IN_MULTI_LOCK(); - in_delmulti_locked(inm); - IN_MULTI_UNLOCK(); - - if (ifp != NULL) - IFF_UNLOCKGIANT(ifp); -} - -/* - * Delete a multicast address record, with locks held. - * - * It is OK to call this routine if the ifp went away. - * Assumes that caller holds the IN_MULTI lock, and that - * Giant was taken before other locks if required by the hardware. - */ -void -in_delmulti_locked(struct in_multi *inm) -{ - struct ifmultiaddr *ifma; - - IN_MULTI_LOCK_ASSERT(); - KASSERT(inm->inm_refcount >= 1, ("%s: freeing freed inm", __func__)); - - if (--inm->inm_refcount == 0) { - igmp_leavegroup(inm); - - ifma = inm->inm_ifma; -#ifdef DIAGNOSTIC - printf("%s: purging ifma %p\n", __func__, ifma); -#endif - KASSERT(ifma->ifma_protospec == inm, - ("%s: ifma_protospec != inm", __func__)); - ifma->ifma_protospec = NULL; - - LIST_REMOVE(inm, inm_link); - free(inm, M_IPMADDR); - - if_delmulti_ifma(ifma); - } -} - -/* * Delete all IPv4 multicast address records, and associated link-layer * multicast address records, associated with ifp. */ --- //depot/vendor/freebsd/src/sys/netinet/in.h 2007/02/27 14:46:47 +++ //depot/user/bms/netdev/sys/netinet/in.h 2007/04/12 09:52:50 @@ -84,6 +84,33 @@ #define _STRUCT_IN_ADDR_DECLARED #endif +#ifndef _SOCKLEN_T_DECLARED +typedef __socklen_t socklen_t; +#define _SOCKLEN_T_DECLARED +#endif + +/* Avoid collision with original definition in sys/socket.h. */ +#ifndef _STRUCT_SOCKADDR_STORAGE_DECLARED +/* + * RFC 2553: protocol-independent placeholder for socket addresses + */ +#define _SS_MAXSIZE 128U +#define _SS_ALIGNSIZE (sizeof(__int64_t)) +#define _SS_PAD1SIZE (_SS_ALIGNSIZE - sizeof(unsigned char) - \ + sizeof(sa_family_t)) +#define _SS_PAD2SIZE (_SS_MAXSIZE - sizeof(unsigned char) - \ + sizeof(sa_family_t) - _SS_PAD1SIZE - _SS_ALIGNSIZE) + +struct sockaddr_storage { + unsigned char ss_len; /* address length */ + sa_family_t ss_family; /* address family */ + char __ss_pad1[_SS_PAD1SIZE]; + __int64_t __ss_align; /* force desired struct alignment */ + char __ss_pad2[_SS_PAD2SIZE]; +}; +#define _STRUCT_SOCKADDR_STORAGE_DECLARED +#endif + /* Socket address, internet style. */ struct sockaddr_in { uint8_t sin_len; @@ -390,7 +417,8 @@ #define IP_RECVDSTADDR 7 /* bool; receive IP dst addr w/dgram */ #define IP_SENDSRCADDR IP_RECVDSTADDR /* cmsg_type to set src addr */ #define IP_RETOPTS 8 /* ip_opts; set/get IP options */ -#define IP_MULTICAST_IF 9 /* u_char; set/get IP multicast i/f */ +#define IP_MULTICAST_IF 9 /* struct in_addr *or* struct ip_mreqn; + * set/get IP multicast i/f */ #define IP_MULTICAST_TTL 10 /* u_char; set/get IP multicast ttl */ #define IP_MULTICAST_LOOP 11 /* u_char; set/get IP multicast loopback */ #define IP_ADD_MEMBERSHIP 12 /* ip_mreq; add an IP group membership */ @@ -435,6 +463,23 @@ #define IP_MINTTL 66 /* minimum TTL for packet or drop */ #define IP_DONTFRAG 67 /* don't fragment packet */ +/* IPv4 Source Filter Multicast API [RFC3678] */ +#define IP_ADD_SOURCE_MEMBERSHIP 70 /* join a source-specific group */ +#define IP_DROP_SOURCE_MEMBERSHIP 71 /* drop a single source */ +#define IP_BLOCK_SOURCE 72 /* block a source */ +#define IP_UNBLOCK_SOURCE 73 /* unblock a source */ + +/* The following option is private; do not use it from user applications. */ +#define IP_MSFILTER 74 /* set/get filter list */ + +/* Protocol Independent Multicast API [RFC3678] */ +#define MCAST_JOIN_GROUP 80 /* join an any-source group */ +#define MCAST_LEAVE_GROUP 81 /* leave all sources for group */ +#define MCAST_JOIN_SOURCE_GROUP 82 /* join a source-specific group */ +#define MCAST_LEAVE_SOURCE_GROUP 83 /* leave a single source */ +#define MCAST_BLOCK_SOURCE 84 /* block a source */ +#define MCAST_UNBLOCK_SOURCE 85 /* unblock a source */ + /* * Defaults and limits for options */ @@ -448,6 +493,7 @@ */ #define IP_MIN_MEMBERSHIPS 31 #define IP_MAX_MEMBERSHIPS 4095 +#define IP_MAX_SOURCE_FILTER 1024 /* # of filters per socket, per group */ /* * Argument structure for IP_ADD_MEMBERSHIP and IP_DROP_MEMBERSHIP. @@ -458,6 +504,82 @@ }; /* + * Modified argument structure for IP_MULTICAST_IF, obtained from Linux. + * This is used to specify an interface index for multicast sends, as + * the IPv4 legacy APIs do not support this (unless IP_SENDIF is available). + */ +struct ip_mreqn { + struct in_addr imr_multiaddr; /* IP multicast address of group */ + struct in_addr imr_address; /* local IP address of interface */ + int imr_ifindex; /* Interface index; cast to uint32_t */ +}; + +/* + * Argument structure for IPv4 Multicast Source Filter APIs. [RFC3678] + */ +struct ip_mreq_source { + struct in_addr imr_multiaddr; /* IP multicast address of group */ + struct in_addr imr_sourceaddr; /* IP address of source */ + struct in_addr imr_interface; /* local IP address of interface */ +}; + +/* + * Argument structures for Protocol-Independent Multicast Source + * Filter APIs. [RFC3678] + */ +struct group_req { + uint32_t gr_interface; /* interface index */ + struct sockaddr_storage gr_group; /* group address */ +}; + +struct group_source_req { + uint32_t gsr_interface; /* interface index */ + struct sockaddr_storage gsr_group; /* group address */ + struct sockaddr_storage gsr_source; /* source address */ +}; + +#ifndef __MSFILTERREQ_DEFINED +#define __MSFILTERREQ_DEFINED +/* + * The following structure is private; do not use it from user applications. + * It is used to communicate IP_MSFILTER/IPV6_MSFILTER information between + * the RFC 3678 libc functions and the kernel. + */ +struct __msfilterreq { + uint32_t msfr_ifindex; /* interface index */ + uint32_t msfr_fmode; /* filter mode for group */ + uint32_t msfr_nsrcs; /* # of sources in msfr_srcs */ + struct sockaddr_storage msfr_group; /* group address */ + struct sockaddr_storage *msfr_srcs; /* pointer to the first member + * of a contiguous array of + * sources to filter in full. + */ +}; +#endif + +struct sockaddr; + +/* + * Advanced (Full-state) APIs [RFC3678] + * The RFC specifies uint_t for the 6th argument to [sg]etsourcefilter(). + * We use uint32_t here to be consistent. + */ +int setipv4sourcefilter(int, struct in_addr, struct in_addr, uint32_t, + uint32_t, struct in_addr *); +int getipv4sourcefilter(int, struct in_addr, struct in_addr, uint32_t *, + uint32_t *, struct in_addr *); +int setsourcefilter(int, uint32_t, struct sockaddr *, socklen_t, + uint32_t, uint32_t, struct sockaddr_storage *); +int getsourcefilter(int, uint32_t, struct sockaddr *, socklen_t, + uint32_t *, uint32_t *, struct sockaddr_storage *); + +/* + * Filter modes; also used to represent per-socket filter mode internally. + */ +#define MCAST_INCLUDE 1 /* fmode: include these source(s) */ +#define MCAST_EXCLUDE 2 /* fmode: exclude these source(s) */ + +/* * Argument for IP_PORTRANGE: * - which range to search when port is unspecified at bind() or connect() */ --- //depot/vendor/freebsd/src/sys/netinet/in_pcb.c 2007/04/10 16:02:34 +++ //depot/user/bms/netdev/sys/netinet/in_pcb.c 2007/04/12 10:30:03 @@ -735,7 +735,8 @@ in_pcbremlists(inp); if (inp->inp_options) (void)m_free(inp->inp_options); - ip_freemoptions(inp->inp_moptions); + if (inp->inp_moptions != NULL) + inp_freemoptions(inp->inp_moptions); inp->inp_vflag = 0; #ifdef MAC --- //depot/vendor/freebsd/src/sys/netinet/in_var.h 2007/03/20 00:36:37 +++ //depot/user/bms/netdev/sys/netinet/in_var.h 2007/04/14 01:44:22 @@ -147,6 +147,12 @@ int rti_type; /* type of router which is querier on this interface */ int rti_time; /* # of slow timeouts since last old query */ SLIST_ENTRY(router_info) rti_list; +#ifdef notyet + int rti_timev1; /* IGMPv1 querier present */ + int rti_timev2; /* IGMPv2 querier present */ + int rti_timer; /* report to general query */ + int rti_qrv; /* querier robustness */ +#endif }; /* @@ -166,7 +172,43 @@ u_int inm_state; /* state of the membership */ struct router_info *inm_rti; /* router info*/ u_int inm_refcount; /* reference count */ +#ifdef notyet /* IGMPv3 source-specific multicast fields */ + TAILQ_HEAD(, in_msfentry) inm_msf; /* all active source filters */ + TAILQ_HEAD(, in_msfentry) inm_msf_record; /* recorded sources */ + TAILQ_HEAD(, in_msfentry) inm_msf_exclude; /* exclude sources */ + TAILQ_HEAD(, in_msfentry) inm_msf_include; /* include sources */ + /* XXX: should this lot go to the router_info structure? */ + /* XXX: can/should these be callouts? */ + /* IGMP protocol timers */ + int32_t inm_ti_curstate; /* current state timer */ + int32_t inm_ti_statechg; /* state change timer */ + /* IGMP report timers */ + uint16_t inm_rpt_statechg; /* state change report timer */ + uint16_t inm_rpt_toxx; /* fmode change report timer */ + /* IGMP protocol state */ + uint16_t inm_fmode; /* filter mode */ + uint32_t inm_recsrc_count; /* # of recorded sources */ + uint16_t inm_exclude_sock_count; /* # of exclude-mode sockets */ + uint16_t inm_gass_count; /* # of g-a-s queries */ +#endif +}; + +#ifdef notyet +/* + * Internet multicast source filter list. This list is used to store + * IP multicast source addresses for each membership on an interface. + * TODO: Allocate these structures using UMA. + * TODO: Find an easier way of linking the struct into two lists at once. + */ +struct in_msfentry { + TAILQ_ENTRY(in_msfentry) isf_link; /* next filter in all-list */ + TAILQ_ENTRY(in_msfentry) isf_next; /* next filter in queue */ + struct in_addr isf_addr; /* the address of this source */ + uint16_t isf_refcount; /* reference count */ + uint16_t isf_reporttag; /* what to report to the IGMP router */ + uint16_t isf_rexmit; /* retransmission state/count */ }; +#endif #ifdef _KERNEL @@ -246,6 +288,12 @@ } while(0) struct route; +struct ip_moptions; + +size_t imo_match_group(struct ip_moptions *, struct ifnet *, + struct sockaddr *); +struct in_msource *imo_match_source(struct ip_moptions *, size_t, + struct sockaddr *); struct in_multi *in_addmulti(struct in_addr *, struct ifnet *); void in_delmulti(struct in_multi *); void in_delmulti_locked(struct in_multi *); --- //depot/vendor/freebsd/src/sys/netinet/ip_carp.c 2007/02/02 12:27:11 +++ //depot/user/bms/netdev/sys/netinet/ip_carp.c 2007/04/06 23:54:30 @@ -380,6 +380,7 @@ sc->sc_imo.imo_membership = (struct in_multi **)malloc( (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_CARP, M_WAITOK); + sc->sc_imo.imo_mfilters = NULL; sc->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS; sc->sc_imo.imo_multicast_vif = -1; @@ -1397,6 +1398,8 @@ imo->imo_membership[n] = NULL; } } + KASSERT(imo->imo_mfilters == NULL, + ("%s: imo_mfilters != NULL", __func__)); imo->imo_num_memberships = 0; imo->imo_multicast_ifp = NULL; } --- //depot/vendor/freebsd/src/sys/netinet/ip_output.c 2007/03/23 09:47:19 +++ //depot/user/bms/netdev/sys/netinet/ip_output.c 2007/04/12 10:01:56 @@ -73,8 +73,6 @@ #include -static MALLOC_DEFINE(M_IPMOPTS, "ip_moptions", "internet multicast options"); - #define print_ip(x, a, y) printf("%s %d.%d.%d.%d%s",\ x, (ntohl(a.s_addr)>>24)&0xFF,\ (ntohl(a.s_addr)>>16)&0xFF,\ @@ -89,11 +87,8 @@ &mbuf_frag_size, 0, "Fragment outgoing mbufs to this size"); #endif -static struct ifnet *ip_multicast_if(struct in_addr *, int *); static void ip_mloopback (struct ifnet *, struct mbuf *, struct sockaddr_in *, int); -static int ip_getmoptions(struct inpcb *, struct sockopt *); -static int ip_setmoptions(struct inpcb *, struct sockopt *); extern struct protosw inetsw[]; @@ -932,13 +927,28 @@ break; #undef OPTSET + /* + * Multicast socket options are processed by the in_mcast + * module. + */ case IP_MULTICAST_IF: case IP_MULTICAST_VIF: case IP_MULTICAST_TTL: case IP_MULTICAST_LOOP: case IP_ADD_MEMBERSHIP: case IP_DROP_MEMBERSHIP: - error = ip_setmoptions(inp, sopt); + case IP_ADD_SOURCE_MEMBERSHIP: + case IP_DROP_SOURCE_MEMBERSHIP: + case IP_BLOCK_SOURCE: + case IP_UNBLOCK_SOURCE: + case IP_MSFILTER: + case MCAST_JOIN_GROUP: + case MCAST_LEAVE_GROUP: + case MCAST_JOIN_SOURCE_GROUP: + case MCAST_LEAVE_SOURCE_GROUP: + case MCAST_BLOCK_SOURCE: + case MCAST_UNBLOCK_SOURCE: + error = inp_setmoptions(inp, sopt); break; case IP_PORTRANGE: @@ -1097,11 +1107,16 @@ error = sooptcopyout(sopt, &optval, sizeof optval); break; + /* + * Multicast socket options are processed by the in_mcast + * module. + */ case IP_MULTICAST_IF: case IP_MULTICAST_VIF: case IP_MULTICAST_TTL: case IP_MULTICAST_LOOP: - error = ip_getmoptions(inp, sopt); + case IP_MSFILTER: + error = inp_getmoptions(inp, sopt); break; #if defined(IPSEC) || defined(FAST_IPSEC) @@ -1134,480 +1149,6 @@ } /* - * XXX - * The whole multicast option thing needs to be re-thought. - * Several of these options are equally applicable to non-multicast - * transmission, and one (IP_MULTICAST_TTL) totally duplicates a - * standard option (IP_TTL). - */ - -/* - * following RFC1724 section 3.3, 0.0.0.0/8 is interpreted as interface index. - */ -static struct ifnet * -ip_multicast_if(a, ifindexp) - struct in_addr *a; - int *ifindexp; -{ - int ifindex; - struct ifnet *ifp; - - if (ifindexp) - *ifindexp = 0; - if (ntohl(a->s_addr) >> 24 == 0) { - ifindex = ntohl(a->s_addr) & 0xffffff; - if (ifindex < 0 || if_index < ifindex) - return NULL; - ifp = ifnet_byindex(ifindex); - if (ifindexp) - *ifindexp = ifindex; - } else { - INADDR_TO_IFP(*a, ifp); - } - return ifp; -} - -/* - * Given an inpcb, return its multicast options structure pointer. Accepts - * an unlocked inpcb pointer, but will return it locked. May sleep. - */ -static struct ip_moptions * -ip_findmoptions(struct inpcb *inp) -{ - struct ip_moptions *imo; - struct in_multi **immp; - - INP_LOCK(inp); - if (inp->inp_moptions != NULL) - return (inp->inp_moptions); - - INP_UNLOCK(inp); - - imo = (struct ip_moptions*)malloc(sizeof(*imo), M_IPMOPTS, M_WAITOK); - immp = (struct in_multi **)malloc((sizeof(*immp) * IP_MIN_MEMBERSHIPS), - M_IPMOPTS, M_WAITOK); - - imo->imo_multicast_ifp = NULL; - imo->imo_multicast_addr.s_addr = INADDR_ANY; - imo->imo_multicast_vif = -1; - imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL; - imo->imo_multicast_loop = IP_DEFAULT_MULTICAST_LOOP; - imo->imo_num_memberships = 0; - imo->imo_max_memberships = IP_MIN_MEMBERSHIPS; - imo->imo_membership = immp; - - INP_LOCK(inp); - if (inp->inp_moptions != NULL) { - free(immp, M_IPMOPTS); - free(imo, M_IPMOPTS); - return (inp->inp_moptions); - } - inp->inp_moptions = imo; - return (imo); -} - -/* - * Set the IP multicast options in response to user setsockopt(). - */ -static int -ip_setmoptions(struct inpcb *inp, struct sockopt *sopt) -{ - int error = 0; - int i; - struct in_addr addr; - struct ip_mreq mreq; - struct ifnet *ifp; - struct ip_moptions *imo; - struct route ro; - struct sockaddr_in *dst; - int ifindex; - int s; - - switch (sopt->sopt_name) { - /* store an index number for the vif you wanna use in the send */ - case IP_MULTICAST_VIF: - if (legal_vif_num == 0) { - error = EOPNOTSUPP; - break; - } - error = sooptcopyin(sopt, &i, sizeof i, sizeof i); - if (error) - break; - if (!legal_vif_num(i) && (i != -1)) { - error = EINVAL; - break; - } - imo = ip_findmoptions(inp); - imo->imo_multicast_vif = i; - INP_UNLOCK(inp); - break; - - case IP_MULTICAST_IF: - /* - * Select the interface for outgoing multicast packets. - */ - error = sooptcopyin(sopt, &addr, sizeof addr, sizeof addr); - if (error) - break; - /* - * INADDR_ANY is used to remove a previous selection. - * When no interface is selected, a default one is - * chosen every time a multicast packet is sent. - */ - imo = ip_findmoptions(inp); - if (addr.s_addr == INADDR_ANY) { - imo->imo_multicast_ifp = NULL; - INP_UNLOCK(inp); - break; - } - /* - * The selected interface is identified by its local - * IP address. Find the interface and confirm that - * it supports multicasting. - */ - s = splimp(); - ifp = ip_multicast_if(&addr, &ifindex); - if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) { - INP_UNLOCK(inp); - splx(s); - error = EADDRNOTAVAIL; - break; - } - imo->imo_multicast_ifp = ifp; - if (ifindex) - imo->imo_multicast_addr = addr; - else - imo->imo_multicast_addr.s_addr = INADDR_ANY; - INP_UNLOCK(inp); - splx(s); - break; - - case IP_MULTICAST_TTL: - /* - * Set the IP time-to-live for outgoing multicast packets. - * The original multicast API required a char argument, - * which is inconsistent with the rest of the socket API. - * We allow either a char or an int. - */ - if (sopt->sopt_valsize == 1) { - u_char ttl; - error = sooptcopyin(sopt, &ttl, 1, 1); - if (error) - break; - imo = ip_findmoptions(inp); - imo->imo_multicast_ttl = ttl; - INP_UNLOCK(inp); - } else { - u_int ttl; - error = sooptcopyin(sopt, &ttl, sizeof ttl, - sizeof ttl); - if (error) - break; - if (ttl > 255) - error = EINVAL; - else { - imo = ip_findmoptions(inp); - imo->imo_multicast_ttl = ttl; - INP_UNLOCK(inp); - } - } - break; - - case IP_MULTICAST_LOOP: - /* - * Set the loopback flag for outgoing multicast packets. - * Must be zero or one. The original multicast API required a - * char argument, which is inconsistent with the rest - * of the socket API. We allow either a char or an int. - */ - if (sopt->sopt_valsize == 1) { - u_char loop; - error = sooptcopyin(sopt, &loop, 1, 1); - if (error) - break; - imo = ip_findmoptions(inp); - imo->imo_multicast_loop = !!loop; - INP_UNLOCK(inp); - } else { - u_int loop; - error = sooptcopyin(sopt, &loop, sizeof loop, - sizeof loop); - if (error) - break; - imo = ip_findmoptions(inp); - imo->imo_multicast_loop = !!loop; - INP_UNLOCK(inp); - } - break; - - case IP_ADD_MEMBERSHIP: - /* - * Add a multicast group membership. - * Group must be a valid IP multicast address. - */ - error = sooptcopyin(sopt, &mreq, sizeof mreq, sizeof mreq); - if (error) - break; - - if (!IN_MULTICAST(ntohl(mreq.imr_multiaddr.s_addr))) { - error = EINVAL; - break; - } - s = splimp(); - /* - * If no interface address was provided, use the interface of - * the route to the given multicast address. - */ - if (mreq.imr_interface.s_addr == INADDR_ANY) { - bzero((caddr_t)&ro, sizeof(ro)); - dst = (struct sockaddr_in *)&ro.ro_dst; - dst->sin_len = sizeof(*dst); - dst->sin_family = AF_INET; - dst->sin_addr = mreq.imr_multiaddr; - rtalloc_ign(&ro, RTF_CLONING); - if (ro.ro_rt == NULL) { - error = EADDRNOTAVAIL; - splx(s); - break; - } - ifp = ro.ro_rt->rt_ifp; - RTFREE(ro.ro_rt); - } - else { - ifp = ip_multicast_if(&mreq.imr_interface, NULL); - } - - /* - * See if we found an interface, and confirm that it - * supports multicast. - */ - if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) { - error = EADDRNOTAVAIL; - splx(s); - break; - } - /* - * See if the membership already exists or if all the - * membership slots are full. - */ - imo = ip_findmoptions(inp); - for (i = 0; i < imo->imo_num_memberships; ++i) { - if (imo->imo_membership[i]->inm_ifp == ifp && - imo->imo_membership[i]->inm_addr.s_addr - == mreq.imr_multiaddr.s_addr) - break; - } - if (i < imo->imo_num_memberships) { - INP_UNLOCK(inp); - error = EADDRINUSE; - splx(s); - break; - } - if (imo->imo_num_memberships == imo->imo_max_memberships) { - struct in_multi **nmships, **omships; - size_t newmax; - /* - * Resize the vector to next power-of-two minus 1. If the - * size would exceed the maximum then we know we've really - * run out of entries. Otherwise, we realloc() the vector - * with the INP lock held to avoid introducing a race. - */ - nmships = NULL; - omships = imo->imo_membership; - newmax = ((imo->imo_max_memberships + 1) * 2) - 1; - if (newmax <= IP_MAX_MEMBERSHIPS) { - nmships = (struct in_multi **)realloc(omships, -sizeof(*nmships) * newmax, M_IPMOPTS, M_NOWAIT); - if (nmships != NULL) { - imo->imo_membership = nmships; - imo->imo_max_memberships = newmax; - } - } - if (nmships == NULL) { - INP_UNLOCK(inp); - error = ETOOMANYREFS; - splx(s); - break; - } - } - /* - * Everything looks good; add a new record to the multicast - * address list for the given interface. - */ - if ((imo->imo_membership[i] = - in_addmulti(&mreq.imr_multiaddr, ifp)) == NULL) { - INP_UNLOCK(inp); - error = ENOBUFS; - splx(s); - break; - } - ++imo->imo_num_memberships; - INP_UNLOCK(inp); - splx(s); - break; - - case IP_DROP_MEMBERSHIP: - /* - * Drop a multicast group membership. - * Group must be a valid IP multicast address. - */ - error = sooptcopyin(sopt, &mreq, sizeof mreq, sizeof mreq); - if (error) - break; - - if (!IN_MULTICAST(ntohl(mreq.imr_multiaddr.s_addr))) { - error = EINVAL; - break; - } - - s = splimp(); - /* - * If an interface address was specified, get a pointer - * to its ifnet structure. - */ - if (mreq.imr_interface.s_addr == INADDR_ANY) - ifp = NULL; - else { - ifp = ip_multicast_if(&mreq.imr_interface, NULL); - if (ifp == NULL) { - error = EADDRNOTAVAIL; - splx(s); - break; - } - } - /* - * Find the membership in the membership array. - */ - imo = ip_findmoptions(inp); - for (i = 0; i < imo->imo_num_memberships; ++i) { - if ((ifp == NULL || - imo->imo_membership[i]->inm_ifp == ifp) && - imo->imo_membership[i]->inm_addr.s_addr == - mreq.imr_multiaddr.s_addr) - break; - } - if (i == imo->imo_num_memberships) { - INP_UNLOCK(inp); - error = EADDRNOTAVAIL; - splx(s); - break; - } - /* - * Give up the multicast address record to which the - * membership points. - */ - in_delmulti(imo->imo_membership[i]); - /* - * Remove the gap in the membership array. - */ - for (++i; i < imo->imo_num_memberships; ++i) - imo->imo_membership[i-1] = imo->imo_membership[i]; - --imo->imo_num_memberships; - INP_UNLOCK(inp); - splx(s); - break; - - default: - error = EOPNOTSUPP; - break; - } - - return (error); -} - -/* - * Return the IP multicast options in response to user getsockopt(). - */ -static int -ip_getmoptions(struct inpcb *inp, struct sockopt *sopt) -{ - struct ip_moptions *imo; - struct in_addr addr; - struct in_ifaddr *ia; - int error, optval; - u_char coptval; - - INP_LOCK(inp); - imo = inp->inp_moptions; - - error = 0; - switch (sopt->sopt_name) { - case IP_MULTICAST_VIF: - if (imo != NULL) - optval = imo->imo_multicast_vif; - else - optval = -1; - INP_UNLOCK(inp); - error = sooptcopyout(sopt, &optval, sizeof optval); - break; - - case IP_MULTICAST_IF: - if (imo == NULL || imo->imo_multicast_ifp == NULL) - addr.s_addr = INADDR_ANY; - else if (imo->imo_multicast_addr.s_addr) { - /* return the value user has set */ - addr = imo->imo_multicast_addr; - } else { - IFP_TO_IA(imo->imo_multicast_ifp, ia); - addr.s_addr = (ia == NULL) ? INADDR_ANY - : IA_SIN(ia)->sin_addr.s_addr; - } - INP_UNLOCK(inp); - error = sooptcopyout(sopt, &addr, sizeof addr); - break; - - case IP_MULTICAST_TTL: - if (imo == 0) - optval = coptval = IP_DEFAULT_MULTICAST_TTL; - else - optval = coptval = imo->imo_multicast_ttl; - INP_UNLOCK(inp); - if (sopt->sopt_valsize == 1) - error = sooptcopyout(sopt, &coptval, 1); - else - error = sooptcopyout(sopt, &optval, sizeof optval); - break; - - case IP_MULTICAST_LOOP: - if (imo == 0) - optval = coptval = IP_DEFAULT_MULTICAST_LOOP; - else - optval = coptval = imo->imo_multicast_loop; - INP_UNLOCK(inp); - if (sopt->sopt_valsize == 1) - error = sooptcopyout(sopt, &coptval, 1); - else - error = sooptcopyout(sopt, &optval, sizeof optval); - break; - - default: - INP_UNLOCK(inp); - error = ENOPROTOOPT; - break; - } - INP_UNLOCK_ASSERT(inp); - - return (error); -} - -/* - * Discard the IP multicast options. - */ -void -ip_freemoptions(imo) - register struct ip_moptions *imo; -{ - register int i; - - if (imo != NULL) { - for (i = 0; i < imo->imo_num_memberships; ++i) - in_delmulti(imo->imo_membership[i]); - free(imo->imo_membership, M_IPMOPTS); - free(imo, M_IPMOPTS); - } -} - -/* * Routine called from ip_output() to loop back a copy of an IP multicast * packet to the input queue of a specified interface. Note that this * calls the output routine of the loopback "driver", but with an interface --- //depot/vendor/freebsd/src/sys/netinet/ip_var.h 2007/04/04 15:32:08 +++ //depot/user/bms/netdev/sys/netinet/ip_var.h 2007/04/10 01:40:44 @@ -79,8 +79,28 @@ }; /* + * Multicast source list entry. + */ +struct in_msource { + TAILQ_ENTRY(in_msource) ims_next; /* next source */ + struct sockaddr_storage ims_addr; /* address of this source */ +}; + +/* + * Multicast filter descriptor; there is one instance per group membership + * on a socket, allocated as an expandable vector hung off ip_moptions. + * struct in_multi contains separate IPv4-stack-wide state for IGMPv3. + */ +struct in_mfilter { + uint16_t imf_fmode; /* filter mode for this socket/group */ + uint16_t imf_nsources; /* # of sources for this socket/group */ + TAILQ_HEAD(, in_msource) imf_sources; /* source list */ +}; + +/* * Structure attached to inpcb.ip_moptions and * passed to ip_output when IP multicast options are in use. + * This structure is lazy-allocated. */ struct ip_moptions { struct ifnet *imo_multicast_ifp; /* ifp for outgoing multicasts */ @@ -91,6 +111,7 @@ u_short imo_num_memberships; /* no. memberships this socket */ u_short imo_max_memberships; /* max memberships this socket */ struct in_multi **imo_membership; /* group memberships */ + struct in_mfilter *imo_mfilters; /* source filters */ }; struct ipstat { @@ -127,12 +148,11 @@ #ifdef _KERNEL -/* - * Flags passed to ip_output as last parameter. - */ -#define IP_FORWARDING 0x01 /* most of ip header exists */ -#define IP_RAWOUTPUT 0x02 /* raw ip header exists */ -#define IP_SENDONES 0x04 /* send all-ones broadcast */ +/* flags passed to ip_output as last parameter */ +#define IP_FORWARDING 0x1 /* most of ip header exists */ +#define IP_RAWOUTPUT 0x2 /* raw ip header exists */ +#define IP_SENDONES 0x4 /* send all-ones broadcast */ +#define IP_SENDTOIF 0x8 /* send on specific ifnet */ #define IP_ROUTETOIF SO_DONTROUTE /* 0x10 bypass routing tables */ #define IP_ALLOWBROADCAST SO_BROADCAST /* 0x20 can send broadcast packets */ @@ -167,12 +187,15 @@ extern int rsvp_on; extern struct pr_usrreqs rip_usrreqs; +void inp_freemoptions(struct ip_moptions *); +int inp_getmoptions(struct inpcb *, struct sockopt *); +int inp_setmoptions(struct inpcb *, struct sockopt *); + int ip_ctloutput(struct socket *, struct sockopt *sopt); void ip_drain(void); void ip_fini(void *xtp); int ip_fragment(struct ip *ip, struct mbuf **m_frag, int mtu, u_long if_hwassist_flags, int sw_csum); -void ip_freemoptions(struct ip_moptions *); void ip_forward(struct mbuf *m, int srcrt); void ip_init(void); extern int --- //depot/vendor/freebsd/src/sys/netinet/sctp_pcb.c 2007/04/03 11:17:30 +++ //depot/user/bms/netdev/sys/netinet/sctp_pcb.c 2007/04/09 20:23:13 @@ -2723,7 +2723,7 @@ ip_pcb->inp_options = 0; } if (ip_pcb->inp_moptions) { - ip_freemoptions(ip_pcb->inp_moptions); + inp_freemoptions(ip_pcb->inp_moptions); ip_pcb->inp_moptions = 0; } #ifdef INET6 --- //depot/vendor/freebsd/src/sys/netinet/udp_usrreq.c 2007/03/08 15:32:22 +++ //depot/user/bms/netdev/sys/netinet/udp_usrreq.c 2007/04/14 01:35:16 @@ -113,10 +113,6 @@ SYSCTL_INT(_net_inet_udp, OID_AUTO, blackhole, CTLFLAG_RW, &blackhole, 0, "Do not send port unreachables for refused connects"); -static int strict_mcast_mship = 0; -SYSCTL_INT(_net_inet_udp, OID_AUTO, strict_mcast_mship, CTLFLAG_RW, - &strict_mcast_mship, 0, "Only send multicast to member sockets"); - struct inpcbhead udb; /* from udp_var.h */ struct inpcbinfo udbinfo; @@ -173,6 +169,7 @@ int iphlen = off; struct ip *ip; struct udphdr *uh; + struct ifnet *ifp; struct inpcb *inp; int len; struct ip save_ip; @@ -181,6 +178,7 @@ struct m_tag *fwd_tag; #endif + ifp = m->m_pkthdr.rcvif; udpstat.udps_ipackets++; /* @@ -296,25 +294,10 @@ INP_INFO_RLOCK(&udbinfo); if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) || - in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) { + in_broadcast(ip->ip_dst, ifp)) { struct inpcb *last; + struct ip_moptions *imo; - /* - * Deliver a multicast or broadcast datagram to *all* sockets - * for which the local and remote addresses and ports match - * those of the incoming datagram. This allows more than one - * process to receive multi/broadcasts on the same port. - * (This really ought to be done for unicast datagrams as - * well, but that would cause problems with existing - * applications that open both address-specific sockets and a - * wildcard socket listening to the same port -- they would - * end up receiving duplicates of every unicast datagram. - * Those applications open the multiple sockets to overcome - * an inadequacy of the UDP socket interface, but for - * backwards compatibility we avoid the problem here rather - * than fixing the interface. Maybe 4.5BSD will remedy - * this?) - */ last = NULL; LIST_FOREACH(inp, &udb, inp_list) { if (inp->inp_lport != uh->uh_dport) @@ -323,45 +306,83 @@ if ((inp->inp_vflag & INP_IPV4) == 0) continue; #endif - if (inp->inp_laddr.s_addr != INADDR_ANY) { - if (inp->inp_laddr.s_addr != ip->ip_dst.s_addr) + if (inp->inp_laddr.s_addr != INADDR_ANY && + inp->inp_laddr.s_addr != ip->ip_dst.s_addr) + continue; + if (inp->inp_faddr.s_addr != INADDR_ANY && + inp->inp_faddr.s_addr != ip->ip_src.s_addr) continue; - } - if (inp->inp_faddr.s_addr != INADDR_ANY) { - if (inp->inp_faddr.s_addr != - ip->ip_src.s_addr || - inp->inp_fport != uh->uh_sport) + /* + * XXX: Do not check source port of incoming datagram + * unless inp_connect() has been called to bind the + * fport part of the 4-tuple; the source could be + * trying to talk to us with an ephemeral port. + */ + if (inp->inp_fport != 0 && + inp->inp_fport != uh->uh_sport) continue; - } + + INP_LOCK(inp); /* - * Check multicast packets to make sure they are only - * sent to sockets with multicast memberships for the - * packet's destination address and arrival interface + * Handle socket delivery policy for any-source + * and source-specific multicast. [RFC3678] */ -#define MSHIP(_inp, n) ((_inp)->inp_moptions->imo_membership[(n)]) -#define NMSHIPS(_inp) ((_inp)->inp_moptions->imo_num_memberships) - INP_LOCK(inp); - if (strict_mcast_mship && inp->inp_moptions != NULL) { - int mship, foundmship = 0; + imo = inp->inp_moptions; + if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) && + imo != NULL) { + struct sockaddr_in sin; + struct in_msource *ims; + int blocked, mode; + size_t idx; + + bzero(&sin, sizeof(struct sockaddr_in)); + sin.sin_len = sizeof(struct sockaddr_in); + sin.sin_family = AF_INET; + sin.sin_addr = ip->ip_dst; - for (mship = 0; mship < NMSHIPS(inp); - mship++) { - if (MSHIP(inp, mship)->inm_addr.s_addr - == ip->ip_dst.s_addr && - MSHIP(inp, mship)->inm_ifp - == m->m_pkthdr.rcvif) { - foundmship = 1; - break; + blocked = 0; + idx = imo_match_group(imo, ifp, + (struct sockaddr *)&sin); + if (idx == -1) { + /* + * No group membership for this socket. + * Do not bump udps_noportbcast, as + * this will happen further down. + */ + blocked++; + } else { + /* + * Check for a multicast source filter + * entry on this socket for this group. + * MCAST_EXCLUDE is the default + * behaviour. It means default accept; + * entries, if present, denote sources + * to be excluded from delivery. + */ + ims = imo_match_source(imo, idx, + (struct sockaddr *)&udp_in); + mode = imo->imo_mfilters[idx].imf_fmode; + if ((ims != NULL && + mode == MCAST_EXCLUDE) || + (ims == NULL && + mode == MCAST_INCLUDE)) { +#ifdef DIAGNOSTIC + if (bootverbose) { + printf("%s: blocked by" + " source filter\n", + __func__); + } +#endif + udpstat.udps_filtermcast++; + blocked++; } } - if (foundmship == 0) { + if (blocked != 0) { INP_UNLOCK(inp); continue; } } -#undef NMSHIPS -#undef MSHIP if (last != NULL) { struct mbuf *n; @@ -405,7 +426,7 @@ * Locate pcb for datagram. */ inp = in_pcblookup_hash(&udbinfo, ip->ip_src, uh->uh_sport, - ip->ip_dst, uh->uh_dport, 1, m->m_pkthdr.rcvif); + ip->ip_dst, uh->uh_dport, 1, ifp); if (inp == NULL) { if (udp_log_in_vain) { char buf[4*sizeof "123"]; --- //depot/vendor/freebsd/src/sys/netinet/udp_var.h 2007/02/20 10:22:30 +++ //depot/user/bms/netdev/sys/netinet/udp_var.h 2007/04/04 22:38:45 @@ -68,6 +68,7 @@ u_long udps_fastout; /* output packets on fast path */ /* of no socket on port, arrived as multicast */ u_long udps_noportmcast; + u_long udps_filtermcast; /* blocked by multicast filter */ }; /* --- //depot/vendor/freebsd/src/sys/netinet6/in6.h 2006/03/28 12:52:24 +++ //depot/user/bms/netdev/sys/netinet6/in6.h 2007/04/04 18:35:48 @@ -467,6 +467,14 @@ * the source address. */ +/* + * The following option is private; do not use it from user applications. + * It is deliberately defined to the same value as IP_MSFILTER. + */ +#define IPV6_MSFILTER 74 /* struct __msfilterreq; + * set/get multicast source filter list. + */ + /* to define items, should talk with KAME guys first, for *BSD compatibility */ #define IPV6_RTHDR_LOOSE 0 /* this hop need not be a neighbor. XXX old spec */ @@ -487,6 +495,18 @@ unsigned int ipv6mr_interface; }; +#ifdef notyet +/* + * Argument structure for IPV6_ADD_SOURCE_MEMBERSHIP, + * IPV6_DROP_SOURCE_MEMBERSHIP, IPV6_BLOCK_SOURCE, and IPV6_UNBLOCK_SOURCE. + */ +struct ipv6_mreq_source { + struct in6_addr ipv6mr_multiaddr; + struct in6_addr ipv6mr_sourceaddr; + uint32_t ipv6mr_interface; +}; +#endif + /* * IPV6_PKTINFO: Packet information(RFC2292 sec 5) */ --- //depot/vendor/freebsd/src/sys/netinet6/in6_pcb.c 2006/11/06 13:43:21 +++ //depot/user/bms/netdev/sys/netinet6/in6_pcb.c 2007/04/09 20:23:13 @@ -458,7 +458,8 @@ /* Check and free IPv4 related resources in case of mapped addr */ if (inp->inp_options) (void)m_free(inp->inp_options); - ip_freemoptions(inp->inp_moptions); + if (inp->inp_moptions != NULL) + inp_freemoptions(inp->inp_moptions); inp->inp_vflag = 0; INP_UNLOCK(inp); uma_zfree(ipi->ipi_zone, inp); --- //depot/vendor/freebsd/src/sys/sys/param.h 2007/04/08 22:47:33 +++ //depot/user/bms/netdev/sys/sys/param.h 2007/04/10 00:36:30 @@ -57,7 +57,7 @@ * is created, otherwise 1. */ #undef __FreeBSD_version -#define __FreeBSD_version 700037 /* Master, propagated to newvers */ +#define __FreeBSD_version 700038 /* Master, propagated to newvers */ #ifndef LOCORE #include --- //depot/vendor/freebsd/src/sys/sys/socket.h 2006/11/03 15:27:11 +++ //depot/user/bms/netdev/sys/sys/socket.h 2007/03/26 22:37:58 @@ -234,6 +234,7 @@ }; #endif +#ifndef _STRUCT_SOCKADDR_STORAGE_DECLARED /* * RFC 2553: protocol-independent placeholder for socket addresses */ @@ -251,6 +252,8 @@ __int64_t __ss_align; /* force desired struct alignment */ char __ss_pad2[_SS_PAD2SIZE]; }; +#define _STRUCT_SOCKADDR_STORAGE_DECLARED +#endif #if __BSD_VISIBLE /* --- //depot/vendor/freebsd/src/usr.bin/netstat/inet.c 2007/02/27 02:39:57 +++ //depot/user/bms/netdev/usr.bin/netstat/inet.c 2007/04/05 00:43:56 @@ -513,7 +513,7 @@ p1a(udps_nosum, "\t%lu with no checksum\n"); p1a(udps_noport, "\t%lu dropped due to no socket\n"); p(udps_noportbcast, - "\t%lu broadcast/multicast datagram%s dropped due to no socket\n"); + "\t%lu broadcast/multicast datagram%s undelivered\n"); p1a(udps_fullsock, "\t%lu dropped due to full socket buffers\n"); p1a(udpps_pcbhashmiss, "\t%lu not for hashed pcb\n"); delivered = udpstat.udps_ipackets - @@ -526,6 +526,9 @@ if (delivered || sflag <= 1) printf("\t%lu delivered\n", delivered); p(udps_opackets, "\t%lu datagram%s output\n"); + /* the next statistic is cumulative in udps_noportbcast */ + p(udps_filtermcast, + "\t%lu time%s multicast source filter matched\n"); #undef p #undef p1a } --- //depot/vendor/freebsd/src/usr.sbin/mtest/mtest.c 2007/03/08 22:41:04 +++ //depot/user/bms/netdev/usr.sbin/mtest/mtest.c 2007/04/04 18:35:48 @@ -55,6 +55,15 @@ #include #include +/* The following two socket options are private to the kernel and libc. */ + +#ifndef IP_SETMSFILTER +#define IP_SETMSFILTER 74 /* atomically set filter list */ +#endif +#ifndef IP_GETMSFILTER +#define IP_GETMSFILTER 75 /* get filter list */ +#endif + static void process_file(char *, int); static void process_cmd(char*, int, FILE *fp); static void usage(void); @@ -135,14 +144,14 @@ { char str1[STR_SIZE]; char str2[STR_SIZE]; + char str3[STR_SIZE]; #ifdef WITH_IGMPV3 - char str3[STR_SIZE]; char filtbuf[IP_MSFILTER_SIZE(MAX_ADDRS)]; #endif struct ifreq ifr; struct ip_mreq imr; + struct ip_mreq_source imrs; #ifdef WITH_IGMPV3 - struct ip_mreq_source imrs; struct ip_msfilter *imsfp; #endif char *line; @@ -256,6 +265,7 @@ */ case 'i': case 'e': + /* XXX: SIOCSIPMSFILTER will be made an internal API. */ if ((sscanf(line, "%s %s %d", str1, str2, &n)) != 3) { printf("-1\n"); break; @@ -284,10 +294,13 @@ else printf("ok\n"); break; +#endif /* WITH_IGMPV3 */ /* * Allow or block traffic from a source, using the * delta based api. + * XXX: Currently we allow this to be used with the ASM-only + * implementation of RFC3678 in FreeBSD 7. */ case 't': case 'b': @@ -302,6 +315,8 @@ break; } +#ifdef WITH_IGMPV3 + /* XXX: SIOCSIPMSFILTER will be made an internal API. */ /* First determine out current filter mode. */ imsfp = (struct ip_msfilter *)filtbuf; imsfp->imsf_multiaddr.s_addr = imrs.imr_multiaddr.s_addr; @@ -325,13 +340,22 @@ opt = (*cmd == 't') ? IP_ADD_SOURCE_MEMBERSHIP : IP_DROP_SOURCE_MEMBERSHIP; } +#else /* !WITH_IGMPV3 */ + /* + * Don't look before we leap; we may only block or unblock + * sources on a socket in exclude mode. + */ + opt = (*cmd == 't') ? IP_UNBLOCK_SOURCE : IP_BLOCK_SOURCE; +#endif /* WITH_IGMPV3 */ if (setsockopt(s, IPPROTO_IP, opt, &imrs, sizeof(imrs)) == -1) warn("ioctl IP_ADD_SOURCE_MEMBERSHIP/IP_DROP_SOURCE_MEMBERSHIP/IP_UNBLOCK_SOURCE/IP_BLOCK_SOURCE"); else printf("ok\n"); break; +#ifdef WITH_IGMPV3 case 'g': + /* XXX: SIOCSIPMSFILTER will be made an internal API. */ if ((sscanf(line, "%s %s %d", str1, str2, &n)) != 3) { printf("-1\n"); break; @@ -360,11 +384,11 @@ printf("%s\n", inet_ntoa(imsfp->imsf_slist[i])); } break; -#else /* !WITH_IGMPV3 */ +#endif /* !WITH_IGMPV3 */ + +#ifndef WITH_IGMPV3 case 'i': case 'e': - case 't': - case 'b': case 'g': printf("warning: IGMPv3 is not supported by this version " "of FreeBSD; command ignored.\n"); @@ -389,11 +413,15 @@ printf("d ifname e.e.e.e.e.e - delete ether multicast address\n"); printf("m ifname 1/0 - set/clear ether allmulti flag\n"); printf("p ifname 1/0 - set/clear ether promisc flag\n"); +#ifdef WITH_IGMPv3 printf("i g.g.g.g i.i.i.i n - set n include mode src filter\n"); printf("e g.g.g.g i.i.i.i n - set n exclude mode src filter\n"); +#endif printf("t g.g.g.g i.i.i.i s.s.s.s - allow traffic from src\n"); printf("b g.g.g.g i.i.i.i s.s.s.s - block traffic from src\n"); +#ifdef WITH_IGMPV3 printf("g g.g.g.g i.i.i.i n - get and show n src filters\n"); +#endif printf("f filename - read command(s) from file\n"); printf("s seconds - sleep for some time\n"); printf("q - quit\n");