1139823Simp/*-
211819Sjulian * Copyright (c) 1984, 1985, 1986, 1987, 1993
311819Sjulian *	The Regents of the University of California.  All rights reserved.
411819Sjulian *
511819Sjulian * Redistribution and use in source and binary forms, with or without
611819Sjulian * modification, are permitted provided that the following conditions
711819Sjulian * are met:
811819Sjulian * 1. Redistributions of source code must retain the above copyright
911819Sjulian *    notice, this list of conditions and the following disclaimer.
1011819Sjulian * 2. Redistributions in binary form must reproduce the above copyright
1111819Sjulian *    notice, this list of conditions and the following disclaimer in the
1211819Sjulian *    documentation and/or other materials provided with the distribution.
13165899Srwatson * 4. Neither the name of the University nor the names of its contributors
14165899Srwatson *    may be used to endorse or promote products derived from this software
15165899Srwatson *    without specific prior written permission.
16165899Srwatson *
17165899Srwatson * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18165899Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19165899Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20165899Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21165899Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22165899Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23165899Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24165899Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25165899Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26165899Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27165899Srwatson * SUCH DAMAGE.
28165899Srwatson *
29165899Srwatson * Copyright (c) 1995, Mike Mitchell
30165899Srwatson *
31165899Srwatson * Redistribution and use in source and binary forms, with or without
32165899Srwatson * modification, are permitted provided that the following conditions
33165899Srwatson * are met:
34165899Srwatson * 1. Redistributions of source code must retain the above copyright
35165899Srwatson *    notice, this list of conditions and the following disclaimer.
36165899Srwatson * 2. Redistributions in binary form must reproduce the above copyright
37165899Srwatson *    notice, this list of conditions and the following disclaimer in the
38165899Srwatson *    documentation and/or other materials provided with the distribution.
3911819Sjulian * 3. All advertising materials mentioning features or use of this software
4011819Sjulian *    must display the following acknowledgement:
4111819Sjulian *	This product includes software developed by the University of
4211819Sjulian *	California, Berkeley and its contributors.
4311819Sjulian * 4. Neither the name of the University nor the names of its contributors
4411819Sjulian *    may be used to endorse or promote products derived from this software
4511819Sjulian *    without specific prior written permission.
4611819Sjulian *
4711819Sjulian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
4811819Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4911819Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5011819Sjulian * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
5111819Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5211819Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5311819Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5411819Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5511819Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5611819Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5711819Sjulian * SUCH DAMAGE.
5811819Sjulian *
5912057Sjulian *	@(#)ipx_outputfl.c
6011819Sjulian */
6111819Sjulian
62116189Sobrien#include <sys/cdefs.h>
63116189Sobrien__FBSDID("$FreeBSD$");
64116189Sobrien
6511819Sjulian#include <sys/param.h>
6611819Sjulian#include <sys/systm.h>
6711819Sjulian#include <sys/mbuf.h>
6811819Sjulian#include <sys/socket.h>
6911819Sjulian
7011819Sjulian#include <net/if.h>
7111819Sjulian#include <net/route.h>
7211819Sjulian
7311819Sjulian#include <netipx/ipx.h>
7411819Sjulian#include <netipx/ipx_if.h>
7511819Sjulian#include <netipx/ipx_var.h>
7611819Sjulian
7711819Sjulianint
78169463Srwatsonipx_outputfl(struct mbuf *m0, struct route *ro, int flags)
7911819Sjulian{
80169463Srwatson	struct ipx *ipx = mtod(m0, struct ipx *);
81169463Srwatson	struct ifnet *ifp = NULL;
8211819Sjulian	int error = 0;
8311819Sjulian	struct sockaddr_ipx *dst;
8411819Sjulian	struct route ipxroute;
8511819Sjulian
8611819Sjulian	/*
8711819Sjulian	 * Route packet.
8811819Sjulian	 */
8925652Sjhay	if (ro == NULL) {
9011819Sjulian		ro = &ipxroute;
9125652Sjhay		bzero((caddr_t)ro, sizeof(*ro));
9211819Sjulian	}
9311819Sjulian	dst = (struct sockaddr_ipx *)&ro->ro_dst;
9425652Sjhay	if (ro->ro_rt == NULL) {
9511819Sjulian		dst->sipx_family = AF_IPX;
9625652Sjhay		dst->sipx_len = sizeof(*dst);
9711819Sjulian		dst->sipx_addr = ipx->ipx_dna;
9811819Sjulian		dst->sipx_addr.x_port = 0;
9911819Sjulian		/*
10011819Sjulian		 * If routing to interface only,
10111819Sjulian		 * short circuit routing lookup.
10211819Sjulian		 */
10311819Sjulian		if (flags & IPX_ROUTETOIF) {
104194608Srwatson			struct ipx_ifaddr *ia;
10511819Sjulian
106194608Srwatson			IPX_IFADDR_RLOCK();
107194608Srwatson			ia = ipx_iaonnetof(&ipx->ipx_dna);
10825652Sjhay			if (ia == NULL) {
109194608Srwatson				IPX_IFADDR_RUNLOCK();
11025652Sjhay				ipxstat.ipxs_noroute++;
11111819Sjulian				error = ENETUNREACH;
11211819Sjulian				goto bad;
11311819Sjulian			}
11411819Sjulian			ifp = ia->ia_ifp;
115194608Srwatson			IPX_IFADDR_RUNLOCK();
11611819Sjulian			goto gotif;
11711819Sjulian		}
118139556Srwatson		rtalloc_ign(ro, 0);
11911819Sjulian	} else if ((ro->ro_rt->rt_flags & RTF_UP) == 0) {
12011819Sjulian		/*
12111819Sjulian		 * The old route has gone away; try for a new one.
12211819Sjulian		 */
123139557Srwatson		RTFREE(ro->ro_rt);
12411819Sjulian		ro->ro_rt = NULL;
125139556Srwatson		rtalloc_ign(ro, 0);
12611819Sjulian	}
12725652Sjhay	if (ro->ro_rt == NULL || (ifp = ro->ro_rt->rt_ifp) == NULL) {
12825652Sjhay		ipxstat.ipxs_noroute++;
12911819Sjulian		error = ENETUNREACH;
13011819Sjulian		goto bad;
13111819Sjulian	}
13211819Sjulian	ro->ro_rt->rt_use++;
13311819Sjulian	if (ro->ro_rt->rt_flags & (RTF_GATEWAY|RTF_HOST))
13411819Sjulian		dst = (struct sockaddr_ipx *)ro->ro_rt->rt_gateway;
13511819Sjuliangotif:
13611819Sjulian	/*
13711819Sjulian	 * Look for multicast addresses and
13811819Sjulian	 * and verify user is allowed to send
13911819Sjulian	 * such a packet.
14011819Sjulian	 */
14111819Sjulian	if (dst->sipx_addr.x_host.c_host[0]&1) {
14243712Sjhay		if ((ifp->if_flags & (IFF_BROADCAST | IFF_LOOPBACK)) == 0) {
14311819Sjulian			error = EADDRNOTAVAIL;
14411819Sjulian			goto bad;
14511819Sjulian		}
14611819Sjulian		if ((flags & IPX_ALLOWBROADCAST) == 0) {
14711819Sjulian			error = EACCES;
14811819Sjulian			goto bad;
14911819Sjulian		}
15043712Sjhay		m0->m_flags |= M_BCAST;
15111819Sjulian	}
15211819Sjulian
15311819Sjulian	if (htons(ipx->ipx_len) <= ifp->if_mtu) {
15425652Sjhay		ipxstat.ipxs_localout++;
15511819Sjulian		error = (*ifp->if_output)(ifp, m0,
156191148Skmacy					(struct sockaddr *)dst, ro);
15711819Sjulian		goto done;
15825652Sjhay	} else {
15925652Sjhay		ipxstat.ipxs_mtutoosmall++;
16025652Sjhay		error = EMSGSIZE;
16125652Sjhay	}
16211819Sjulianbad:
16311819Sjulian	m_freem(m0);
16411819Sjuliandone:
16525652Sjhay	if (ro == &ipxroute && (flags & IPX_ROUTETOIF) == 0 &&
16625652Sjhay	    ro->ro_rt != NULL) {
16711819Sjulian		RTFREE(ro->ro_rt);
16825652Sjhay		ro->ro_rt = NULL;
16911819Sjulian	}
17011819Sjulian	return (error);
17111819Sjulian}
17225652Sjhay
17325652Sjhay/*
17425652Sjhay * This will broadcast the type 20 (Netbios) packet to all the interfaces
17525652Sjhay * that have ipx configured and isn't in the list yet.
17625652Sjhay */
17725652Sjhayint
178169463Srwatsonipx_output_type20(struct mbuf *m)
17925652Sjhay{
180169463Srwatson	struct ipx *ipx;
18145572Seivind	union ipx_net *nbnet;
182194905Srwatson	struct ipx_ifaddr *ia, *tia;
18325652Sjhay	int error = 0;
18425652Sjhay	struct mbuf *m1;
18525652Sjhay	int i;
18625652Sjhay	struct ifnet *ifp;
18725652Sjhay	struct sockaddr_ipx dst;
18825652Sjhay
18925652Sjhay	/*
19025652Sjhay	 * We have to get to the 32 bytes after the ipx header also, so
19125652Sjhay	 * that we can fill in the network address of the receiving
19225652Sjhay	 * interface.
19325652Sjhay	 */
19425652Sjhay	if ((m->m_flags & M_EXT || m->m_len < (sizeof(struct ipx) + 32)) &&
19525652Sjhay	    (m = m_pullup(m, sizeof(struct ipx) + 32)) == NULL) {
19625652Sjhay		ipxstat.ipxs_toosmall++;
19725652Sjhay		return (0);
19825652Sjhay	}
19925652Sjhay	ipx = mtod(m, struct ipx *);
20025652Sjhay	nbnet = (union ipx_net *)(ipx + 1);
20125652Sjhay
20225652Sjhay	if (ipx->ipx_tc >= 8)
20325652Sjhay		goto bad;
20425652Sjhay	/*
20525652Sjhay	 * Now see if we have already seen this.
20625652Sjhay	 */
207194905Srwatson	tia = NULL;
208194608Srwatson	IPX_IFADDR_RLOCK();
209194905Srwatson	TAILQ_FOREACH(ia, &ipx_ifaddrhead, ia_link) {
210194905Srwatson		if (ia->ia_ifa.ifa_ifp == m->m_pkthdr.rcvif) {
211194905Srwatson			if (tia == NULL)
21225652Sjhay				tia = ia;
213194905Srwatson			for (i=0; i < ipx->ipx_tc; i++, nbnet++) {
214194905Srwatson				if (ipx_neteqnn(ia->ia_addr.sipx_addr.x_net,
215194905Srwatson				    *nbnet)) {
216194608Srwatson					IPX_IFADDR_RUNLOCK();
21725652Sjhay					goto bad;
218194608Srwatson				}
219194905Srwatson			}
22025652Sjhay		}
221194905Srwatson	}
222194608Srwatson
22325652Sjhay	/*
22425652Sjhay	 * Don't route the packet if the interface where it come from
22525652Sjhay	 * does not have an IPX address.
22625652Sjhay	 */
227194608Srwatson	if (tia == NULL) {
228194608Srwatson		IPX_IFADDR_RUNLOCK();
22925652Sjhay		goto bad;
230194608Srwatson	}
23125652Sjhay
23225652Sjhay	/*
23325652Sjhay	 * Add our receiving interface to the list.
23425652Sjhay	 */
23525652Sjhay        nbnet = (union ipx_net *)(ipx + 1);
23625652Sjhay	nbnet += ipx->ipx_tc;
23725652Sjhay	*nbnet = tia->ia_addr.sipx_addr.x_net;
23825652Sjhay
23925652Sjhay	/*
24025652Sjhay	 * Increment the hop count.
24125652Sjhay	 */
24225652Sjhay	ipx->ipx_tc++;
24325652Sjhay	ipxstat.ipxs_forward++;
24425652Sjhay
24525652Sjhay	/*
24625652Sjhay	 * Send to all directly connected ifaces not in list and
24725652Sjhay	 * not to the one it came from.
24825652Sjhay	 */
24925652Sjhay	m->m_flags &= ~M_BCAST;
25025652Sjhay	bzero(&dst, sizeof(dst));
25125652Sjhay	dst.sipx_family = AF_IPX;
25225652Sjhay	dst.sipx_len = 12;
25325652Sjhay	dst.sipx_addr.x_host = ipx_broadhost;
25425652Sjhay
255194905Srwatson	TAILQ_FOREACH(ia, &ipx_ifaddrhead, ia_link) {
256194905Srwatson		if (ia->ia_ifa.ifa_ifp != m->m_pkthdr.rcvif) {
25725652Sjhay        		nbnet = (union ipx_net *)(ipx + 1);
258194905Srwatson			for (i=0; i < ipx->ipx_tc; i++, nbnet++)
259194905Srwatson				if (ipx_neteqnn(ia->ia_addr.sipx_addr.x_net,
260194905Srwatson				    *nbnet))
26125652Sjhay					goto skip_this;
26225652Sjhay
26325652Sjhay			/*
26425652Sjhay			 * Insert the net address of the dest net and
26525652Sjhay			 * calculate the new checksum if needed.
26625652Sjhay			 */
26725652Sjhay			ifp = ia->ia_ifa.ifa_ifp;
26825652Sjhay			dst.sipx_addr.x_net = ia->ia_addr.sipx_addr.x_net;
26925652Sjhay			ipx->ipx_dna.x_net = dst.sipx_addr.x_net;
27050519Sjhay			if(ipx->ipx_sum != 0xffff)
27150519Sjhay				ipx->ipx_sum = ipx_cksum(m, ntohs(ipx->ipx_len));
27259683Sbp
273243882Sglebius			m1 = m_copym(m, 0, M_COPYALL, M_NOWAIT);
27425652Sjhay			if(m1) {
27525652Sjhay				error = (*ifp->if_output)(ifp, m1,
27625652Sjhay					(struct sockaddr *)&dst, NULL);
27725652Sjhay				/* XXX ipxstat.ipxs_localout++; */
27825652Sjhay			}
27927125Sbdeskip_this: ;
28025652Sjhay		}
281194905Srwatson	}
282194608Srwatson	IPX_IFADDR_RUNLOCK();
28325652Sjhay
28425652Sjhaybad:
28525652Sjhay	m_freem(m);
28625652Sjhay	return (error);
28725652Sjhay}
288