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