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