Index: head/sys/netinet/igmp.c =================================================================== --- head/sys/netinet/igmp.c (revision 12703) +++ head/sys/netinet/igmp.c (revision 12704) @@ -1,616 +1,616 @@ /* * Copyright (c) 1988 Stephen Deering. * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Stephen Deering of Stanford University. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)igmp.c 8.1 (Berkeley) 7/19/93 - * $Id: igmp.c,v 1.13 1995/11/14 20:33:52 phk Exp $ + * $Id: igmp.c,v 1.14 1995/12/02 19:37:52 bde Exp $ */ /* * Internet Group Management Protocol (IGMP) routines. * * Written by Steve Deering, Stanford, May 1988. * Modified by Rosen Sharma, Stanford, Aug 1994. * Modified by Bill Fenner, Xerox PARC, Feb 1995. * * MULTICAST Revision: 3.3.1.2 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -extern int fill_rti __P((struct in_multi *inm)); -extern struct router_info * +static int fill_rti __P((struct in_multi *inm)); +static struct router_info * find_rti __P((struct ifnet *ifp)); -struct igmpstat igmpstat; +static struct igmpstat igmpstat; SYSCTL_STRUCT(_net_inet_igmp, IGMPCTL_STATS, stats, CTLFLAG_RD, &igmpstat, igmpstat, ""); static int igmp_timers_are_running; static u_long igmp_all_hosts_group; static u_long igmp_local_group; static u_long igmp_local_group_mask; static struct router_info *Head; static void igmp_sendpkt(struct in_multi *, int); static void igmp_sendleave(struct in_multi *); void igmp_init() { /* * To avoid byte-swapping the same value over and over again. */ igmp_all_hosts_group = htonl(INADDR_ALLHOSTS_GROUP); igmp_local_group = htonl(0xe0000000); /* 224.0.0.0 */ igmp_local_group_mask = htonl(0xffffff00); /* ........^ */ igmp_timers_are_running = 0; Head = (struct router_info *) 0; } -int +static int fill_rti(inm) struct in_multi *inm; { register struct router_info *rti = Head; #ifdef IGMP_DEBUG printf("[igmp.c, _fill_rti] --> entering \n"); #endif while (rti) { if (rti->ifp == inm->inm_ifp) { inm->inm_rti = rti; #ifdef IGMP_DEBUG printf("[igmp.c, _fill_rti] --> found old entry \n"); #endif if (rti->type == IGMP_OLD_ROUTER) return IGMP_HOST_MEMBERSHIP_REPORT; else return IGMP_HOST_NEW_MEMBERSHIP_REPORT; } rti = rti->next; } MALLOC(rti, struct router_info *, sizeof *rti, M_MRTABLE, M_NOWAIT); rti->ifp = inm->inm_ifp; rti->type = IGMP_NEW_ROUTER; rti->time = IGMP_AGE_THRESHOLD; rti->next = Head; Head = rti; inm->inm_rti = rti; #ifdef IGMP_DEBUG printf("[igmp.c, _fill_rti] --> created new entry \n"); #endif return IGMP_HOST_NEW_MEMBERSHIP_REPORT; } -struct router_info * +static struct router_info * find_rti(ifp) struct ifnet *ifp; { register struct router_info *rti = Head; #ifdef IGMP_DEBUG printf("[igmp.c, _find_rti] --> entering \n"); #endif while (rti) { if (rti->ifp == ifp) { #ifdef IGMP_DEBUG printf("[igmp.c, _find_rti] --> found old entry \n"); #endif return rti; } rti = rti->next; } MALLOC(rti, struct router_info *, sizeof *rti, M_MRTABLE, M_NOWAIT); rti->ifp = ifp; rti->type = IGMP_NEW_ROUTER; rti->time = IGMP_AGE_THRESHOLD; rti->next = Head; Head = rti; #ifdef IGMP_DEBUG printf("[igmp.c, _find_rti] --> created an entry \n"); #endif return rti; } void igmp_input(m, iphlen) register struct mbuf *m; register int iphlen; { register struct igmp *igmp; register struct ip *ip; register int igmplen; register struct ifnet *ifp = m->m_pkthdr.rcvif; register int minlen; register struct in_multi *inm; register struct in_ifaddr *ia; struct in_multistep step; struct router_info *rti; int timer; /** timer value in the igmp query header **/ ++igmpstat.igps_rcv_total; ip = mtod(m, struct ip *); igmplen = ip->ip_len; /* * Validate lengths */ if (igmplen < IGMP_MINLEN) { ++igmpstat.igps_rcv_tooshort; m_freem(m); return; } minlen = iphlen + IGMP_MINLEN; if ((m->m_flags & M_EXT || m->m_len < minlen) && (m = m_pullup(m, minlen)) == 0) { ++igmpstat.igps_rcv_tooshort; return; } /* * Validate checksum */ m->m_data += iphlen; m->m_len -= iphlen; igmp = mtod(m, struct igmp *); if (in_cksum(m, igmplen)) { ++igmpstat.igps_rcv_badsum; m_freem(m); return; } m->m_data -= iphlen; m->m_len += iphlen; ip = mtod(m, struct ip *); timer = igmp->igmp_code * PR_FASTHZ / IGMP_TIMER_SCALE; rti = find_rti(ifp); switch (igmp->igmp_type) { case IGMP_HOST_MEMBERSHIP_QUERY: ++igmpstat.igps_rcv_queries; if (ifp->if_flags & IFF_LOOPBACK) break; if (igmp->igmp_code == 0) { rti->type = IGMP_OLD_ROUTER; rti->time = 0; /* ** Do exactly as RFC 1112 says */ if (ip->ip_dst.s_addr != igmp_all_hosts_group) { ++igmpstat.igps_rcv_badqueries; m_freem(m); return; } /* * Start the timers in all of our membership records for * the interface on which the query arrived, except those * that are already running and those that belong to a * "local" group (224.0.0.X). */ IN_FIRST_MULTI(step, inm); while (inm != NULL) { if (inm->inm_ifp == ifp && inm->inm_timer == 0 && ((inm->inm_addr.s_addr & igmp_local_group_mask) != igmp_local_group)) { inm->inm_state = IGMP_DELAYING_MEMBER; inm->inm_timer = IGMP_RANDOM_DELAY( IGMP_MAX_HOST_REPORT_DELAY * PR_FASTHZ ); igmp_timers_are_running = 1; } IN_NEXT_MULTI(step, inm); } } else { /* ** New Router */ if (!(m->m_flags & M_MCAST)) { ++igmpstat.igps_rcv_badqueries; m_freem(m); return; } /* * - Start the timers in all of our membership records * that the query applies to for the interface on * which the query arrived excl. those that belong * to a "local" group (224.0.0.X) * - For timers already running check if they need to * be reset. * - Use the igmp->igmp_code field as the maximum * delay possible */ IN_FIRST_MULTI(step, inm); while (inm != NULL) { if (inm->inm_ifp == ifp && (inm->inm_addr.s_addr & igmp_local_group_mask) != igmp_local_group && (ip->ip_dst.s_addr == igmp_all_hosts_group || ip->ip_dst.s_addr == inm->inm_addr.s_addr)) { switch(inm->inm_state) { case IGMP_IDLE_MEMBER: case IGMP_LAZY_MEMBER: case IGMP_AWAKENING_MEMBER: inm->inm_timer = IGMP_RANDOM_DELAY(timer); igmp_timers_are_running = 1; inm->inm_state = IGMP_DELAYING_MEMBER; break; case IGMP_DELAYING_MEMBER: if (inm->inm_timer > timer) { inm->inm_timer = IGMP_RANDOM_DELAY(timer); igmp_timers_are_running = 1; inm->inm_state = IGMP_DELAYING_MEMBER; } break; case IGMP_SLEEPING_MEMBER: inm->inm_state = IGMP_AWAKENING_MEMBER; break; } } IN_NEXT_MULTI(step, inm); } } break; case IGMP_HOST_MEMBERSHIP_REPORT: /* * an old report */ ++igmpstat.igps_rcv_reports; if (ifp->if_flags & IFF_LOOPBACK) break; if (!IN_MULTICAST(ntohl(igmp->igmp_group.s_addr)) || igmp->igmp_group.s_addr != ip->ip_dst.s_addr) { ++igmpstat.igps_rcv_badreports; m_freem(m); return; } /* * KLUDGE: if the IP source address of the report has an * unspecified (i.e., zero) subnet number, as is allowed for * a booting host, replace it with the correct subnet number * so that a process-level multicast routing demon can * determine which subnet it arrived from. This is necessary * to compensate for the lack of any way for a process to * determine the arrival interface of an incoming packet. */ if ((ntohl(ip->ip_src.s_addr) & IN_CLASSA_NET) == 0) { IFP_TO_IA(ifp, ia); if (ia) ip->ip_src.s_addr = htonl(ia->ia_subnet); } /* * If we belong to the group being reported, stop * our timer for that group. */ IN_LOOKUP_MULTI(igmp->igmp_group, ifp, inm); if (inm != NULL) { inm->inm_timer = 0; ++igmpstat.igps_rcv_ourreports; switch(inm->inm_state){ case IGMP_IDLE_MEMBER: case IGMP_LAZY_MEMBER: case IGMP_AWAKENING_MEMBER: case IGMP_SLEEPING_MEMBER: inm->inm_state = IGMP_SLEEPING_MEMBER; break; case IGMP_DELAYING_MEMBER: if (inm->inm_rti->type == IGMP_OLD_ROUTER) inm->inm_state = IGMP_LAZY_MEMBER; else inm->inm_state = IGMP_SLEEPING_MEMBER; break; } } break; case IGMP_HOST_NEW_MEMBERSHIP_REPORT: /* * a new report */ /* * We can get confused and think there's someone * else out there if we are a multicast router. * For fast leave to work, we have to know that * we are the only member. */ IFP_TO_IA(ifp, ia); if (ia && ip->ip_src.s_addr == IA_SIN(ia)->sin_addr.s_addr) break; ++igmpstat.igps_rcv_reports; if (ifp->if_flags & IFF_LOOPBACK) break; if (!IN_MULTICAST(ntohl(igmp->igmp_group.s_addr)) || igmp->igmp_group.s_addr != ip->ip_dst.s_addr) { ++igmpstat.igps_rcv_badreports; m_freem(m); return; } /* * KLUDGE: if the IP source address of the report has an * unspecified (i.e., zero) subnet number, as is allowed for * a booting host, replace it with the correct subnet number * so that a process-level multicast routing demon can * determine which subnet it arrived from. This is necessary * to compensate for the lack of any way for a process to * determine the arrival interface of an incoming packet. */ if ((ntohl(ip->ip_src.s_addr) & IN_CLASSA_NET) == 0) { /* #ifndef MROUTING XXX - I don't think the ifdef is necessary */ IFP_TO_IA(ifp, ia); /* #endif */ if (ia) ip->ip_src.s_addr = htonl(ia->ia_subnet); } /* * If we belong to the group being reported, stop * our timer for that group. */ IN_LOOKUP_MULTI(igmp->igmp_group, ifp, inm); if (inm != NULL) { inm->inm_timer = 0; ++igmpstat.igps_rcv_ourreports; switch(inm->inm_state){ case IGMP_DELAYING_MEMBER: case IGMP_IDLE_MEMBER: inm->inm_state = IGMP_LAZY_MEMBER; break; case IGMP_AWAKENING_MEMBER: inm->inm_state = IGMP_LAZY_MEMBER; break; case IGMP_LAZY_MEMBER: case IGMP_SLEEPING_MEMBER: break; } } } /* * Pass all valid IGMP packets up to any process(es) listening * on a raw IGMP socket. */ rip_input(m); } void igmp_joingroup(inm) struct in_multi *inm; { int s = splnet(); inm->inm_state = IGMP_IDLE_MEMBER; if ((inm->inm_addr.s_addr & igmp_local_group_mask) == igmp_local_group || inm->inm_ifp->if_flags & IFF_LOOPBACK) inm->inm_timer = 0; else { igmp_sendpkt(inm,fill_rti(inm)); inm->inm_timer = IGMP_RANDOM_DELAY( IGMP_MAX_HOST_REPORT_DELAY*PR_FASTHZ); inm->inm_state = IGMP_DELAYING_MEMBER; igmp_timers_are_running = 1; } splx(s); } void igmp_leavegroup(inm) struct in_multi *inm; { switch(inm->inm_state) { case IGMP_DELAYING_MEMBER: case IGMP_IDLE_MEMBER: if (((inm->inm_addr.s_addr & igmp_local_group_mask) != igmp_local_group) && !(inm->inm_ifp->if_flags & IFF_LOOPBACK)) if (inm->inm_rti->type != IGMP_OLD_ROUTER) igmp_sendleave(inm); break; case IGMP_LAZY_MEMBER: case IGMP_AWAKENING_MEMBER: case IGMP_SLEEPING_MEMBER: break; } } void igmp_fasttimo() { register struct in_multi *inm; struct in_multistep step; int s; /* * Quick check to see if any work needs to be done, in order * to minimize the overhead of fasttimo processing. */ if (!igmp_timers_are_running) return; s = splnet(); igmp_timers_are_running = 0; IN_FIRST_MULTI(step, inm); while (inm != NULL) { if (inm->inm_timer == 0) { /* do nothing */ } else if (--inm->inm_timer == 0) { if (inm->inm_state == IGMP_DELAYING_MEMBER) { if (inm->inm_rti->type == IGMP_OLD_ROUTER) igmp_sendpkt(inm, IGMP_HOST_MEMBERSHIP_REPORT); else igmp_sendpkt(inm, IGMP_HOST_NEW_MEMBERSHIP_REPORT); inm->inm_state = IGMP_IDLE_MEMBER; } } else { igmp_timers_are_running = 1; } IN_NEXT_MULTI(step, inm); } splx(s); } void igmp_slowtimo() { int s = splnet(); register struct router_info *rti = Head; #ifdef IGMP_DEBUG printf("[igmp.c,_slowtimo] -- > entering \n"); #endif while (rti) { rti->time ++; if (rti->time >= IGMP_AGE_THRESHOLD){ rti->type = IGMP_NEW_ROUTER; rti->time = IGMP_AGE_THRESHOLD; } rti = rti->next; } #ifdef IGMP_DEBUG printf("[igmp.c,_slowtimo] -- > exiting \n"); #endif splx(s); } static void igmp_sendpkt(inm, type) struct in_multi *inm; int type; { struct mbuf *m; struct igmp *igmp; struct ip *ip; struct ip_moptions *imo; MGETHDR(m, M_DONTWAIT, MT_HEADER); if (m == NULL) return; MALLOC(imo, struct ip_moptions *, sizeof *imo, M_IPMOPTS, M_DONTWAIT); if (!imo) { m_free(m); return; } m->m_pkthdr.rcvif = loif; m->m_pkthdr.len = sizeof(struct ip) + IGMP_MINLEN; MH_ALIGN(m, IGMP_MINLEN + sizeof(struct ip)); m->m_data += sizeof(struct ip); m->m_len = IGMP_MINLEN; igmp = mtod(m, struct igmp *); igmp->igmp_type = type; igmp->igmp_code = 0; igmp->igmp_group = inm->inm_addr; igmp->igmp_cksum = 0; igmp->igmp_cksum = in_cksum(m, IGMP_MINLEN); m->m_data -= sizeof(struct ip); m->m_len += sizeof(struct ip); ip = mtod(m, struct ip *); ip->ip_tos = 0; ip->ip_len = sizeof(struct ip) + IGMP_MINLEN; ip->ip_off = 0; ip->ip_p = IPPROTO_IGMP; ip->ip_src.s_addr = INADDR_ANY; ip->ip_dst = igmp->igmp_group; imo->imo_multicast_ifp = inm->inm_ifp; imo->imo_multicast_ttl = 1; imo->imo_multicast_vif = -1; /* * Request loopback of the report if we are acting as a multicast * router, so that the process-level routing demon can hear it. */ imo->imo_multicast_loop = (ip_mrouter != NULL); ip_output(m, (struct mbuf *)0, (struct route *)0, 0, imo); FREE(imo, M_IPMOPTS); ++igmpstat.igps_snd_reports; } static void igmp_sendleave(inm) struct in_multi *inm; { igmp_sendpkt(inm, IGMP_HOST_LEAVE_MESSAGE); } Index: head/sys/netinet/in.c =================================================================== --- head/sys/netinet/in.c (revision 12703) +++ head/sys/netinet/in.c (revision 12704) @@ -1,694 +1,695 @@ /* * Copyright (c) 1982, 1986, 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)in.c 8.4 (Berkeley) 1/9/95 - * $Id: in.c,v 1.18 1995/11/14 20:33:56 phk Exp $ + * $Id: in.c,v 1.19 1995/11/20 12:28:21 phk Exp $ */ #include #include #include #include #include #include #include #include +#include +#include #include #include #include #include #include #include #include /* * This structure is used to keep track of in_multi chains which belong to * deleted interface addresses. */ static LIST_HEAD(, multi_kludge) in_mk; /* XXX BSS initialization */ struct multi_kludge { LIST_ENTRY(multi_kludge) mk_entry; struct ifnet *mk_ifp; struct in_multihead mk_head; }; static void in_socktrim __P((struct sockaddr_in *)); static int in_ifinit __P((struct ifnet *, struct in_ifaddr *, struct sockaddr_in *, int)); static void in_ifscrub __P((struct ifnet *, struct in_ifaddr *)); -#ifndef SUBNETSARELOCAL -#define SUBNETSARELOCAL 1 -#endif -int subnetsarelocal = SUBNETSARELOCAL; +static int subnetsarelocal = 1; +SYSCTL_INT(_net_inet_ip, OID_AUTO, subnets_are_local, CTLFLAG_RW, + &subnetsarelocal, 0, ""); /* * Return 1 if an internet address is for a ``local'' host * (one to which we have a connection). If subnetsarelocal * is true, this includes other subnets of the local net. * Otherwise, it includes only the directly-connected (sub)nets. */ int in_localaddr(in) struct in_addr in; { register u_long i = ntohl(in.s_addr); register struct in_ifaddr *ia; if (subnetsarelocal) { for (ia = in_ifaddr; ia; ia = ia->ia_next) if ((i & ia->ia_netmask) == ia->ia_net) return (1); } else { for (ia = in_ifaddr; ia; ia = ia->ia_next) if ((i & ia->ia_subnetmask) == ia->ia_subnet) return (1); } return (0); } /* * Determine whether an IP address is in a reserved set of addresses * that may not be forwarded, or whether datagrams to that destination * may be forwarded. */ int in_canforward(in) struct in_addr in; { register u_long i = ntohl(in.s_addr); register u_long net; if (IN_EXPERIMENTAL(i) || IN_MULTICAST(i)) return (0); if (IN_CLASSA(i)) { net = i & IN_CLASSA_NET; if (net == 0 || net == (IN_LOOPBACKNET << IN_CLASSA_NSHIFT)) return (0); } return (1); } /* * Trim a mask in a sockaddr */ static void in_socktrim(ap) struct sockaddr_in *ap; { register char *cplim = (char *) &ap->sin_addr; register char *cp = (char *) (&ap->sin_addr + 1); ap->sin_len = 0; while (--cp >= cplim) if (*cp) { (ap)->sin_len = cp - (char *) (ap) + 1; break; } } -int in_interfaces; /* number of external internet interfaces */ +static int in_interfaces; /* number of external internet interfaces */ /* * Generic internet control operations (ioctl's). * Ifp is 0 if not an interface-specific ioctl. */ /* ARGSUSED */ int in_control(so, cmd, data, ifp) struct socket *so; u_long cmd; caddr_t data; register struct ifnet *ifp; { register struct ifreq *ifr = (struct ifreq *)data; register struct in_ifaddr *ia = 0; register struct ifaddr *ifa; struct in_ifaddr *oia; struct in_aliasreq *ifra = (struct in_aliasreq *)data; struct sockaddr_in oldaddr; int error, hostIsNew, maskIsNew; u_long i; struct multi_kludge *mk; /* * Find address for this interface, if it exists. */ if (ifp) for (ia = in_ifaddr; ia; ia = ia->ia_next) if (ia->ia_ifp == ifp) break; switch (cmd) { case SIOCAIFADDR: case SIOCDIFADDR: if (ifra->ifra_addr.sin_family == AF_INET) { for (oia = ia; ia; ia = ia->ia_next) { if (ia->ia_ifp == ifp && ia->ia_addr.sin_addr.s_addr == ifra->ifra_addr.sin_addr.s_addr) break; } if ((ifp->if_flags & IFF_POINTOPOINT) && (cmd == SIOCAIFADDR) && (ifra->ifra_dstaddr.sin_addr.s_addr == INADDR_ANY)) { return EDESTADDRREQ; } } if (cmd == SIOCDIFADDR && ia == 0) return (EADDRNOTAVAIL); /* FALLTHROUGH */ case SIOCSIFADDR: case SIOCSIFNETMASK: case SIOCSIFDSTADDR: if ((so->so_state & SS_PRIV) == 0) return (EPERM); if (ifp == 0) panic("in_control"); if (ia == (struct in_ifaddr *)0) { oia = (struct in_ifaddr *) malloc(sizeof *oia, M_IFADDR, M_WAITOK); if (oia == (struct in_ifaddr *)NULL) return (ENOBUFS); bzero((caddr_t)oia, sizeof *oia); ia = in_ifaddr; if (ia) { for ( ; ia->ia_next; ia = ia->ia_next) continue; ia->ia_next = oia; } else in_ifaddr = oia; ia = oia; ifa = ifp->if_addrlist; if (ifa) { for ( ; ifa->ifa_next; ifa = ifa->ifa_next) continue; ifa->ifa_next = (struct ifaddr *) ia; } else ifp->if_addrlist = (struct ifaddr *) ia; ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr; ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_sockmask; ia->ia_sockmask.sin_len = 8; if (ifp->if_flags & IFF_BROADCAST) { ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr); ia->ia_broadaddr.sin_family = AF_INET; } ia->ia_ifp = ifp; if (!(ifp->if_flags & IFF_LOOPBACK)) in_interfaces++; } break; case SIOCSIFBRDADDR: if ((so->so_state & SS_PRIV) == 0) return (EPERM); /* FALLTHROUGH */ case SIOCGIFADDR: case SIOCGIFNETMASK: case SIOCGIFDSTADDR: case SIOCGIFBRDADDR: if (ia == (struct in_ifaddr *)0) return (EADDRNOTAVAIL); break; } switch (cmd) { case SIOCGIFADDR: *((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_addr; break; case SIOCGIFBRDADDR: if ((ifp->if_flags & IFF_BROADCAST) == 0) return (EINVAL); *((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_broadaddr; break; case SIOCGIFDSTADDR: if ((ifp->if_flags & IFF_POINTOPOINT) == 0) return (EINVAL); *((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_dstaddr; break; case SIOCGIFNETMASK: *((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_sockmask; break; case SIOCSIFDSTADDR: if ((ifp->if_flags & IFF_POINTOPOINT) == 0) return (EINVAL); oldaddr = ia->ia_dstaddr; ia->ia_dstaddr = *(struct sockaddr_in *)&ifr->ifr_dstaddr; if (ifp->if_ioctl && (error = (*ifp->if_ioctl) (ifp, SIOCSIFDSTADDR, (caddr_t)ia))) { ia->ia_dstaddr = oldaddr; return (error); } if (ia->ia_flags & IFA_ROUTE) { ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&oldaddr; rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr; rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP); } break; case SIOCSIFBRDADDR: if ((ifp->if_flags & IFF_BROADCAST) == 0) return (EINVAL); ia->ia_broadaddr = *(struct sockaddr_in *)&ifr->ifr_broadaddr; break; case SIOCSIFADDR: return (in_ifinit(ifp, ia, (struct sockaddr_in *) &ifr->ifr_addr, 1)); case SIOCSIFNETMASK: i = ifra->ifra_addr.sin_addr.s_addr; ia->ia_subnetmask = ntohl(ia->ia_sockmask.sin_addr.s_addr = i); break; case SIOCAIFADDR: maskIsNew = 0; hostIsNew = 1; error = 0; if (ia->ia_addr.sin_family == AF_INET) { if (ifra->ifra_addr.sin_len == 0) { ifra->ifra_addr = ia->ia_addr; hostIsNew = 0; } else if (ifra->ifra_addr.sin_addr.s_addr == ia->ia_addr.sin_addr.s_addr) hostIsNew = 0; } if (ifra->ifra_mask.sin_len) { in_ifscrub(ifp, ia); ia->ia_sockmask = ifra->ifra_mask; ia->ia_subnetmask = ntohl(ia->ia_sockmask.sin_addr.s_addr); maskIsNew = 1; } if ((ifp->if_flags & IFF_POINTOPOINT) && (ifra->ifra_dstaddr.sin_family == AF_INET)) { in_ifscrub(ifp, ia); ia->ia_dstaddr = ifra->ifra_dstaddr; maskIsNew = 1; /* We lie; but the effect's the same */ } if (ifra->ifra_addr.sin_family == AF_INET && (hostIsNew || maskIsNew)) error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0); if ((ifp->if_flags & IFF_BROADCAST) && (ifra->ifra_broadaddr.sin_family == AF_INET)) ia->ia_broadaddr = ifra->ifra_broadaddr; return (error); case SIOCDIFADDR: mk = malloc(sizeof *mk, M_IPMADDR, M_WAITOK); if (!mk) return ENOBUFS; in_ifscrub(ifp, ia); if ((ifa = ifp->if_addrlist) == (struct ifaddr *)ia) ifp->if_addrlist = ifa->ifa_next; else { while (ifa->ifa_next && (ifa->ifa_next != (struct ifaddr *)ia)) ifa = ifa->ifa_next; if (ifa->ifa_next) ifa->ifa_next = ((struct ifaddr *)ia)->ifa_next; else printf("Couldn't unlink inifaddr from ifp\n"); } oia = ia; if (oia == (ia = in_ifaddr)) in_ifaddr = ia->ia_next; else { while (ia->ia_next && (ia->ia_next != oia)) ia = ia->ia_next; if (ia->ia_next) ia->ia_next = oia->ia_next; else printf("Didn't unlink inifadr from list\n"); } if (!oia->ia_multiaddrs.lh_first) { IFAFREE(&oia->ia_ifa); FREE(mk, M_IPMADDR); break; } /* * Multicast address kludge: * If there were any multicast addresses attached to this * interface address, either move them to another address * on this interface, or save them until such time as this * interface is reconfigured for IP. */ IFP_TO_IA(oia->ia_ifp, ia); if (ia) { /* there is another address */ struct in_multi *inm; for(inm = oia->ia_multiaddrs.lh_first; inm; inm = inm->inm_entry.le_next) { IFAFREE(&inm->inm_ia->ia_ifa); ia->ia_ifa.ifa_refcnt++; inm->inm_ia = ia; LIST_INSERT_HEAD(&ia->ia_multiaddrs, inm, inm_entry); } FREE(mk, M_IPMADDR); } else { /* last address on this if deleted, save */ struct in_multi *inm; LIST_INIT(&mk->mk_head); mk->mk_ifp = ifp; for(inm = oia->ia_multiaddrs.lh_first; inm; inm = inm->inm_entry.le_next) { LIST_INSERT_HEAD(&mk->mk_head, inm, inm_entry); } if (mk->mk_head.lh_first) { LIST_INSERT_HEAD(&in_mk, mk, mk_entry); } else { FREE(mk, M_IPMADDR); } } IFAFREE((&oia->ia_ifa)); break; default: if (ifp == 0 || ifp->if_ioctl == 0) return (EOPNOTSUPP); return ((*ifp->if_ioctl)(ifp, cmd, data)); } return (0); } /* * Delete any existing route for an interface. */ static void in_ifscrub(ifp, ia) register struct ifnet *ifp; register struct in_ifaddr *ia; { if ((ia->ia_flags & IFA_ROUTE) == 0) return; if (ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT)) rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); else rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0); ia->ia_flags &= ~IFA_ROUTE; } /* * Initialize an interface's internet address * and routing table entry. */ static int in_ifinit(ifp, ia, sin, scrub) register struct ifnet *ifp; register struct in_ifaddr *ia; struct sockaddr_in *sin; int scrub; { register u_long i = ntohl(sin->sin_addr.s_addr); struct sockaddr_in oldaddr; int s = splimp(), flags = RTF_UP, error; struct multi_kludge *mk; oldaddr = ia->ia_addr; ia->ia_addr = *sin; /* * Give the interface a chance to initialize * if this is its first address, * and to validate the address if necessary. */ if (ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) { splx(s); ia->ia_addr = oldaddr; return (error); } splx(s); if (scrub) { ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr; in_ifscrub(ifp, ia); ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; } if (IN_CLASSA(i)) ia->ia_netmask = IN_CLASSA_NET; else if (IN_CLASSB(i)) ia->ia_netmask = IN_CLASSB_NET; else ia->ia_netmask = IN_CLASSC_NET; /* * The subnet mask usually includes at least the standard network part, * but may may be smaller in the case of supernetting. * If it is set, we believe it. */ if (ia->ia_subnetmask == 0) { ia->ia_subnetmask = ia->ia_netmask; ia->ia_sockmask.sin_addr.s_addr = htonl(ia->ia_subnetmask); } else ia->ia_netmask &= ia->ia_subnetmask; ia->ia_net = i & ia->ia_netmask; ia->ia_subnet = i & ia->ia_subnetmask; in_socktrim(&ia->ia_sockmask); /* * Add route for the network. */ ia->ia_ifa.ifa_metric = ifp->if_metric; if (ifp->if_flags & IFF_BROADCAST) { ia->ia_broadaddr.sin_addr.s_addr = htonl(ia->ia_subnet | ~ia->ia_subnetmask); ia->ia_netbroadcast.s_addr = htonl(ia->ia_net | ~ ia->ia_netmask); } else if (ifp->if_flags & IFF_LOOPBACK) { ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr; flags |= RTF_HOST; } else if (ifp->if_flags & IFF_POINTOPOINT) { if (ia->ia_dstaddr.sin_family != AF_INET) return (0); flags |= RTF_HOST; } if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0) ia->ia_flags |= IFA_ROUTE; LIST_INIT(&ia->ia_multiaddrs); /* * If the interface supports multicast, join the "all hosts" * multicast group on that interface. */ if (ifp->if_flags & IFF_MULTICAST) { struct in_addr addr; /* * Continuation of multicast address hack: * If there was a multicast group list previously saved * for this interface, then we re-attach it to the first * address configured on the i/f. */ for(mk = in_mk.lh_first; mk; mk = mk->mk_entry.le_next) { if(mk->mk_ifp == ifp) { struct in_multi *inm; for(inm = mk->mk_head.lh_first; inm; inm = inm->inm_entry.le_next) { IFAFREE(&inm->inm_ia->ia_ifa); ia->ia_ifa.ifa_refcnt++; inm->inm_ia = ia; LIST_INSERT_HEAD(&ia->ia_multiaddrs, inm, inm_entry); } LIST_REMOVE(mk, mk_entry); free(mk, M_IPMADDR); break; } } addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); in_addmulti(&addr, ifp); } return (error); } /* * Return 1 if the address might be a local broadcast address. */ int in_broadcast(in, ifp) struct in_addr in; struct ifnet *ifp; { register struct ifaddr *ifa; u_long t; if (in.s_addr == INADDR_BROADCAST || in.s_addr == INADDR_ANY) return 1; if ((ifp->if_flags & IFF_BROADCAST) == 0) return 0; t = ntohl(in.s_addr); /* * Look through the list of addresses for a match * with a broadcast address. */ #define ia ((struct in_ifaddr *)ifa) for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) if (ifa->ifa_addr->sa_family == AF_INET && (in.s_addr == ia->ia_broadaddr.sin_addr.s_addr || in.s_addr == ia->ia_netbroadcast.s_addr || /* * Check for old-style (host 0) broadcast. */ t == ia->ia_subnet || t == ia->ia_net)) return 1; return (0); #undef ia } /* * Add an address to the list of IP multicast addresses for a given interface. */ struct in_multi * in_addmulti(ap, ifp) register struct in_addr *ap; register struct ifnet *ifp; { register struct in_multi *inm; struct ifreq ifr; struct in_ifaddr *ia; int s = splnet(); /* * See if address already in list. */ IN_LOOKUP_MULTI(*ap, ifp, inm); if (inm != NULL) { /* * Found it; just increment the reference count. */ ++inm->inm_refcount; } else { /* * New address; allocate a new multicast record * and link it into the interface's multicast list. */ inm = (struct in_multi *)malloc(sizeof(*inm), M_IPMADDR, M_NOWAIT); if (inm == NULL) { splx(s); return (NULL); } inm->inm_addr = *ap; inm->inm_ifp = ifp; inm->inm_refcount = 1; IFP_TO_IA(ifp, ia); if (ia == NULL) { free(inm, M_IPMADDR); splx(s); return (NULL); } inm->inm_ia = ia; ia->ia_ifa.ifa_refcnt++; /* gain a reference */ LIST_INSERT_HEAD(&ia->ia_multiaddrs, inm, inm_entry); /* * Ask the network driver to update its multicast reception * filter appropriately for the new address. */ ((struct sockaddr_in *)&ifr.ifr_addr)->sin_family = AF_INET; ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr = *ap; if ((ifp->if_ioctl == NULL) || (*ifp->if_ioctl)(ifp, SIOCADDMULTI,(caddr_t)&ifr) != 0) { LIST_REMOVE(inm, inm_entry); IFAFREE(&ia->ia_ifa); /* release reference */ free(inm, M_IPMADDR); splx(s); return (NULL); } /* * Let IGMP know that we have joined a new IP multicast group. */ igmp_joingroup(inm); } splx(s); return (inm); } /* * Delete a multicast address record. */ void in_delmulti(inm) register struct in_multi *inm; { struct ifreq ifr; int s = splnet(); if (--inm->inm_refcount == 0) { /* * No remaining claims to this record; let IGMP know that * we are leaving the multicast group. */ igmp_leavegroup(inm); /* * Unlink from list. */ LIST_REMOVE(inm, inm_entry); IFAFREE(&inm->inm_ia->ia_ifa); /* release reference */ /* * Notify the network driver to update its multicast reception * filter. */ ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_family = AF_INET; ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_addr = inm->inm_addr; (*inm->inm_ifp->if_ioctl)(inm->inm_ifp, SIOCDELMULTI, (caddr_t)&ifr); free(inm, M_IPMADDR); } splx(s); } Index: head/sys/netinet/raw_ip.c =================================================================== --- head/sys/netinet/raw_ip.c (revision 12703) +++ head/sys/netinet/raw_ip.c (revision 12704) @@ -1,457 +1,457 @@ /* * Copyright (c) 1982, 1986, 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)raw_ip.c 8.7 (Berkeley) 5/15/95 - * $Id: raw_ip.c,v 1.23 1995/10/21 02:12:20 davidg Exp $ + * $Id: raw_ip.c,v 1.24 1995/11/14 20:34:23 phk Exp $ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -struct inpcbhead ripcb; -struct inpcbinfo ripcbinfo; +static struct inpcbhead ripcb; +static struct inpcbinfo ripcbinfo; /* * Nominal space allocated to a raw ip socket. */ #define RIPSNDQ 8192 #define RIPRCVQ 8192 /* * Raw interface to IP protocol. */ /* * Initialize raw connection block q. */ void rip_init() { LIST_INIT(&ripcb); ripcbinfo.listhead = &ripcb; /* * XXX We don't use the hash list for raw IP, but it's easier * to allocate a one entry hash list than it is to check all * over the place for hashbase == NULL. */ ripcbinfo.hashbase = phashinit(1, M_PCB, &ripcbinfo.hashsize); } -struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET }; +static struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET }; /* * Setup generic address and protocol structures * for raw_input routine, then pass them along with * mbuf chain. */ void rip_input(m) struct mbuf *m; { register struct ip *ip = mtod(m, struct ip *); register struct inpcb *inp; struct socket *last = 0; ripsrc.sin_addr = ip->ip_src; for (inp = ripcb.lh_first; inp != NULL; inp = inp->inp_list.le_next) { if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != ip->ip_p) continue; if (inp->inp_laddr.s_addr && inp->inp_laddr.s_addr != ip->ip_dst.s_addr) continue; if (inp->inp_faddr.s_addr && inp->inp_faddr.s_addr != ip->ip_src.s_addr) continue; if (last) { struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); if (n) { if (sbappendaddr(&last->so_rcv, (struct sockaddr *)&ripsrc, n, (struct mbuf *)0) == 0) /* should notify about lost packet */ m_freem(n); else sorwakeup(last); } } last = inp->inp_socket; } if (last) { if (sbappendaddr(&last->so_rcv, (struct sockaddr *)&ripsrc, m, (struct mbuf *)0) == 0) m_freem(m); else sorwakeup(last); } else { m_freem(m); ipstat.ips_noproto++; ipstat.ips_delivered--; } } /* * Generate IP header and pass packet to ip_output. * Tack on options user may have setup with control call. */ int rip_output(m, so, dst) register struct mbuf *m; struct socket *so; u_long dst; { register struct ip *ip; register struct inpcb *inp = sotoinpcb(so); struct mbuf *opts; int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST; /* * If the user handed us a complete IP packet, use it. * Otherwise, allocate an mbuf for a header and fill it in. */ if ((inp->inp_flags & INP_HDRINCL) == 0) { M_PREPEND(m, sizeof(struct ip), M_WAIT); ip = mtod(m, struct ip *); ip->ip_tos = 0; ip->ip_off = 0; ip->ip_p = inp->inp_ip.ip_p; ip->ip_len = m->m_pkthdr.len; ip->ip_src = inp->inp_laddr; ip->ip_dst.s_addr = dst; ip->ip_ttl = MAXTTL; opts = inp->inp_options; } else { ip = mtod(m, struct ip *); if (ip->ip_id == 0) ip->ip_id = htons(ip_id++); opts = NULL; /* XXX prevent ip_output from overwriting header fields */ flags |= IP_RAWOUTPUT; ipstat.ips_rawout++; } return (ip_output(m, opts, &inp->inp_route, flags, inp->inp_moptions)); } /* * Raw IP socket option processing. */ int rip_ctloutput(op, so, level, optname, m) int op; struct socket *so; int level, optname; struct mbuf **m; { register struct inpcb *inp = sotoinpcb(so); register int error; if (level != IPPROTO_IP) { if (op == PRCO_SETOPT && *m) (void)m_free(*m); return (EINVAL); } switch (optname) { case IP_HDRINCL: error = 0; if (op == PRCO_SETOPT) { if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int)) error = EINVAL; else if (*mtod(*m, int *)) inp->inp_flags |= INP_HDRINCL; else inp->inp_flags &= ~INP_HDRINCL; if (*m) (void)m_free(*m); } else { *m = m_get(M_WAIT, MT_SOOPTS); (*m)->m_len = sizeof (int); *mtod(*m, int *) = inp->inp_flags & INP_HDRINCL; } return (error); case IP_FW_ADD: case IP_FW_DEL: case IP_FW_FLUSH: case IP_FW_POLICY: if (ip_fw_ctl_ptr==NULL) { if (*m) (void)m_free(*m); return(EINVAL); } if (op == PRCO_SETOPT) { error=(*ip_fw_ctl_ptr)(optname, *m); if (*m) (void)m_free(*m); } else error=EINVAL; return(error); case IP_ACCT_DEL: case IP_ACCT_ADD: case IP_ACCT_CLR: case IP_ACCT_FLUSH: case IP_ACCT_ZERO: if (ip_acct_ctl_ptr==NULL) { if (*m) (void)m_free(*m); return(EINVAL); } if (op == PRCO_SETOPT) { error=(*ip_acct_ctl_ptr)(optname, *m); if (*m) (void)m_free(*m); } else error=EINVAL; return(error); case IP_RSVP_ON: return ip_rsvp_init(so); break; case IP_RSVP_OFF: return ip_rsvp_done(); break; case IP_RSVP_VIF_ON: return ip_rsvp_vif_init(so, *m); case IP_RSVP_VIF_OFF: return ip_rsvp_vif_done(so, *m); case MRT_INIT: case MRT_DONE: case MRT_ADD_VIF: case MRT_DEL_VIF: case MRT_ADD_MFC: case MRT_DEL_MFC: case MRT_VERSION: case MRT_ASSERT: if (op == PRCO_SETOPT) { error = ip_mrouter_set(optname, so, *m); if (*m) (void)m_free(*m); } else if (op == PRCO_GETOPT) { error = ip_mrouter_get(optname, so, m); } else error = EINVAL; return (error); } return (ip_ctloutput(op, so, level, optname, m)); } static u_long rip_sendspace = RIPSNDQ; /* XXX sysctl ? */ static u_long rip_recvspace = RIPRCVQ; /* XXX sysctl ? */ /*ARGSUSED*/ int rip_usrreq(so, req, m, nam, control) register struct socket *so; int req; struct mbuf *m, *nam, *control; { register int error = 0; register struct inpcb *inp = sotoinpcb(so); if (req == PRU_CONTROL) return (in_control(so, (u_long)m, (caddr_t)nam, (struct ifnet *)control)); switch (req) { case PRU_ATTACH: if (inp) panic("rip_attach"); if ((so->so_state & SS_PRIV) == 0) { error = EACCES; break; } if ((error = soreserve(so, rip_sendspace, rip_recvspace)) || (error = in_pcballoc(so, &ripcbinfo))) break; inp = (struct inpcb *)so->so_pcb; inp->inp_ip.ip_p = (int)nam; break; case PRU_DISCONNECT: if ((so->so_state & SS_ISCONNECTED) == 0) { error = ENOTCONN; break; } /* FALLTHROUGH */ case PRU_ABORT: soisdisconnected(so); /* FALLTHROUGH */ case PRU_DETACH: if (inp == 0) panic("rip_detach"); if (so == ip_mrouter) ip_mrouter_done(); ip_rsvp_force_done(so); if (so == ip_rsvpd) ip_rsvp_done(); in_pcbdetach(inp); break; case PRU_BIND: { struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); if (nam->m_len != sizeof(*addr)) { error = EINVAL; break; } if ((ifnet == 0) || ((addr->sin_family != AF_INET) && (addr->sin_family != AF_IMPLINK)) || (addr->sin_addr.s_addr && ifa_ifwithaddr((struct sockaddr *)addr) == 0)) { error = EADDRNOTAVAIL; break; } inp->inp_laddr = addr->sin_addr; break; } case PRU_CONNECT: { struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); if (nam->m_len != sizeof(*addr)) { error = EINVAL; break; } if (ifnet == 0) { error = EADDRNOTAVAIL; break; } if ((addr->sin_family != AF_INET) && (addr->sin_family != AF_IMPLINK)) { error = EAFNOSUPPORT; break; } inp->inp_faddr = addr->sin_addr; soisconnected(so); break; } case PRU_CONNECT2: error = EOPNOTSUPP; break; /* * Mark the connection as being incapable of further input. */ case PRU_SHUTDOWN: socantsendmore(so); break; /* * Ship a packet out. The appropriate raw output * routine handles any massaging necessary. */ case PRU_SEND: { register u_long dst; if (so->so_state & SS_ISCONNECTED) { if (nam) { error = EISCONN; break; } dst = inp->inp_faddr.s_addr; } else { if (nam == NULL) { error = ENOTCONN; break; } dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr; } error = rip_output(m, so, dst); m = NULL; break; } case PRU_SENSE: /* * stat: don't bother with a blocksize. */ return (0); /* * Not supported. */ case PRU_RCVOOB: case PRU_RCVD: case PRU_LISTEN: case PRU_ACCEPT: case PRU_SENDOOB: error = EOPNOTSUPP; break; case PRU_SOCKADDR: in_setsockaddr(inp, nam); break; case PRU_PEERADDR: in_setpeeraddr(inp, nam); break; default: panic("rip_usrreq"); } if (m != NULL) m_freem(m); return (error); }