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