ipx_outputfl.c revision 59683
111819Sjulian/*
211819Sjulian * Copyright (c) 1995, Mike Mitchell
311819Sjulian * Copyright (c) 1984, 1985, 1986, 1987, 1993
411819Sjulian *	The Regents of the University of California.  All rights reserved.
511819Sjulian *
611819Sjulian * Redistribution and use in source and binary forms, with or without
711819Sjulian * modification, are permitted provided that the following conditions
811819Sjulian * are met:
911819Sjulian * 1. Redistributions of source code must retain the above copyright
1011819Sjulian *    notice, this list of conditions and the following disclaimer.
1111819Sjulian * 2. Redistributions in binary form must reproduce the above copyright
1211819Sjulian *    notice, this list of conditions and the following disclaimer in the
1311819Sjulian *    documentation and/or other materials provided with the distribution.
1411819Sjulian * 3. All advertising materials mentioning features or use of this software
1511819Sjulian *    must display the following acknowledgement:
1611819Sjulian *	This product includes software developed by the University of
1711819Sjulian *	California, Berkeley and its contributors.
1811819Sjulian * 4. Neither the name of the University nor the names of its contributors
1911819Sjulian *    may be used to endorse or promote products derived from this software
2011819Sjulian *    without specific prior written permission.
2111819Sjulian *
2211819Sjulian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2311819Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2411819Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2511819Sjulian * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2611819Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2711819Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2811819Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2911819Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3011819Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3111819Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3211819Sjulian * SUCH DAMAGE.
3311819Sjulian *
3412057Sjulian *	@(#)ipx_outputfl.c
3512057Sjulian *
3650477Speter * $FreeBSD: head/sys/netipx/ipx_outputfl.c 59683 2000-04-27 10:29:14Z bp $
3711819Sjulian */
3811819Sjulian
3911819Sjulian#include <sys/param.h>
4011819Sjulian#include <sys/systm.h>
4111819Sjulian#include <sys/mbuf.h>
4211819Sjulian#include <sys/socket.h>
4311819Sjulian
4411819Sjulian#include <net/if.h>
4511819Sjulian#include <net/route.h>
4611819Sjulian
4711819Sjulian#include <netipx/ipx.h>
4811819Sjulian#include <netipx/ipx_if.h>
4911819Sjulian#include <netipx/ipx_var.h>
5011819Sjulian
5111819Sjulian#ifdef vax
5211819Sjulian#include <machine/mtpr.h>
5311819Sjulian#endif
5411819Sjulian
5533181Seivindstatic int ipx_copy_output = 0;
5611819Sjulian
5711819Sjulianint
5811819Sjulianipx_outputfl(m0, ro, flags)
5911819Sjulian	struct mbuf *m0;
6011819Sjulian	struct route *ro;
6111819Sjulian	int flags;
6211819Sjulian{
6311819Sjulian	register struct ipx *ipx = mtod(m0, struct ipx *);
6425652Sjhay	register struct ifnet *ifp = NULL;
6511819Sjulian	int error = 0;
6611819Sjulian	struct sockaddr_ipx *dst;
6711819Sjulian	struct route ipxroute;
6811819Sjulian
6911819Sjulian	/*
7011819Sjulian	 * Route packet.
7111819Sjulian	 */
7225652Sjhay	if (ro == NULL) {
7311819Sjulian		ro = &ipxroute;
7425652Sjhay		bzero((caddr_t)ro, sizeof(*ro));
7511819Sjulian	}
7611819Sjulian	dst = (struct sockaddr_ipx *)&ro->ro_dst;
7725652Sjhay	if (ro->ro_rt == NULL) {
7811819Sjulian		dst->sipx_family = AF_IPX;
7925652Sjhay		dst->sipx_len = sizeof(*dst);
8011819Sjulian		dst->sipx_addr = ipx->ipx_dna;
8111819Sjulian		dst->sipx_addr.x_port = 0;
8211819Sjulian		/*
8311819Sjulian		 * If routing to interface only,
8411819Sjulian		 * short circuit routing lookup.
8511819Sjulian		 */
8611819Sjulian		if (flags & IPX_ROUTETOIF) {
8711819Sjulian			struct ipx_ifaddr *ia = ipx_iaonnetof(&ipx->ipx_dna);
8811819Sjulian
8925652Sjhay			if (ia == NULL) {
9025652Sjhay				ipxstat.ipxs_noroute++;
9111819Sjulian				error = ENETUNREACH;
9211819Sjulian				goto bad;
9311819Sjulian			}
9411819Sjulian			ifp = ia->ia_ifp;
9511819Sjulian			goto gotif;
9611819Sjulian		}
9711819Sjulian		rtalloc(ro);
9811819Sjulian	} else if ((ro->ro_rt->rt_flags & RTF_UP) == 0) {
9911819Sjulian		/*
10011819Sjulian		 * The old route has gone away; try for a new one.
10111819Sjulian		 */
10211819Sjulian		rtfree(ro->ro_rt);
10311819Sjulian		ro->ro_rt = NULL;
10411819Sjulian		rtalloc(ro);
10511819Sjulian	}
10625652Sjhay	if (ro->ro_rt == NULL || (ifp = ro->ro_rt->rt_ifp) == NULL) {
10725652Sjhay		ipxstat.ipxs_noroute++;
10811819Sjulian		error = ENETUNREACH;
10911819Sjulian		goto bad;
11011819Sjulian	}
11111819Sjulian	ro->ro_rt->rt_use++;
11211819Sjulian	if (ro->ro_rt->rt_flags & (RTF_GATEWAY|RTF_HOST))
11311819Sjulian		dst = (struct sockaddr_ipx *)ro->ro_rt->rt_gateway;
11411819Sjuliangotif:
11511819Sjulian	/*
11611819Sjulian	 * Look for multicast addresses and
11711819Sjulian	 * and verify user is allowed to send
11811819Sjulian	 * such a packet.
11911819Sjulian	 */
12011819Sjulian	if (dst->sipx_addr.x_host.c_host[0]&1) {
12143712Sjhay		if ((ifp->if_flags & (IFF_BROADCAST | IFF_LOOPBACK)) == 0) {
12211819Sjulian			error = EADDRNOTAVAIL;
12311819Sjulian			goto bad;
12411819Sjulian		}
12511819Sjulian		if ((flags & IPX_ALLOWBROADCAST) == 0) {
12611819Sjulian			error = EACCES;
12711819Sjulian			goto bad;
12811819Sjulian		}
12943712Sjhay		m0->m_flags |= M_BCAST;
13011819Sjulian	}
13111819Sjulian
13211819Sjulian	if (htons(ipx->ipx_len) <= ifp->if_mtu) {
13325652Sjhay		ipxstat.ipxs_localout++;
13411819Sjulian		if (ipx_copy_output) {
13511819Sjulian			ipx_watch_output(m0, ifp);
13611819Sjulian		}
13711819Sjulian		error = (*ifp->if_output)(ifp, m0,
13811819Sjulian					(struct sockaddr *)dst, ro->ro_rt);
13911819Sjulian		goto done;
14025652Sjhay	} else {
14125652Sjhay		ipxstat.ipxs_mtutoosmall++;
14225652Sjhay		error = EMSGSIZE;
14325652Sjhay	}
14411819Sjulianbad:
14511819Sjulian	if (ipx_copy_output) {
14611819Sjulian		ipx_watch_output(m0, ifp);
14711819Sjulian	}
14811819Sjulian	m_freem(m0);
14911819Sjuliandone:
15025652Sjhay	if (ro == &ipxroute && (flags & IPX_ROUTETOIF) == 0 &&
15125652Sjhay	    ro->ro_rt != NULL) {
15211819Sjulian		RTFREE(ro->ro_rt);
15325652Sjhay		ro->ro_rt = NULL;
15411819Sjulian	}
15511819Sjulian	return (error);
15611819Sjulian}
15725652Sjhay
15825652Sjhay/*
15925652Sjhay * This will broadcast the type 20 (Netbios) packet to all the interfaces
16025652Sjhay * that have ipx configured and isn't in the list yet.
16125652Sjhay */
16225652Sjhayint
16325652Sjhayipx_output_type20(m)
16425652Sjhay	struct mbuf *m;
16525652Sjhay{
16625652Sjhay	register struct ipx *ipx;
16745572Seivind	union ipx_net *nbnet;
16825652Sjhay	struct ipx_ifaddr *ia, *tia = NULL;
16925652Sjhay	int error = 0;
17025652Sjhay	struct mbuf *m1;
17125652Sjhay	int i;
17225652Sjhay	struct ifnet *ifp;
17325652Sjhay	struct sockaddr_ipx dst;
17425652Sjhay
17525652Sjhay	/*
17625652Sjhay	 * We have to get to the 32 bytes after the ipx header also, so
17725652Sjhay	 * that we can fill in the network address of the receiving
17825652Sjhay	 * interface.
17925652Sjhay	 */
18025652Sjhay	if ((m->m_flags & M_EXT || m->m_len < (sizeof(struct ipx) + 32)) &&
18125652Sjhay	    (m = m_pullup(m, sizeof(struct ipx) + 32)) == NULL) {
18225652Sjhay		ipxstat.ipxs_toosmall++;
18325652Sjhay		return (0);
18425652Sjhay	}
18525652Sjhay	ipx = mtod(m, struct ipx *);
18625652Sjhay	nbnet = (union ipx_net *)(ipx + 1);
18725652Sjhay
18825652Sjhay	if (ipx->ipx_tc >= 8)
18925652Sjhay		goto bad;
19025652Sjhay	/*
19125652Sjhay	 * Now see if we have already seen this.
19225652Sjhay	 */
19325652Sjhay	for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
19425652Sjhay		if(ia->ia_ifa.ifa_ifp == m->m_pkthdr.rcvif) {
19525652Sjhay			if(tia == NULL)
19625652Sjhay				tia = ia;
19725652Sjhay
19825652Sjhay			for (i=0;i<ipx->ipx_tc;i++,nbnet++)
19925652Sjhay				if(ipx_neteqnn(ia->ia_addr.sipx_addr.x_net,
20025652Sjhay							*nbnet))
20125652Sjhay					goto bad;
20225652Sjhay		}
20325652Sjhay	/*
20425652Sjhay	 * Don't route the packet if the interface where it come from
20525652Sjhay	 * does not have an IPX address.
20625652Sjhay	 */
20725652Sjhay	if(tia == NULL)
20825652Sjhay		goto bad;
20925652Sjhay
21025652Sjhay	/*
21125652Sjhay	 * Add our receiving interface to the list.
21225652Sjhay	 */
21325652Sjhay        nbnet = (union ipx_net *)(ipx + 1);
21425652Sjhay	nbnet += ipx->ipx_tc;
21525652Sjhay	*nbnet = tia->ia_addr.sipx_addr.x_net;
21625652Sjhay
21725652Sjhay	/*
21825652Sjhay	 * Increment the hop count.
21925652Sjhay	 */
22025652Sjhay	ipx->ipx_tc++;
22125652Sjhay	ipxstat.ipxs_forward++;
22225652Sjhay
22325652Sjhay	/*
22425652Sjhay	 * Send to all directly connected ifaces not in list and
22525652Sjhay	 * not to the one it came from.
22625652Sjhay	 */
22725652Sjhay	m->m_flags &= ~M_BCAST;
22825652Sjhay	bzero(&dst, sizeof(dst));
22925652Sjhay	dst.sipx_family = AF_IPX;
23025652Sjhay	dst.sipx_len = 12;
23125652Sjhay	dst.sipx_addr.x_host = ipx_broadhost;
23225652Sjhay
23325652Sjhay	for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
23425652Sjhay		if(ia->ia_ifa.ifa_ifp != m->m_pkthdr.rcvif) {
23525652Sjhay        		nbnet = (union ipx_net *)(ipx + 1);
23625652Sjhay			for (i=0;i<ipx->ipx_tc;i++,nbnet++)
23725652Sjhay				if(ipx_neteqnn(ia->ia_addr.sipx_addr.x_net,
23825652Sjhay							*nbnet))
23925652Sjhay					goto skip_this;
24025652Sjhay
24125652Sjhay			/*
24225652Sjhay			 * Insert the net address of the dest net and
24325652Sjhay			 * calculate the new checksum if needed.
24425652Sjhay			 */
24525652Sjhay			ifp = ia->ia_ifa.ifa_ifp;
24625652Sjhay			dst.sipx_addr.x_net = ia->ia_addr.sipx_addr.x_net;
24725652Sjhay			ipx->ipx_dna.x_net = dst.sipx_addr.x_net;
24850519Sjhay			if(ipx->ipx_sum != 0xffff)
24950519Sjhay				ipx->ipx_sum = ipx_cksum(m, ntohs(ipx->ipx_len));
25059683Sbp
25159683Sbp			m1 = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
25225652Sjhay			if(m1) {
25325652Sjhay				error = (*ifp->if_output)(ifp, m1,
25425652Sjhay					(struct sockaddr *)&dst, NULL);
25525652Sjhay				/* XXX ipxstat.ipxs_localout++; */
25625652Sjhay			}
25727125Sbdeskip_this: ;
25825652Sjhay		}
25925652Sjhay
26025652Sjhaybad:
26125652Sjhay	m_freem(m);
26225652Sjhay	return (error);
26325652Sjhay}
264