ipx_usrreq.c revision 11819
1/*
2 * Copyright (c) 1995, Mike Mitchell
3 * Copyright (c) 1984, 1985, 1986, 1987, 1993
4 *	The Regents of the University of California.  All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 *    must display the following acknowledgement:
16 *	This product includes software developed by the University of
17 *	California, Berkeley and its contributors.
18 * 4. Neither the name of the University nor the names of its contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 *	@(#)ipx_usrreq.c
35 */
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/malloc.h>
40#include <sys/mbuf.h>
41#include <sys/protosw.h>
42#include <sys/socket.h>
43#include <sys/socketvar.h>
44#include <sys/errno.h>
45#include <sys/stat.h>
46
47#include <net/if.h>
48#include <net/route.h>
49
50#include <netipx/ipx.h>
51#include <netipx/ipx_pcb.h>
52#include <netipx/ipx_if.h>
53#include <netipx/ipx_var.h>
54#include <netipx/ipx_error.h>
55
56/*
57 * IPX protocol implementation.
58 */
59
60int noipxRoute;
61
62/*
63 *  This may also be called for raw listeners.
64 */
65void
66ipx_input(m, ipxp)
67	struct mbuf *m;
68	register struct ipxpcb *ipxp;
69{
70	register struct ipx *ipx = mtod(m, struct ipx *);
71	struct ifnet *ifp = m->m_pkthdr.rcvif;
72	struct sockaddr_ipx ipx_ipx = { sizeof(ipx_ipx), AF_IPX };
73
74	if (ipxp==0)
75		panic("No ipxpcb");
76	/*
77	 * Construct sockaddr format source address.
78	 * Stuff source address and datagram in user buffer.
79	 */
80	ipx_ipx.sipx_addr = ipx->ipx_sna;
81	if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp) {
82		register struct ifaddr *ifa;
83
84		for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
85			if (ifa->ifa_addr->sa_family == AF_IPX) {
86				ipx_ipx.sipx_addr.x_net =
87					IA_SIPX(ifa)->sipx_addr.x_net;
88				break;
89			}
90		}
91	}
92	ipxp->ipxp_rpt = ipx->ipx_pt;
93	if ( ! (ipxp->ipxp_flags & IPXP_RAWIN) ) {
94		m->m_len -= sizeof (struct ipx);
95		m->m_pkthdr.len -= sizeof (struct ipx);
96		m->m_data += sizeof (struct ipx);
97	}
98	if (sbappendaddr(&ipxp->ipxp_socket->so_rcv, (struct sockaddr *)&ipx_ipx,
99	    m, (struct mbuf *)0) == 0)
100		goto bad;
101	sorwakeup(ipxp->ipxp_socket);
102	return;
103bad:
104	m_freem(m);
105}
106
107void
108ipx_abort(ipxp)
109	struct ipxpcb *ipxp;
110{
111	struct socket *so = ipxp->ipxp_socket;
112
113	ipx_pcbdisconnect(ipxp);
114	soisdisconnected(so);
115}
116/*
117 * Drop connection, reporting
118 * the specified error.
119 */
120/* struct ipxpcb * DELETE THIS */
121void
122ipx_drop(ipxp, errno)
123	register struct ipxpcb *ipxp;
124	int errno;
125{
126	struct socket *so = ipxp->ipxp_socket;
127
128	/*
129	 * someday, in the xerox world
130	 * we will generate error protocol packets
131	 * announcing that the socket has gone away.
132	 */
133	/*if (TCPS_HAVERCVDSYN(tp->t_state)) {
134		tp->t_state = TCPS_CLOSED;
135		(void) tcp_output(tp);
136	}*/
137	so->so_error = errno;
138	ipx_pcbdisconnect(ipxp);
139	soisdisconnected(so);
140}
141
142int
143ipx_output(ipxp, m0)
144	struct ipxpcb *ipxp;
145	struct mbuf *m0;
146{
147	register struct mbuf *m;
148	register struct ipx *ipx;
149	register struct socket *so;
150	register int len = 0;
151	register struct route *ro;
152	struct mbuf *mprev = NULL;
153
154	/*
155	 * Calculate data length.
156	 */
157	for (m = m0; m; m = m->m_next) {
158		mprev = m;
159		len += m->m_len;
160	}
161	/*
162	 * Make sure packet is actually of even length.
163	 */
164
165	if (len & 1) {
166		m = mprev;
167		if ((m->m_flags & M_EXT) == 0 &&
168			(m->m_len + m->m_data < &m->m_dat[MLEN])) {
169			m->m_len++;
170		} else {
171			struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);
172
173			if (m1 == 0) {
174				m_freem(m0);
175				return (ENOBUFS);
176			}
177			m1->m_len = 1;
178			* mtod(m1, char *) = 0;
179			m->m_next = m1;
180		}
181		m0->m_pkthdr.len++;
182	}
183
184	/*
185	 * Fill in mbuf with extended IPX header
186	 * and addresses and length put into network format.
187	 */
188	m = m0;
189	if (ipxp->ipxp_flags & IPXP_RAWOUT) {
190		ipx = mtod(m, struct ipx *);
191	} else {
192		M_PREPEND(m, sizeof (struct ipx), M_DONTWAIT);
193		if (m == 0)
194			return (ENOBUFS);
195		ipx = mtod(m, struct ipx *);
196		ipx->ipx_tc = 0;
197		ipx->ipx_pt = ipxp->ipxp_dpt;
198		ipx->ipx_sna = ipxp->ipxp_laddr;
199		ipx->ipx_dna = ipxp->ipxp_faddr;
200		len += sizeof (struct ipx);
201	}
202
203	ipx->ipx_len = htons((u_short)len);
204
205	if (ipxcksum) {
206		ipx->ipx_sum = 0;
207		len = ((len - 1) | 1) + 1;
208		ipx->ipx_sum = ipx_cksum(m, len);
209	} else
210		ipx->ipx_sum = 0xffff;
211
212	/*
213	 * Output datagram.
214	 */
215	so = ipxp->ipxp_socket;
216	if (so->so_options & SO_DONTROUTE)
217		return (ipx_outputfl(m, (struct route *)0,
218		    (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF));
219	/*
220	 * Use cached route for previous datagram if
221	 * possible.  If the previous net was the same
222	 * and the interface was a broadcast medium, or
223	 * if the previous destination was identical,
224	 * then we are ok.
225	 *
226	 * NB: We don't handle broadcasts because that
227	 *     would require 3 subroutine calls.
228	 */
229	ro = &ipxp->ipxp_route;
230#ifdef ancient_history
231	/*
232	 * I think that this will all be handled in ipx_pcbconnect!
233	 */
234	if (ro->ro_rt) {
235		if(ipx_neteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) {
236			/*
237			 * This assumes we have no GH type routes
238			 */
239			if (ro->ro_rt->rt_flags & RTF_HOST) {
240				if (!ipx_hosteq(ipxp->ipxp_lastdst, ipx->ipx_dna))
241					goto re_route;
242
243			}
244			if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) {
245				register struct ipx_addr *dst =
246						&satoipx_addr(ro->ro_dst);
247				dst->x_host = ipx->ipx_dna.x_host;
248			}
249			/*
250			 * Otherwise, we go through the same gateway
251			 * and dst is already set up.
252			 */
253		} else {
254		re_route:
255			RTFREE(ro->ro_rt);
256			ro->ro_rt = (struct rtentry *)0;
257		}
258	}
259	ipxp->ipxp_lastdst = ipx->ipx_dna;
260#endif /* ancient_history */
261	if (noipxRoute) ro = 0;
262	return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST));
263}
264/* ARGSUSED */
265int
266ipx_ctloutput(req, so, level, name, value)
267	int req, level;
268	struct socket *so;
269	int name;
270	struct mbuf **value;
271{
272	register struct mbuf *m;
273	struct ipxpcb *ipxp = sotoipxpcb(so);
274	int mask, error = 0;
275	/*extern long ipx_pexseq;*/ /*XXX*//*JRE*/
276
277	if (ipxp == NULL)
278		return (EINVAL);
279
280	switch (req) {
281
282	case PRCO_GETOPT:
283		if (value==NULL)
284			return (EINVAL);
285		m = m_get(M_DONTWAIT, MT_DATA);
286		if (m==NULL)
287			return (ENOBUFS);
288		switch (name) {
289
290		case SO_ALL_PACKETS:
291			mask = IPXP_ALL_PACKETS;
292			goto get_flags;
293
294		case SO_HEADERS_ON_INPUT:
295			mask = IPXP_RAWIN;
296			goto get_flags;
297
298		case SO_HEADERS_ON_OUTPUT:
299			mask = IPXP_RAWOUT;
300		get_flags:
301			m->m_len = sizeof(short);
302			*mtod(m, short *) = ipxp->ipxp_flags & mask;
303			break;
304
305		case SO_DEFAULT_HEADERS:
306			m->m_len = sizeof(struct ipx);
307			{
308				register struct ipx *ipx = mtod(m, struct ipx *);
309				ipx->ipx_len = 0;
310				ipx->ipx_sum = 0;
311				ipx->ipx_tc = 0;
312				ipx->ipx_pt = ipxp->ipxp_dpt;
313				ipx->ipx_dna = ipxp->ipxp_faddr;
314				ipx->ipx_sna = ipxp->ipxp_laddr;
315			}
316			break;
317
318		case SO_SEQNO:
319			m->m_len = sizeof(long);
320			*mtod(m, long *) = ipx_pexseq++;
321			break;
322
323		default:
324			error = EINVAL;
325		}
326		*value = m;
327		break;
328
329	case PRCO_SETOPT:
330		switch (name) {
331			int *ok;
332
333		case SO_ALL_PACKETS:
334			mask = IPXP_ALL_PACKETS;
335			goto set_head;
336
337		case SO_HEADERS_ON_INPUT:
338			mask = IPXP_RAWIN;
339			goto set_head;
340
341		case SO_HEADERS_ON_OUTPUT:
342			mask = IPXP_RAWOUT;
343		set_head:
344			if (value && *value) {
345				ok = mtod(*value, int *);
346				if (*ok)
347					ipxp->ipxp_flags |= mask;
348				else
349					ipxp->ipxp_flags &= ~mask;
350			} else error = EINVAL;
351			break;
352
353		case SO_DEFAULT_HEADERS:
354			{
355				register struct ipx *ipx
356				    = mtod(*value, struct ipx *);
357				ipxp->ipxp_dpt = ipx->ipx_pt;
358			}
359			break;
360#ifdef IPXIP
361		case SO_IPXIP_ROUTE:
362			error = ipxip_route(*value);
363			break;
364#endif /* IPXIP */
365#ifdef IPXTUNNEL
366		case SO_IPXTUNNEL_ROUTE
367			error = ipxtun_route(*value);
368			break;
369#endif
370		default:
371			error = EINVAL;
372		}
373		if (value && *value)
374			m_freem(*value);
375		break;
376	}
377	return (error);
378}
379
380/*ARGSUSED*/
381int
382ipx_usrreq(so, req, m, nam, control)
383	struct socket *so;
384	int req;
385	struct mbuf *m, *nam, *control;
386{
387	struct ipxpcb *ipxp = sotoipxpcb(so);
388	int error = 0;
389
390	if (req == PRU_CONTROL)
391                return (ipx_control(so, (int)m, (caddr_t)nam,
392			(struct ifnet *)control));
393	if (control && control->m_len) {
394		error = EINVAL;
395		goto release;
396	}
397	if (ipxp == NULL && req != PRU_ATTACH) {
398		error = EINVAL;
399		goto release;
400	}
401	switch (req) {
402
403	case PRU_ATTACH:
404		if (ipxp != NULL) {
405			error = EINVAL;
406			break;
407		}
408		error = ipx_pcballoc(so, &ipxpcb);
409		if (error)
410			break;
411		error = soreserve(so, (u_long) 2048, (u_long) 2048);
412		if (error)
413			break;
414		break;
415
416	case PRU_DETACH:
417		if (ipxp == NULL) {
418			error = ENOTCONN;
419			break;
420		}
421		ipx_pcbdetach(ipxp);
422		break;
423
424	case PRU_BIND:
425		error = ipx_pcbbind(ipxp, nam);
426		break;
427
428	case PRU_LISTEN:
429		error = EOPNOTSUPP;
430		break;
431
432	case PRU_CONNECT:
433		if (!ipx_nullhost(ipxp->ipxp_faddr)) {
434			error = EISCONN;
435			break;
436		}
437		error = ipx_pcbconnect(ipxp, nam);
438		if (error == 0)
439			soisconnected(so);
440		break;
441
442	case PRU_CONNECT2:
443		error = EOPNOTSUPP;
444		break;
445
446	case PRU_ACCEPT:
447		error = EOPNOTSUPP;
448		break;
449
450	case PRU_DISCONNECT:
451		if (ipx_nullhost(ipxp->ipxp_faddr)) {
452			error = ENOTCONN;
453			break;
454		}
455		ipx_pcbdisconnect(ipxp);
456		soisdisconnected(so);
457		break;
458
459	case PRU_SHUTDOWN:
460		socantsendmore(so);
461		break;
462
463	case PRU_SEND:
464	{
465		struct ipx_addr laddr;
466		int s = 0;
467
468		if (nam) {
469			laddr = ipxp->ipxp_laddr;
470			if (!ipx_nullhost(ipxp->ipxp_faddr)) {
471				error = EISCONN;
472				break;
473			}
474			/*
475			 * Must block input while temporarily connected.
476			 */
477			s = splnet();
478			error = ipx_pcbconnect(ipxp, nam);
479			if (error) {
480				splx(s);
481				break;
482			}
483		} else {
484			if (ipx_nullhost(ipxp->ipxp_faddr)) {
485				error = ENOTCONN;
486				break;
487			}
488		}
489		error = ipx_output(ipxp, m);
490		m = NULL;
491		if (nam) {
492			ipx_pcbdisconnect(ipxp);
493			splx(s);
494			ipxp->ipxp_laddr.x_host = laddr.x_host;
495			ipxp->ipxp_laddr.x_port = laddr.x_port;
496		}
497	}
498		break;
499
500	case PRU_ABORT:
501		ipx_pcbdetach(ipxp);
502		sofree(so);
503		soisdisconnected(so);
504		break;
505
506	case PRU_SOCKADDR:
507		ipx_setsockaddr(ipxp, nam);
508		break;
509
510	case PRU_PEERADDR:
511		ipx_setpeeraddr(ipxp, nam);
512		break;
513
514	case PRU_SENSE:
515		/*
516		 * stat: don't bother with a blocksize.
517		 */
518		return (0);
519
520	case PRU_SENDOOB:
521	case PRU_FASTTIMO:
522	case PRU_SLOWTIMO:
523	case PRU_PROTORCV:
524	case PRU_PROTOSEND:
525		error =  EOPNOTSUPP;
526		break;
527
528	case PRU_CONTROL:
529	case PRU_RCVD:
530	case PRU_RCVOOB:
531		return (EOPNOTSUPP);	/* do not free mbuf's */
532
533	default:
534		panic("ipx_usrreq");
535	}
536release:
537	if (control != NULL)
538		m_freem(control);
539	if (m != NULL)
540		m_freem(m);
541	return (error);
542}
543/*ARGSUSED*/
544int
545ipx_raw_usrreq(so, req, m, nam, control)
546	struct socket *so;
547	int req;
548	struct mbuf *m, *nam, *control;
549{
550	int error = 0;
551	struct ipxpcb *ipxp = sotoipxpcb(so);
552	/*extern struct ipxpcb ipxrawpcb;*//*XXX*//*JRE*/
553
554	switch (req) {
555
556	case PRU_ATTACH:
557
558		if (!(so->so_state & SS_PRIV) || (ipxp != NULL)) {
559			error = EINVAL;
560			break;
561		}
562		error = ipx_pcballoc(so, &ipxrawpcb);
563		if (error)
564			break;
565		error = soreserve(so, (u_long) 2048, (u_long) 2048);
566		if (error)
567			break;
568		ipxp = sotoipxpcb(so);
569		ipxp->ipxp_faddr.x_host = ipx_broadhost;
570		ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT;
571		break;
572	default:
573		error = ipx_usrreq(so, req, m, nam, control);
574	}
575	return (error);
576}
577
578