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