diff --git a/sys/netipx/ipx_input.c b/sys/netipx/ipx_input.c index 812226b259e5..c20d543635c6 100644 --- a/sys/netipx/ipx_input.c +++ b/sys/netipx/ipx_input.c @@ -1,503 +1,503 @@ /* * Copyright (c) 2004 Robert N. M. Watson * Copyright (c) 1995, Mike Mitchell * Copyright (c) 1984, 1985, 1986, 1987, 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. * * @(#)ipx_input.c */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include int ipxcksum = 0; SYSCTL_INT(_net_ipx_ipx, OID_AUTO, checksum, CTLFLAG_RW, &ipxcksum, 0, ""); static int ipxprintfs = 0; /* printing forwarding information */ SYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxprintfs, CTLFLAG_RW, &ipxprintfs, 0, ""); static int ipxforwarding = 0; SYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxforwarding, CTLFLAG_RW, &ipxforwarding, 0, ""); static int ipxnetbios = 0; SYSCTL_INT(_net_ipx, OID_AUTO, ipxnetbios, CTLFLAG_RW, &ipxnetbios, 0, ""); const union ipx_net ipx_zeronet; const union ipx_host ipx_zerohost; const union ipx_net ipx_broadnet = { .s_net[0] = 0xffff, .s_net[1] = 0xffff }; const union ipx_host ipx_broadhost = { .s_host[0] = 0xffff, .s_host[1] = 0xffff, .s_host[2] = 0xffff }; struct ipxstat ipxstat; struct sockaddr_ipx ipx_netmask, ipx_hostmask; /* * IPX protocol control block (pcb) lists. */ struct ipxpcbhead ipxpcb_list; struct ipxpcbhead ipxrawpcb_list; static int ipxqmaxlen = IFQ_MAXLEN; static struct ifqueue ipxintrq; long ipx_pexseq; static int ipx_do_route(struct ipx_addr *src, struct route *ro); static void ipx_undo_route(struct route *ro); static void ipx_forward(struct mbuf *m); static void ipxintr(struct mbuf *m); /* * IPX initialization. */ void ipx_init() { read_random(&ipx_pexseq, sizeof ipx_pexseq); LIST_INIT(&ipxpcb_list); LIST_INIT(&ipxrawpcb_list); ipx_netmask.sipx_len = 6; ipx_netmask.sipx_addr.x_net = ipx_broadnet; ipx_hostmask.sipx_len = 12; ipx_hostmask.sipx_addr.x_net = ipx_broadnet; ipx_hostmask.sipx_addr.x_host = ipx_broadhost; ipxintrq.ifq_maxlen = ipxqmaxlen; mtx_init(&ipxintrq.ifq_mtx, "ipx_inq", NULL, MTX_DEF); netisr_register(NETISR_IPX, ipxintr, &ipxintrq, 0); } /* * IPX input routine. Pass to next level. */ static void ipxintr(struct mbuf *m) { register struct ipx *ipx; register struct ipxpcb *ipxp; struct ipx_ifaddr *ia; int len; GIANT_REQUIRED; /* * If no IPX addresses have been set yet but the interfaces * are receiving, can't do anything with incoming packets yet. */ if (ipx_ifaddr == NULL) goto bad; ipxstat.ipxs_total++; if ((m->m_flags & M_EXT || m->m_len < sizeof(struct ipx)) && (m = m_pullup(m, sizeof(struct ipx))) == 0) { ipxstat.ipxs_toosmall++; return; } /* * Give any raw listeners a crack at the packet */ LIST_FOREACH(ipxp, &ipxrawpcb_list, ipxp_list) { struct mbuf *m1 = m_copy(m, 0, (int)M_COPYALL); if (m1 != NULL) ipx_input(m1, ipxp); } ipx = mtod(m, struct ipx *); len = ntohs(ipx->ipx_len); /* * Check that the amount of data in the buffers * is as at least much as the IPX header would have us expect. * Trim mbufs if longer than we expect. * Drop packet if shorter than we expect. */ if (m->m_pkthdr.len < len) { ipxstat.ipxs_tooshort++; goto bad; } if (m->m_pkthdr.len > len) { if (m->m_len == m->m_pkthdr.len) { m->m_len = len; m->m_pkthdr.len = len; } else m_adj(m, len - m->m_pkthdr.len); } if (ipxcksum && ipx->ipx_sum != 0xffff) { if (ipx->ipx_sum != ipx_cksum(m, len)) { ipxstat.ipxs_badsum++; goto bad; } } /* * Propagated (Netbios) packets (type 20) has to be handled * different. :-( */ if (ipx->ipx_pt == IPXPROTO_NETBIOS) { if (ipxnetbios) { ipx_output_type20(m); return; } else goto bad; } /* * Is this a directed broadcast? */ if (ipx_hosteqnh(ipx_broadhost,ipx->ipx_dna.x_host)) { if ((!ipx_neteq(ipx->ipx_dna, ipx->ipx_sna)) && (!ipx_neteqnn(ipx->ipx_dna.x_net, ipx_broadnet)) && (!ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet)) && (!ipx_neteqnn(ipx->ipx_dna.x_net, ipx_zeronet)) ) { /* * If it is a broadcast to the net where it was * received from, treat it as ours. */ for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) if((ia->ia_ifa.ifa_ifp == m->m_pkthdr.rcvif) && ipx_neteq(ia->ia_addr.sipx_addr, ipx->ipx_dna)) goto ours; /* * Look to see if I need to eat this packet. * Algorithm is to forward all young packets * and prematurely age any packets which will * by physically broadcasted. * Any very old packets eaten without forwarding * would die anyway. * * Suggestion of Bill Nesheim, Cornell U. */ if (ipx->ipx_tc < IPX_MAXHOPS) { ipx_forward(m); return; } } /* * Is this our packet? If not, forward. */ } else { for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) if (ipx_hosteq(ipx->ipx_dna, ia->ia_addr.sipx_addr) && (ipx_neteq(ipx->ipx_dna, ia->ia_addr.sipx_addr) || ipx_neteqnn(ipx->ipx_dna.x_net, ipx_zeronet))) break; if (ia == NULL) { ipx_forward(m); return; } } ours: /* * Locate pcb for datagram. */ ipxp = ipx_pcblookup(&ipx->ipx_sna, ipx->ipx_dna.x_port, IPX_WILDCARD); /* * Switch out to protocol's input routine. */ if (ipxp != NULL) { ipxstat.ipxs_delivered++; if ((ipxp->ipxp_flags & IPXP_ALL_PACKETS) == 0) switch (ipx->ipx_pt) { case IPXPROTO_SPX: spx_input(m, ipxp); return; } ipx_input(m, ipxp); } else goto bad; return; bad: m_freem(m); } void ipx_ctlinput(cmd, arg_as_sa, dummy) int cmd; struct sockaddr *arg_as_sa; /* XXX should be swapped with dummy */ void *dummy; { caddr_t arg = (/* XXX */ caddr_t)arg_as_sa; struct ipx_addr *ipx; if (cmd < 0 || cmd >= PRC_NCMDS) return; switch (cmd) { struct sockaddr_ipx *sipx; case PRC_IFDOWN: case PRC_HOSTDEAD: case PRC_HOSTUNREACH: sipx = (struct sockaddr_ipx *)arg; if (sipx->sipx_family != AF_IPX) return; ipx = &sipx->sipx_addr; break; default: if (ipxprintfs) printf("ipx_ctlinput: cmd %d.\n", cmd); break; } } /* * Forward a packet. If some error occurs drop the packet. IPX don't * have a way to return errors to the sender. */ static struct route ipx_droute; static struct route ipx_sroute; static void ipx_forward(m) struct mbuf *m; { register struct ipx *ipx = mtod(m, struct ipx *); register int error; struct mbuf *mcopy = NULL; int agedelta = 1; int flags = IPX_FORWARDING; int ok_there = 0; int ok_back = 0; if (ipxforwarding == 0) { /* can't tell difference between net and host */ ipxstat.ipxs_cantforward++; m_freem(m); goto cleanup; } ipx->ipx_tc++; if (ipx->ipx_tc > IPX_MAXHOPS) { ipxstat.ipxs_cantforward++; m_freem(m); goto cleanup; } if ((ok_there = ipx_do_route(&ipx->ipx_dna,&ipx_droute)) == 0) { ipxstat.ipxs_noroute++; m_freem(m); goto cleanup; } /* * Here we think about forwarding broadcast packets, * so we try to insure that it doesn't go back out * on the interface it came in on. Also, if we * are going to physically broadcast this, let us * age the packet so we can eat it safely the second time around. */ if (ipx->ipx_dna.x_host.c_host[0] & 0x1) { struct ipx_ifaddr *ia = ipx_iaonnetof(&ipx->ipx_dna); struct ifnet *ifp; if (ia != NULL) { /* I'm gonna hafta eat this packet */ agedelta += IPX_MAXHOPS - ipx->ipx_tc; ipx->ipx_tc = IPX_MAXHOPS; } if ((ok_back = ipx_do_route(&ipx->ipx_sna,&ipx_sroute)) == 0) { /* error = ENETUNREACH; He'll never get it! */ ipxstat.ipxs_noroute++; m_freem(m); goto cleanup; } if (ipx_droute.ro_rt && (ifp = ipx_droute.ro_rt->rt_ifp) && ipx_sroute.ro_rt && (ifp != ipx_sroute.ro_rt->rt_ifp)) { flags |= IPX_ALLOWBROADCAST; } else { ipxstat.ipxs_noroute++; m_freem(m); goto cleanup; } } /* * We don't need to recompute checksum because ipx_tc field * is ignored by checksum calculation routine, however * it may be desirable to reset checksum if ipxcksum == 0 */ #if 0 if (!ipxcksum) ipx->ipx_sum = 0xffff; #endif error = ipx_outputfl(m, &ipx_droute, flags); if (error == 0) { ipxstat.ipxs_forward++; if (ipxprintfs) { printf("forward: "); ipx_printhost(&ipx->ipx_sna); printf(" to "); ipx_printhost(&ipx->ipx_dna); printf(" hops %d\n", ipx->ipx_tc); } } else if (mcopy != NULL) { ipx = mtod(mcopy, struct ipx *); switch (error) { case ENETUNREACH: case EHOSTDOWN: case EHOSTUNREACH: case ENETDOWN: case EPERM: ipxstat.ipxs_noroute++; break; case EMSGSIZE: ipxstat.ipxs_mtutoosmall++; break; case ENOBUFS: ipxstat.ipxs_odropped++; break; } mcopy = NULL; m_freem(m); } cleanup: if (ok_there) ipx_undo_route(&ipx_droute); if (ok_back) ipx_undo_route(&ipx_sroute); if (mcopy != NULL) m_freem(mcopy); } static int ipx_do_route(src, ro) struct ipx_addr *src; struct route *ro; { struct sockaddr_ipx *dst; bzero((caddr_t)ro, sizeof(*ro)); dst = (struct sockaddr_ipx *)&ro->ro_dst; dst->sipx_len = sizeof(*dst); dst->sipx_family = AF_IPX; dst->sipx_addr = *src; dst->sipx_addr.x_port = 0; - rtalloc(ro); + rtalloc_ign(ro, 0); if (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL) { return (0); } ro->ro_rt->rt_use++; return (1); } static void ipx_undo_route(ro) register struct route *ro; { if (ro->ro_rt != NULL) { RTFREE(ro->ro_rt); } } void ipx_watch_output(m, ifp) struct mbuf *m; struct ifnet *ifp; { register struct ipxpcb *ipxp; register struct ifaddr *ifa; register struct ipx_ifaddr *ia; /* * Give any raw listeners a crack at the packet */ LIST_FOREACH(ipxp, &ipxrawpcb_list, ipxp_list) { struct mbuf *m0 = m_copy(m, 0, (int)M_COPYALL); if (m0 != NULL) { register struct ipx *ipx; M_PREPEND(m0, sizeof(*ipx), M_DONTWAIT); if (m0 == NULL) continue; ipx = mtod(m0, struct ipx *); ipx->ipx_sna.x_net = ipx_zeronet; for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) if (ifp == ia->ia_ifp) break; if (ia == NULL) ipx->ipx_sna.x_host = ipx_zerohost; else ipx->ipx_sna.x_host = ia->ia_addr.sipx_addr.x_host; if (ifp != NULL && (ifp->if_flags & IFF_POINTOPOINT)) TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family == AF_IPX) { ipx->ipx_sna = IA_SIPX(ifa)->sipx_addr; break; } } ipx->ipx_len = ntohl(m0->m_pkthdr.len); ipx_input(m0, ipxp); } } } diff --git a/sys/netipx/ipx_ip.c b/sys/netipx/ipx_ip.c index d069fb9bd34a..c706674da27d 100644 --- a/sys/netipx/ipx_ip.c +++ b/sys/netipx/ipx_ip.c @@ -1,452 +1,452 @@ /* * Copyright (c) 1995, Mike Mitchell * Copyright (c) 1984, 1985, 1986, 1987, 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. * * @(#)ipx_ip.c */ #include __FBSDID("$FreeBSD$"); /* * Software interface driver for encapsulating IPX in IP. */ #include "opt_inet.h" #include "opt_ipx.h" #ifdef IPXIP #ifndef INET #error The option IPXIP requires option INET. #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static struct ifnet ipxipif; static int ipxipif_units; /* list of all hosts and gateways or broadcast addrs */ static struct ifnet_en *ipxip_list; static struct ifnet_en *ipxipattach(void); static int ipxip_free(struct ifnet *ifp); static int ipxipioctl(struct ifnet *ifp, u_long cmd, caddr_t data); static int ipxipoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct rtentry *rt); static void ipxip_rtchange(struct in_addr *dst); static void ipxipstart(struct ifnet *ifp); static struct ifnet_en * ipxipattach() { register struct ifnet_en *m; register struct ifnet *ifp; if (ipxipif.if_mtu == 0) { ifp = &ipxipif; if_initname(ifp, "ipxip", ipxipif_units); ifp->if_mtu = LOMTU; ifp->if_ioctl = ipxipioctl; ifp->if_output = ipxipoutput; ifp->if_start = ipxipstart; ifp->if_flags = IFF_POINTOPOINT; } MALLOC((m), struct ifnet_en *, sizeof(*m), M_PCB, M_NOWAIT | M_ZERO); if (m == NULL) return (NULL); m->ifen_next = ipxip_list; ipxip_list = m; ifp = &m->ifen_ifnet; if_initname(ifp, "ipxip", ipxipif_units++); ifp->if_mtu = LOMTU; ifp->if_ioctl = ipxipioctl; ifp->if_output = ipxipoutput; ifp->if_start = ipxipstart; ifp->if_flags = IFF_POINTOPOINT; if_attach(ifp); return (m); } /* * Process an ioctl request. */ static int ipxipioctl(ifp, cmd, data) register struct ifnet *ifp; u_long cmd; caddr_t data; { int error = 0; struct ifreq *ifr; switch (cmd) { case SIOCSIFADDR: ifp->if_flags |= IFF_UP; /* FALLTHROUGH */ case SIOCSIFDSTADDR: /* * Everything else is done at a higher level. */ break; case SIOCSIFFLAGS: ifr = (struct ifreq *)data; if ((ifr->ifr_flags & IFF_UP) == 0) error = ipxip_free(ifp); default: error = EINVAL; } return (error); } static struct mbuf *ipxip_badlen; static struct mbuf *ipxip_lastin; static int ipxip_hold_input; void ipxip_input(m, hlen) register struct mbuf *m; int hlen; { register struct ip *ip; register struct ipx *ipx; int len, s; if (ipxip_hold_input) { if (ipxip_lastin != NULL) { m_freem(ipxip_lastin); } ipxip_lastin = m_copym(m, 0, (int)M_COPYALL, M_DONTWAIT); } /* * Get IP and IPX header together in first mbuf. */ ipxipif.if_ipackets++; s = sizeof(struct ip) + sizeof(struct ipx); if (((m->m_flags & M_EXT) || m->m_len < s) && (m = m_pullup(m, s)) == NULL) { ipxipif.if_ierrors++; return; } ip = mtod(m, struct ip *); if (ip->ip_hl > (sizeof(struct ip) >> 2)) { ip_stripoptions(m, (struct mbuf *)NULL); if (m->m_len < s) { if ((m = m_pullup(m, s)) == NULL) { ipxipif.if_ierrors++; return; } ip = mtod(m, struct ip *); } } /* * Make mbuf data length reflect IPX length. * If not enough data to reflect IPX length, drop. */ m->m_data += sizeof(struct ip); m->m_len -= sizeof(struct ip); m->m_pkthdr.len -= sizeof(struct ip); ipx = mtod(m, struct ipx *); len = ntohs(ipx->ipx_len); if (len & 1) len++; /* Preserve Garbage Byte */ if (ip->ip_len != len) { if (len > ip->ip_len) { ipxipif.if_ierrors++; if (ipxip_badlen) m_freem(ipxip_badlen); ipxip_badlen = m; return; } /* Any extra will be trimmed off by the IPX routines */ } /* * Deliver to IPX */ netisr_dispatch(NETISR_IPX, m); } static int ipxipoutput(ifp, m, dst, rt) struct ifnet *ifp; struct mbuf *m; struct sockaddr *dst; struct rtentry *rt; { register struct ifnet_en *ifn = (struct ifnet_en *)ifp; register struct ip *ip; register struct route *ro = &(ifn->ifen_route); register int len = 0; register struct ipx *ipx = mtod(m, struct ipx *); int error; ifn->ifen_ifnet.if_opackets++; ipxipif.if_opackets++; /* * Calculate data length and make space * for IP header. */ len = ntohs(ipx->ipx_len); if (len & 1) len++; /* Preserve Garbage Byte */ /* following clause not necessary on vax */ if (3 & (intptr_t)m->m_data) { /* force longword alignment of ip hdr */ struct mbuf *m0 = m_gethdr(MT_HEADER, M_DONTWAIT); if (m0 == NULL) { m_freem(m); return (ENOBUFS); } MH_ALIGN(m0, sizeof(struct ip)); m0->m_flags = m->m_flags & M_COPYFLAGS; m0->m_next = m; m0->m_len = sizeof(struct ip); m0->m_pkthdr.len = m0->m_len + m->m_len; m->m_flags &= ~M_PKTHDR; m = m0; } else { M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); if (m == NULL) return (ENOBUFS); } /* * Fill in IP header. */ ip = mtod(m, struct ip *); *(long *)ip = 0; ip->ip_p = IPPROTO_IDP; ip->ip_src = ifn->ifen_src; ip->ip_dst = ifn->ifen_dst; ip->ip_len = (u_short)len + sizeof(struct ip); ip->ip_ttl = MAXTTL; /* * Output final datagram. */ error = (ip_output(m, (struct mbuf *)NULL, ro, SO_BROADCAST, NULL, NULL)); if (error) { ifn->ifen_ifnet.if_oerrors++; ifn->ifen_ifnet.if_ierrors = error; } return (error); m_freem(m); return (ENETUNREACH); } static void ipxipstart(ifp) struct ifnet *ifp; { panic("ipxip_start called\n"); } static struct ifreq ifr_ipxip = {"ipxip0"}; int ipxip_route(so, sopt) struct socket *so; struct sockopt *sopt; { int error; struct ifnet_en *ifn; struct sockaddr_in *src; struct ipxip_req rq; struct sockaddr_ipx *ipx_dst; struct sockaddr_in *ip_dst; struct route ro; error = sooptcopyin(sopt, &rq, sizeof rq, sizeof rq); if (error) return (error); ipx_dst = (struct sockaddr_ipx *)&rq.rq_ipx; ip_dst = (struct sockaddr_in *)&rq.rq_ip; /* * First, make sure we already have an IPX address: */ if (ipx_ifaddr == NULL) return (EADDRNOTAVAIL); /* * Now, determine if we can get to the destination */ bzero((caddr_t)&ro, sizeof(ro)); ro.ro_dst = *(struct sockaddr *)ip_dst; - rtalloc(&ro); + rtalloc_ign(&ro, 0); if (ro.ro_rt == NULL || ro.ro_rt->rt_ifp == NULL) { return (ENETUNREACH); } /* * And see how he's going to get back to us: * i.e., what return ip address do we use? */ { register struct in_ifaddr *ia; struct ifnet *ifp = ro.ro_rt->rt_ifp; for (ia = TAILQ_FIRST(&in_ifaddrhead); ia != NULL; ia = TAILQ_NEXT(ia, ia_link)) if (ia->ia_ifp == ifp) break; if (ia == NULL) ia = TAILQ_FIRST(&in_ifaddrhead); if (ia == NULL) { RTFREE(ro.ro_rt); return (EADDRNOTAVAIL); } src = (struct sockaddr_in *)&ia->ia_addr; } /* * Is there a free (pseudo-)interface or space? */ for (ifn = ipxip_list; ifn != NULL; ifn = ifn->ifen_next) { if ((ifn->ifen_ifnet.if_flags & IFF_UP) == 0) break; } if (ifn == NULL) ifn = ipxipattach(); if (ifn == NULL) { RTFREE(ro.ro_rt); return (ENOBUFS); } ifn->ifen_route = ro; ifn->ifen_dst = ip_dst->sin_addr; ifn->ifen_src = src->sin_addr; /* * now configure this as a point to point link */ ifr_ipxip.ifr_name[4] = '0' + ipxipif_units - 1; ifr_ipxip.ifr_dstaddr = *(struct sockaddr *)ipx_dst; ipx_control(so, (int)SIOCSIFDSTADDR, (caddr_t)&ifr_ipxip, (struct ifnet *)ifn, sopt->sopt_td); /* use any of our addresses */ satoipx_addr(ifr_ipxip.ifr_addr).x_host = ipx_ifaddr->ia_addr.sipx_addr.x_host; return (ipx_control(so, (int)SIOCSIFADDR, (caddr_t)&ifr_ipxip, (struct ifnet *)ifn, sopt->sopt_td)); } static int ipxip_free(ifp) struct ifnet *ifp; { register struct ifnet_en *ifn = (struct ifnet_en *)ifp; struct route *ro = & ifn->ifen_route; if (ro->ro_rt != NULL) { RTFREE(ro->ro_rt); ro->ro_rt = NULL; } ifp->if_flags &= ~IFF_UP; return (0); } void ipxip_ctlinput(cmd, sa, dummy) int cmd; struct sockaddr *sa; void *dummy; { struct sockaddr_in *sin; if ((unsigned)cmd >= PRC_NCMDS) return; if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK) return; sin = (struct sockaddr_in *)sa; if (sin->sin_addr.s_addr == INADDR_ANY) return; switch (cmd) { case PRC_ROUTEDEAD: case PRC_REDIRECT_NET: case PRC_REDIRECT_HOST: case PRC_REDIRECT_TOSNET: case PRC_REDIRECT_TOSHOST: ipxip_rtchange(&sin->sin_addr); break; } } static void ipxip_rtchange(dst) register struct in_addr *dst; { register struct ifnet_en *ifn; for (ifn = ipxip_list; ifn != NULL; ifn = ifn->ifen_next) { if (ifn->ifen_dst.s_addr == dst->s_addr && ifn->ifen_route.ro_rt != NULL) { RTFREE(ifn->ifen_route.ro_rt); ifn->ifen_route.ro_rt = NULL; } } } #endif /* IPXIP */ diff --git a/sys/netipx/ipx_outputfl.c b/sys/netipx/ipx_outputfl.c index bdca9a2bfb18..c2585dca38ac 100644 --- a/sys/netipx/ipx_outputfl.c +++ b/sys/netipx/ipx_outputfl.c @@ -1,260 +1,260 @@ /* * Copyright (c) 1995, Mike Mitchell * Copyright (c) 1984, 1985, 1986, 1987, 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. * * @(#)ipx_outputfl.c */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include static int ipx_copy_output = 0; int ipx_outputfl(m0, ro, flags) struct mbuf *m0; struct route *ro; int flags; { register struct ipx *ipx = mtod(m0, struct ipx *); register struct ifnet *ifp = NULL; int error = 0; struct sockaddr_ipx *dst; struct route ipxroute; /* * Route packet. */ if (ro == NULL) { ro = &ipxroute; bzero((caddr_t)ro, sizeof(*ro)); } dst = (struct sockaddr_ipx *)&ro->ro_dst; if (ro->ro_rt == NULL) { dst->sipx_family = AF_IPX; dst->sipx_len = sizeof(*dst); dst->sipx_addr = ipx->ipx_dna; dst->sipx_addr.x_port = 0; /* * If routing to interface only, * short circuit routing lookup. */ if (flags & IPX_ROUTETOIF) { struct ipx_ifaddr *ia = ipx_iaonnetof(&ipx->ipx_dna); if (ia == NULL) { ipxstat.ipxs_noroute++; error = ENETUNREACH; goto bad; } ifp = ia->ia_ifp; goto gotif; } - rtalloc(ro); + rtalloc_ign(ro, 0); } else if ((ro->ro_rt->rt_flags & RTF_UP) == 0) { /* * The old route has gone away; try for a new one. */ rtfree(ro->ro_rt); ro->ro_rt = NULL; - rtalloc(ro); + rtalloc_ign(ro, 0); } if (ro->ro_rt == NULL || (ifp = ro->ro_rt->rt_ifp) == NULL) { ipxstat.ipxs_noroute++; error = ENETUNREACH; goto bad; } ro->ro_rt->rt_use++; if (ro->ro_rt->rt_flags & (RTF_GATEWAY|RTF_HOST)) dst = (struct sockaddr_ipx *)ro->ro_rt->rt_gateway; gotif: /* * Look for multicast addresses and * and verify user is allowed to send * such a packet. */ if (dst->sipx_addr.x_host.c_host[0]&1) { if ((ifp->if_flags & (IFF_BROADCAST | IFF_LOOPBACK)) == 0) { error = EADDRNOTAVAIL; goto bad; } if ((flags & IPX_ALLOWBROADCAST) == 0) { error = EACCES; goto bad; } m0->m_flags |= M_BCAST; } if (htons(ipx->ipx_len) <= ifp->if_mtu) { ipxstat.ipxs_localout++; if (ipx_copy_output) { ipx_watch_output(m0, ifp); } error = (*ifp->if_output)(ifp, m0, (struct sockaddr *)dst, ro->ro_rt); goto done; } else { ipxstat.ipxs_mtutoosmall++; error = EMSGSIZE; } bad: if (ipx_copy_output) { ipx_watch_output(m0, ifp); } m_freem(m0); done: if (ro == &ipxroute && (flags & IPX_ROUTETOIF) == 0 && ro->ro_rt != NULL) { RTFREE(ro->ro_rt); ro->ro_rt = NULL; } return (error); } /* * This will broadcast the type 20 (Netbios) packet to all the interfaces * that have ipx configured and isn't in the list yet. */ int ipx_output_type20(m) struct mbuf *m; { register struct ipx *ipx; union ipx_net *nbnet; struct ipx_ifaddr *ia, *tia = NULL; int error = 0; struct mbuf *m1; int i; struct ifnet *ifp; struct sockaddr_ipx dst; /* * We have to get to the 32 bytes after the ipx header also, so * that we can fill in the network address of the receiving * interface. */ if ((m->m_flags & M_EXT || m->m_len < (sizeof(struct ipx) + 32)) && (m = m_pullup(m, sizeof(struct ipx) + 32)) == NULL) { ipxstat.ipxs_toosmall++; return (0); } ipx = mtod(m, struct ipx *); nbnet = (union ipx_net *)(ipx + 1); if (ipx->ipx_tc >= 8) goto bad; /* * Now see if we have already seen this. */ for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) if(ia->ia_ifa.ifa_ifp == m->m_pkthdr.rcvif) { if(tia == NULL) tia = ia; for (i=0;iipx_tc;i++,nbnet++) if(ipx_neteqnn(ia->ia_addr.sipx_addr.x_net, *nbnet)) goto bad; } /* * Don't route the packet if the interface where it come from * does not have an IPX address. */ if(tia == NULL) goto bad; /* * Add our receiving interface to the list. */ nbnet = (union ipx_net *)(ipx + 1); nbnet += ipx->ipx_tc; *nbnet = tia->ia_addr.sipx_addr.x_net; /* * Increment the hop count. */ ipx->ipx_tc++; ipxstat.ipxs_forward++; /* * Send to all directly connected ifaces not in list and * not to the one it came from. */ m->m_flags &= ~M_BCAST; bzero(&dst, sizeof(dst)); dst.sipx_family = AF_IPX; dst.sipx_len = 12; dst.sipx_addr.x_host = ipx_broadhost; for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) if(ia->ia_ifa.ifa_ifp != m->m_pkthdr.rcvif) { nbnet = (union ipx_net *)(ipx + 1); for (i=0;iipx_tc;i++,nbnet++) if(ipx_neteqnn(ia->ia_addr.sipx_addr.x_net, *nbnet)) goto skip_this; /* * Insert the net address of the dest net and * calculate the new checksum if needed. */ ifp = ia->ia_ifa.ifa_ifp; dst.sipx_addr.x_net = ia->ia_addr.sipx_addr.x_net; ipx->ipx_dna.x_net = dst.sipx_addr.x_net; if(ipx->ipx_sum != 0xffff) ipx->ipx_sum = ipx_cksum(m, ntohs(ipx->ipx_len)); m1 = m_copym(m, 0, M_COPYALL, M_DONTWAIT); if(m1) { error = (*ifp->if_output)(ifp, m1, (struct sockaddr *)&dst, NULL); /* XXX ipxstat.ipxs_localout++; */ } skip_this: ; } bad: m_freem(m); return (error); } diff --git a/sys/netipx/ipx_pcb.c b/sys/netipx/ipx_pcb.c index e1fcfcae2a46..663cfebd69f5 100644 --- a/sys/netipx/ipx_pcb.c +++ b/sys/netipx/ipx_pcb.c @@ -1,355 +1,355 @@ /* * Copyright (c) 2004 Robert N. M. Watson * Copyright (c) 1995, Mike Mitchell * Copyright (c) 1984, 1985, 1986, 1987, 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. * * @(#)ipx_pcb.c */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include static struct ipx_addr zeroipx_addr; static u_short ipxpcb_lport_cache; int ipx_pcballoc(so, head, td) struct socket *so; struct ipxpcbhead *head; struct thread *td; { register struct ipxpcb *ipxp; MALLOC(ipxp, struct ipxpcb *, sizeof *ipxp, M_PCB, M_NOWAIT | M_ZERO); if (ipxp == NULL) return (ENOBUFS); ipxp->ipxp_socket = so; if (ipxcksum) ipxp->ipxp_flags |= IPXP_CHECKSUM; LIST_INSERT_HEAD(head, ipxp, ipxp_list); so->so_pcb = (caddr_t)ipxp; return (0); } int ipx_pcbbind(ipxp, nam, td) register struct ipxpcb *ipxp; struct sockaddr *nam; struct thread *td; { register struct sockaddr_ipx *sipx; u_short lport = 0; if (ipxp->ipxp_lport || !ipx_nullhost(ipxp->ipxp_laddr)) return (EINVAL); if (nam == NULL) goto noname; sipx = (struct sockaddr_ipx *)nam; if (!ipx_nullhost(sipx->sipx_addr)) { int tport = sipx->sipx_port; sipx->sipx_port = 0; /* yech... */ if (ifa_ifwithaddr((struct sockaddr *)sipx) == 0) return (EADDRNOTAVAIL); sipx->sipx_port = tport; } lport = sipx->sipx_port; if (lport) { u_short aport = ntohs(lport); int error; if (aport < IPXPORT_RESERVED && td != NULL && (error = suser(td)) != 0) return (error); if (ipx_pcblookup(&zeroipx_addr, lport, 0)) return (EADDRINUSE); } ipxp->ipxp_laddr = sipx->sipx_addr; noname: if (lport == 0) do { ipxpcb_lport_cache++; if ((ipxpcb_lport_cache < IPXPORT_RESERVED) || (ipxpcb_lport_cache >= IPXPORT_WELLKNOWN)) ipxpcb_lport_cache = IPXPORT_RESERVED; lport = htons(ipxpcb_lport_cache); } while (ipx_pcblookup(&zeroipx_addr, lport, 0)); ipxp->ipxp_lport = lport; return (0); } /* * Connect from a socket to a specified address. * Both address and port must be specified in argument sipx. * If don't have a local address for this socket yet, * then pick one. */ int ipx_pcbconnect(ipxp, nam, td) struct ipxpcb *ipxp; struct sockaddr *nam; struct thread *td; { struct ipx_ifaddr *ia; register struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)nam; register struct ipx_addr *dst; register struct route *ro; struct ifnet *ifp; ia = NULL; if (sipx->sipx_family != AF_IPX) return (EAFNOSUPPORT); if (sipx->sipx_port == 0 || ipx_nullhost(sipx->sipx_addr)) return (EADDRNOTAVAIL); /* * If we haven't bound which network number to use as ours, * we will use the number of the outgoing interface. * This depends on having done a routing lookup, which * we will probably have to do anyway, so we might * as well do it now. On the other hand if we are * sending to multiple destinations we may have already * done the lookup, so see if we can use the route * from before. In any case, we only * chose a port number once, even if sending to multiple * destinations. */ ro = &ipxp->ipxp_route; dst = &satoipx_addr(ro->ro_dst); if (ipxp->ipxp_socket->so_options & SO_DONTROUTE) goto flush; if (!ipx_neteq(ipxp->ipxp_lastdst, sipx->sipx_addr)) goto flush; if (!ipx_hosteq(ipxp->ipxp_lastdst, sipx->sipx_addr)) { if (ro->ro_rt != NULL && !(ro->ro_rt->rt_flags & RTF_HOST)) { /* can patch route to avoid rtalloc */ *dst = sipx->sipx_addr; } else { flush: if (ro->ro_rt != NULL) RTFREE(ro->ro_rt); ro->ro_rt = NULL; } }/* else cached route is ok; do nothing */ ipxp->ipxp_lastdst = sipx->sipx_addr; if ((ipxp->ipxp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL)) { /* No route yet, so try to acquire one */ ro->ro_dst.sa_family = AF_IPX; ro->ro_dst.sa_len = sizeof(ro->ro_dst); *dst = sipx->sipx_addr; dst->x_port = 0; - rtalloc(ro); + rtalloc_ign(ro, 0); } if (ipx_neteqnn(ipxp->ipxp_laddr.x_net, ipx_zeronet)) { /* * If route is known or can be allocated now, * our src addr is taken from the i/f, else punt. */ /* * If we found a route, use the address * corresponding to the outgoing interface */ if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL) for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) if (ia->ia_ifp == ifp) break; if (ia == NULL) { u_short fport = sipx->sipx_addr.x_port; sipx->sipx_addr.x_port = 0; ia = (struct ipx_ifaddr *) ifa_ifwithdstaddr((struct sockaddr *)sipx); sipx->sipx_addr.x_port = fport; if (ia == NULL) ia = ipx_iaonnetof(&sipx->sipx_addr); if (ia == NULL) ia = ipx_ifaddr; if (ia == NULL) return (EADDRNOTAVAIL); } ipxp->ipxp_laddr.x_net = satoipx_addr(ia->ia_addr).x_net; } if (ipx_nullhost(ipxp->ipxp_laddr)) { /* * If route is known or can be allocated now, * our src addr is taken from the i/f, else punt. */ /* * If we found a route, use the address * corresponding to the outgoing interface */ if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL) for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) if (ia->ia_ifp == ifp) break; if (ia == NULL) { u_short fport = sipx->sipx_addr.x_port; sipx->sipx_addr.x_port = 0; ia = (struct ipx_ifaddr *) ifa_ifwithdstaddr((struct sockaddr *)sipx); sipx->sipx_addr.x_port = fport; if (ia == NULL) ia = ipx_iaonnetof(&sipx->sipx_addr); if (ia == NULL) ia = ipx_ifaddr; if (ia == NULL) return (EADDRNOTAVAIL); } ipxp->ipxp_laddr.x_host = satoipx_addr(ia->ia_addr).x_host; } if (ipx_pcblookup(&sipx->sipx_addr, ipxp->ipxp_lport, 0)) return (EADDRINUSE); if (ipxp->ipxp_lport == 0) ipx_pcbbind(ipxp, (struct sockaddr *)NULL, td); /* XXX just leave it zero if we can't find a route */ ipxp->ipxp_faddr = sipx->sipx_addr; /* Includes ipxp->ipxp_fport = sipx->sipx_port; */ return (0); } void ipx_pcbdisconnect(ipxp) struct ipxpcb *ipxp; { ipxp->ipxp_faddr = zeroipx_addr; if (ipxp->ipxp_socket->so_state & SS_NOFDREF) ipx_pcbdetach(ipxp); } void ipx_pcbdetach(ipxp) struct ipxpcb *ipxp; { struct socket *so = ipxp->ipxp_socket; ACCEPT_LOCK(); SOCK_LOCK(so); so->so_pcb = 0; sotryfree(so); if (ipxp->ipxp_route.ro_rt != NULL) rtfree(ipxp->ipxp_route.ro_rt); LIST_REMOVE(ipxp, ipxp_list); FREE(ipxp, M_PCB); } void ipx_setsockaddr(ipxp, nam) register struct ipxpcb *ipxp; struct sockaddr **nam; { struct sockaddr_ipx *sipx, ssipx; sipx = &ssipx; bzero((caddr_t)sipx, sizeof(*sipx)); sipx->sipx_len = sizeof(*sipx); sipx->sipx_family = AF_IPX; sipx->sipx_addr = ipxp->ipxp_laddr; *nam = sodupsockaddr((struct sockaddr *)sipx, M_NOWAIT); } void ipx_setpeeraddr(ipxp, nam) register struct ipxpcb *ipxp; struct sockaddr **nam; { struct sockaddr_ipx *sipx, ssipx; sipx = &ssipx; bzero((caddr_t)sipx, sizeof(*sipx)); sipx->sipx_len = sizeof(*sipx); sipx->sipx_family = AF_IPX; sipx->sipx_addr = ipxp->ipxp_faddr; *nam = sodupsockaddr((struct sockaddr *)sipx, M_NOWAIT); } struct ipxpcb * ipx_pcblookup(faddr, lport, wildp) struct ipx_addr *faddr; u_short lport; int wildp; { register struct ipxpcb *ipxp, *match = 0; int matchwild = 3, wildcard; u_short fport; fport = faddr->x_port; LIST_FOREACH(ipxp, &ipxpcb_list, ipxp_list) { if (ipxp->ipxp_lport != lport) continue; wildcard = 0; if (ipx_nullhost(ipxp->ipxp_faddr)) { if (!ipx_nullhost(*faddr)) wildcard++; } else { if (ipx_nullhost(*faddr)) wildcard++; else { if (!ipx_hosteq(ipxp->ipxp_faddr, *faddr)) continue; if (ipxp->ipxp_fport != fport) { if (ipxp->ipxp_fport != 0) continue; else wildcard++; } } } if (wildcard && wildp == 0) continue; if (wildcard < matchwild) { match = ipxp; matchwild = wildcard; if (wildcard == 0) break; } } return (match); }