ipx_outputfl.c revision 139556
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
3511819Sjulian */
3611819Sjulian
37116189Sobrien#include <sys/cdefs.h>
38116189Sobrien__FBSDID("$FreeBSD: head/sys/netipx/ipx_outputfl.c 139556 2005-01-02 01:39:38Z rwatson $");
39116189Sobrien
4011819Sjulian#include <sys/param.h>
4111819Sjulian#include <sys/systm.h>
4211819Sjulian#include <sys/mbuf.h>
4311819Sjulian#include <sys/socket.h>
4411819Sjulian
4511819Sjulian#include <net/if.h>
4611819Sjulian#include <net/route.h>
4711819Sjulian
4811819Sjulian#include <netipx/ipx.h>
4911819Sjulian#include <netipx/ipx_if.h>
5011819Sjulian#include <netipx/ipx_var.h>
5111819Sjulian
5233181Seivindstatic int ipx_copy_output = 0;
5311819Sjulian
5411819Sjulianint
5511819Sjulianipx_outputfl(m0, ro, flags)
5611819Sjulian	struct mbuf *m0;
5711819Sjulian	struct route *ro;
5811819Sjulian	int flags;
5911819Sjulian{
6011819Sjulian	register struct ipx *ipx = mtod(m0, struct ipx *);
6125652Sjhay	register struct ifnet *ifp = NULL;
6211819Sjulian	int error = 0;
6311819Sjulian	struct sockaddr_ipx *dst;
6411819Sjulian	struct route ipxroute;
6511819Sjulian
6611819Sjulian	/*
6711819Sjulian	 * Route packet.
6811819Sjulian	 */
6925652Sjhay	if (ro == NULL) {
7011819Sjulian		ro = &ipxroute;
7125652Sjhay		bzero((caddr_t)ro, sizeof(*ro));
7211819Sjulian	}
7311819Sjulian	dst = (struct sockaddr_ipx *)&ro->ro_dst;
7425652Sjhay	if (ro->ro_rt == NULL) {
7511819Sjulian		dst->sipx_family = AF_IPX;
7625652Sjhay		dst->sipx_len = sizeof(*dst);
7711819Sjulian		dst->sipx_addr = ipx->ipx_dna;
7811819Sjulian		dst->sipx_addr.x_port = 0;
7911819Sjulian		/*
8011819Sjulian		 * If routing to interface only,
8111819Sjulian		 * short circuit routing lookup.
8211819Sjulian		 */
8311819Sjulian		if (flags & IPX_ROUTETOIF) {
8411819Sjulian			struct ipx_ifaddr *ia = ipx_iaonnetof(&ipx->ipx_dna);
8511819Sjulian
8625652Sjhay			if (ia == NULL) {
8725652Sjhay				ipxstat.ipxs_noroute++;
8811819Sjulian				error = ENETUNREACH;
8911819Sjulian				goto bad;
9011819Sjulian			}
9111819Sjulian			ifp = ia->ia_ifp;
9211819Sjulian			goto gotif;
9311819Sjulian		}
94139556Srwatson		rtalloc_ign(ro, 0);
9511819Sjulian	} else if ((ro->ro_rt->rt_flags & RTF_UP) == 0) {
9611819Sjulian		/*
9711819Sjulian		 * The old route has gone away; try for a new one.
9811819Sjulian		 */
9911819Sjulian		rtfree(ro->ro_rt);
10011819Sjulian		ro->ro_rt = NULL;
101139556Srwatson		rtalloc_ign(ro, 0);
10211819Sjulian	}
10325652Sjhay	if (ro->ro_rt == NULL || (ifp = ro->ro_rt->rt_ifp) == NULL) {
10425652Sjhay		ipxstat.ipxs_noroute++;
10511819Sjulian		error = ENETUNREACH;
10611819Sjulian		goto bad;
10711819Sjulian	}
10811819Sjulian	ro->ro_rt->rt_use++;
10911819Sjulian	if (ro->ro_rt->rt_flags & (RTF_GATEWAY|RTF_HOST))
11011819Sjulian		dst = (struct sockaddr_ipx *)ro->ro_rt->rt_gateway;
11111819Sjuliangotif:
11211819Sjulian	/*
11311819Sjulian	 * Look for multicast addresses and
11411819Sjulian	 * and verify user is allowed to send
11511819Sjulian	 * such a packet.
11611819Sjulian	 */
11711819Sjulian	if (dst->sipx_addr.x_host.c_host[0]&1) {
11843712Sjhay		if ((ifp->if_flags & (IFF_BROADCAST | IFF_LOOPBACK)) == 0) {
11911819Sjulian			error = EADDRNOTAVAIL;
12011819Sjulian			goto bad;
12111819Sjulian		}
12211819Sjulian		if ((flags & IPX_ALLOWBROADCAST) == 0) {
12311819Sjulian			error = EACCES;
12411819Sjulian			goto bad;
12511819Sjulian		}
12643712Sjhay		m0->m_flags |= M_BCAST;
12711819Sjulian	}
12811819Sjulian
12911819Sjulian	if (htons(ipx->ipx_len) <= ifp->if_mtu) {
13025652Sjhay		ipxstat.ipxs_localout++;
13111819Sjulian		if (ipx_copy_output) {
13211819Sjulian			ipx_watch_output(m0, ifp);
13311819Sjulian		}
13411819Sjulian		error = (*ifp->if_output)(ifp, m0,
13511819Sjulian					(struct sockaddr *)dst, ro->ro_rt);
13611819Sjulian		goto done;
13725652Sjhay	} else {
13825652Sjhay		ipxstat.ipxs_mtutoosmall++;
13925652Sjhay		error = EMSGSIZE;
14025652Sjhay	}
14111819Sjulianbad:
14211819Sjulian	if (ipx_copy_output) {
14311819Sjulian		ipx_watch_output(m0, ifp);
14411819Sjulian	}
14511819Sjulian	m_freem(m0);
14611819Sjuliandone:
14725652Sjhay	if (ro == &ipxroute && (flags & IPX_ROUTETOIF) == 0 &&
14825652Sjhay	    ro->ro_rt != NULL) {
14911819Sjulian		RTFREE(ro->ro_rt);
15025652Sjhay		ro->ro_rt = NULL;
15111819Sjulian	}
15211819Sjulian	return (error);
15311819Sjulian}
15425652Sjhay
15525652Sjhay/*
15625652Sjhay * This will broadcast the type 20 (Netbios) packet to all the interfaces
15725652Sjhay * that have ipx configured and isn't in the list yet.
15825652Sjhay */
15925652Sjhayint
16025652Sjhayipx_output_type20(m)
16125652Sjhay	struct mbuf *m;
16225652Sjhay{
16325652Sjhay	register struct ipx *ipx;
16445572Seivind	union ipx_net *nbnet;
16525652Sjhay	struct ipx_ifaddr *ia, *tia = NULL;
16625652Sjhay	int error = 0;
16725652Sjhay	struct mbuf *m1;
16825652Sjhay	int i;
16925652Sjhay	struct ifnet *ifp;
17025652Sjhay	struct sockaddr_ipx dst;
17125652Sjhay
17225652Sjhay	/*
17325652Sjhay	 * We have to get to the 32 bytes after the ipx header also, so
17425652Sjhay	 * that we can fill in the network address of the receiving
17525652Sjhay	 * interface.
17625652Sjhay	 */
17725652Sjhay	if ((m->m_flags & M_EXT || m->m_len < (sizeof(struct ipx) + 32)) &&
17825652Sjhay	    (m = m_pullup(m, sizeof(struct ipx) + 32)) == NULL) {
17925652Sjhay		ipxstat.ipxs_toosmall++;
18025652Sjhay		return (0);
18125652Sjhay	}
18225652Sjhay	ipx = mtod(m, struct ipx *);
18325652Sjhay	nbnet = (union ipx_net *)(ipx + 1);
18425652Sjhay
18525652Sjhay	if (ipx->ipx_tc >= 8)
18625652Sjhay		goto bad;
18725652Sjhay	/*
18825652Sjhay	 * Now see if we have already seen this.
18925652Sjhay	 */
19025652Sjhay	for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
19125652Sjhay		if(ia->ia_ifa.ifa_ifp == m->m_pkthdr.rcvif) {
19225652Sjhay			if(tia == NULL)
19325652Sjhay				tia = ia;
19425652Sjhay
19525652Sjhay			for (i=0;i<ipx->ipx_tc;i++,nbnet++)
19625652Sjhay				if(ipx_neteqnn(ia->ia_addr.sipx_addr.x_net,
19725652Sjhay							*nbnet))
19825652Sjhay					goto bad;
19925652Sjhay		}
20025652Sjhay	/*
20125652Sjhay	 * Don't route the packet if the interface where it come from
20225652Sjhay	 * does not have an IPX address.
20325652Sjhay	 */
20425652Sjhay	if(tia == NULL)
20525652Sjhay		goto bad;
20625652Sjhay
20725652Sjhay	/*
20825652Sjhay	 * Add our receiving interface to the list.
20925652Sjhay	 */
21025652Sjhay        nbnet = (union ipx_net *)(ipx + 1);
21125652Sjhay	nbnet += ipx->ipx_tc;
21225652Sjhay	*nbnet = tia->ia_addr.sipx_addr.x_net;
21325652Sjhay
21425652Sjhay	/*
21525652Sjhay	 * Increment the hop count.
21625652Sjhay	 */
21725652Sjhay	ipx->ipx_tc++;
21825652Sjhay	ipxstat.ipxs_forward++;
21925652Sjhay
22025652Sjhay	/*
22125652Sjhay	 * Send to all directly connected ifaces not in list and
22225652Sjhay	 * not to the one it came from.
22325652Sjhay	 */
22425652Sjhay	m->m_flags &= ~M_BCAST;
22525652Sjhay	bzero(&dst, sizeof(dst));
22625652Sjhay	dst.sipx_family = AF_IPX;
22725652Sjhay	dst.sipx_len = 12;
22825652Sjhay	dst.sipx_addr.x_host = ipx_broadhost;
22925652Sjhay
23025652Sjhay	for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
23125652Sjhay		if(ia->ia_ifa.ifa_ifp != m->m_pkthdr.rcvif) {
23225652Sjhay        		nbnet = (union ipx_net *)(ipx + 1);
23325652Sjhay			for (i=0;i<ipx->ipx_tc;i++,nbnet++)
23425652Sjhay				if(ipx_neteqnn(ia->ia_addr.sipx_addr.x_net,
23525652Sjhay							*nbnet))
23625652Sjhay					goto skip_this;
23725652Sjhay
23825652Sjhay			/*
23925652Sjhay			 * Insert the net address of the dest net and
24025652Sjhay			 * calculate the new checksum if needed.
24125652Sjhay			 */
24225652Sjhay			ifp = ia->ia_ifa.ifa_ifp;
24325652Sjhay			dst.sipx_addr.x_net = ia->ia_addr.sipx_addr.x_net;
24425652Sjhay			ipx->ipx_dna.x_net = dst.sipx_addr.x_net;
24550519Sjhay			if(ipx->ipx_sum != 0xffff)
24650519Sjhay				ipx->ipx_sum = ipx_cksum(m, ntohs(ipx->ipx_len));
24759683Sbp
248111119Simp			m1 = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
24925652Sjhay			if(m1) {
25025652Sjhay				error = (*ifp->if_output)(ifp, m1,
25125652Sjhay					(struct sockaddr *)&dst, NULL);
25225652Sjhay				/* XXX ipxstat.ipxs_localout++; */
25325652Sjhay			}
25427125Sbdeskip_this: ;
25525652Sjhay		}
25625652Sjhay
25725652Sjhaybad:
25825652Sjhay	m_freem(m);
25925652Sjhay	return (error);
26025652Sjhay}
261