ipx_outputfl.c revision 191148
1/*-
2 * Copyright (c) 1984, 1985, 1986, 1987, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * Copyright (c) 1995, Mike Mitchell
30 *
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
33 * are met:
34 * 1. Redistributions of source code must retain the above copyright
35 *    notice, this list of conditions and the following disclaimer.
36 * 2. Redistributions in binary form must reproduce the above copyright
37 *    notice, this list of conditions and the following disclaimer in the
38 *    documentation and/or other materials provided with the distribution.
39 * 3. All advertising materials mentioning features or use of this software
40 *    must display the following acknowledgement:
41 *	This product includes software developed by the University of
42 *	California, Berkeley and its contributors.
43 * 4. Neither the name of the University nor the names of its contributors
44 *    may be used to endorse or promote products derived from this software
45 *    without specific prior written permission.
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57 * SUCH DAMAGE.
58 *
59 *	@(#)ipx_outputfl.c
60 */
61
62#include <sys/cdefs.h>
63__FBSDID("$FreeBSD: head/sys/netipx/ipx_outputfl.c 191148 2009-04-16 20:30:28Z kmacy $");
64
65#include <sys/param.h>
66#include <sys/systm.h>
67#include <sys/mbuf.h>
68#include <sys/socket.h>
69
70#include <net/if.h>
71#include <net/route.h>
72
73#include <netipx/ipx.h>
74#include <netipx/ipx_if.h>
75#include <netipx/ipx_var.h>
76
77static int ipx_copy_output = 0;
78
79int
80ipx_outputfl(struct mbuf *m0, struct route *ro, int flags)
81{
82	struct ipx *ipx = mtod(m0, struct ipx *);
83	struct ifnet *ifp = NULL;
84	int error = 0;
85	struct sockaddr_ipx *dst;
86	struct route ipxroute;
87
88	/*
89	 * Route packet.
90	 */
91	if (ro == NULL) {
92		ro = &ipxroute;
93		bzero((caddr_t)ro, sizeof(*ro));
94	}
95	dst = (struct sockaddr_ipx *)&ro->ro_dst;
96	if (ro->ro_rt == NULL) {
97		dst->sipx_family = AF_IPX;
98		dst->sipx_len = sizeof(*dst);
99		dst->sipx_addr = ipx->ipx_dna;
100		dst->sipx_addr.x_port = 0;
101		/*
102		 * If routing to interface only,
103		 * short circuit routing lookup.
104		 */
105		if (flags & IPX_ROUTETOIF) {
106			struct ipx_ifaddr *ia = ipx_iaonnetof(&ipx->ipx_dna);
107
108			if (ia == NULL) {
109				ipxstat.ipxs_noroute++;
110				error = ENETUNREACH;
111				goto bad;
112			}
113			ifp = ia->ia_ifp;
114			goto gotif;
115		}
116		rtalloc_ign(ro, 0);
117	} else if ((ro->ro_rt->rt_flags & RTF_UP) == 0) {
118		/*
119		 * The old route has gone away; try for a new one.
120		 */
121		RTFREE(ro->ro_rt);
122		ro->ro_rt = NULL;
123		rtalloc_ign(ro, 0);
124	}
125	if (ro->ro_rt == NULL || (ifp = ro->ro_rt->rt_ifp) == NULL) {
126		ipxstat.ipxs_noroute++;
127		error = ENETUNREACH;
128		goto bad;
129	}
130	ro->ro_rt->rt_use++;
131	if (ro->ro_rt->rt_flags & (RTF_GATEWAY|RTF_HOST))
132		dst = (struct sockaddr_ipx *)ro->ro_rt->rt_gateway;
133gotif:
134	/*
135	 * Look for multicast addresses and
136	 * and verify user is allowed to send
137	 * such a packet.
138	 */
139	if (dst->sipx_addr.x_host.c_host[0]&1) {
140		if ((ifp->if_flags & (IFF_BROADCAST | IFF_LOOPBACK)) == 0) {
141			error = EADDRNOTAVAIL;
142			goto bad;
143		}
144		if ((flags & IPX_ALLOWBROADCAST) == 0) {
145			error = EACCES;
146			goto bad;
147		}
148		m0->m_flags |= M_BCAST;
149	}
150
151	if (htons(ipx->ipx_len) <= ifp->if_mtu) {
152		ipxstat.ipxs_localout++;
153		if (ipx_copy_output) {
154			ipx_watch_output(m0, ifp);
155		}
156		error = (*ifp->if_output)(ifp, m0,
157					(struct sockaddr *)dst, ro);
158		goto done;
159	} else {
160		ipxstat.ipxs_mtutoosmall++;
161		error = EMSGSIZE;
162	}
163bad:
164	if (ipx_copy_output) {
165		ipx_watch_output(m0, ifp);
166	}
167	m_freem(m0);
168done:
169	if (ro == &ipxroute && (flags & IPX_ROUTETOIF) == 0 &&
170	    ro->ro_rt != NULL) {
171		RTFREE(ro->ro_rt);
172		ro->ro_rt = NULL;
173	}
174	return (error);
175}
176
177/*
178 * This will broadcast the type 20 (Netbios) packet to all the interfaces
179 * that have ipx configured and isn't in the list yet.
180 */
181int
182ipx_output_type20(struct mbuf *m)
183{
184	struct ipx *ipx;
185	union ipx_net *nbnet;
186	struct ipx_ifaddr *ia, *tia = NULL;
187	int error = 0;
188	struct mbuf *m1;
189	int i;
190	struct ifnet *ifp;
191	struct sockaddr_ipx dst;
192
193	/*
194	 * We have to get to the 32 bytes after the ipx header also, so
195	 * that we can fill in the network address of the receiving
196	 * interface.
197	 */
198	if ((m->m_flags & M_EXT || m->m_len < (sizeof(struct ipx) + 32)) &&
199	    (m = m_pullup(m, sizeof(struct ipx) + 32)) == NULL) {
200		ipxstat.ipxs_toosmall++;
201		return (0);
202	}
203	ipx = mtod(m, struct ipx *);
204	nbnet = (union ipx_net *)(ipx + 1);
205
206	if (ipx->ipx_tc >= 8)
207		goto bad;
208	/*
209	 * Now see if we have already seen this.
210	 */
211	for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
212		if(ia->ia_ifa.ifa_ifp == m->m_pkthdr.rcvif) {
213			if(tia == NULL)
214				tia = ia;
215
216			for (i=0;i<ipx->ipx_tc;i++,nbnet++)
217				if(ipx_neteqnn(ia->ia_addr.sipx_addr.x_net,
218							*nbnet))
219					goto bad;
220		}
221	/*
222	 * Don't route the packet if the interface where it come from
223	 * does not have an IPX address.
224	 */
225	if(tia == NULL)
226		goto bad;
227
228	/*
229	 * Add our receiving interface to the list.
230	 */
231        nbnet = (union ipx_net *)(ipx + 1);
232	nbnet += ipx->ipx_tc;
233	*nbnet = tia->ia_addr.sipx_addr.x_net;
234
235	/*
236	 * Increment the hop count.
237	 */
238	ipx->ipx_tc++;
239	ipxstat.ipxs_forward++;
240
241	/*
242	 * Send to all directly connected ifaces not in list and
243	 * not to the one it came from.
244	 */
245	m->m_flags &= ~M_BCAST;
246	bzero(&dst, sizeof(dst));
247	dst.sipx_family = AF_IPX;
248	dst.sipx_len = 12;
249	dst.sipx_addr.x_host = ipx_broadhost;
250
251	for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
252		if(ia->ia_ifa.ifa_ifp != m->m_pkthdr.rcvif) {
253        		nbnet = (union ipx_net *)(ipx + 1);
254			for (i=0;i<ipx->ipx_tc;i++,nbnet++)
255				if(ipx_neteqnn(ia->ia_addr.sipx_addr.x_net,
256							*nbnet))
257					goto skip_this;
258
259			/*
260			 * Insert the net address of the dest net and
261			 * calculate the new checksum if needed.
262			 */
263			ifp = ia->ia_ifa.ifa_ifp;
264			dst.sipx_addr.x_net = ia->ia_addr.sipx_addr.x_net;
265			ipx->ipx_dna.x_net = dst.sipx_addr.x_net;
266			if(ipx->ipx_sum != 0xffff)
267				ipx->ipx_sum = ipx_cksum(m, ntohs(ipx->ipx_len));
268
269			m1 = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
270			if(m1) {
271				error = (*ifp->if_output)(ifp, m1,
272					(struct sockaddr *)&dst, NULL);
273				/* XXX ipxstat.ipxs_localout++; */
274			}
275skip_this: ;
276		}
277
278bad:
279	m_freem(m);
280	return (error);
281}
282