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$
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 = 0;
148 register struct route *ro;
149 struct mbuf *mprev;
150 extern int idpcksum;
151
152 /*
153 * Calculate data length.
154 */
155 for (m = m0; m; m = m->m_next) {
156 mprev = m;
157 len += m->m_len;
158 }
159 /*
160 * Make sure packet is actually of even length.
161 */
162
163 if (len & 1) {
164 m = mprev;
165 if ((m->m_flags & M_EXT) == 0 &&
166 (m->m_len + m->m_data < &m->m_dat[MLEN])) {
167 m->m_len++;
168 } else {
169 struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);
170
171 if (m1 == 0) {
172 m_freem(m0);
173 return (ENOBUFS);
174 }
175 m1->m_len = 1;
176 * mtod(m1, char *) = 0;
177 m->m_next = m1;
178 }
179 m0->m_pkthdr.len++;
180 }
181
182 /*
183 * Fill in mbuf with extended IDP header
184 * and addresses and length put into network format.
185 */
186 m = m0;
187 if (nsp->nsp_flags & NSP_RAWOUT) {
188 idp = mtod(m, struct idp *);
189 } else {
190 M_PREPEND(m, sizeof (struct idp), M_DONTWAIT);
191 if (m == 0)
192 return (ENOBUFS);
193 idp = mtod(m, struct idp *);
194 idp->idp_tc = 0;
195 idp->idp_pt = nsp->nsp_dpt;
196 idp->idp_sna = nsp->nsp_laddr;
197 idp->idp_dna = nsp->nsp_faddr;
198 len += sizeof (struct idp);
199 }
200
201 idp->idp_len = htons((u_short)len);
202
203 if (idpcksum) {
204 idp->idp_sum = 0;
205 len = ((len - 1) | 1) + 1;
206 idp->idp_sum = ns_cksum(m, len);
207 } else
208 idp->idp_sum = 0xffff;
209
210 /*
211 * Output datagram.
212 */
213 so = nsp->nsp_socket;
214 if (so->so_options & SO_DONTROUTE)
215 return (ns_output(m, (struct route *)0,
216 (so->so_options & SO_BROADCAST) | NS_ROUTETOIF));
217 /*
218 * Use cached route for previous datagram if
219 * possible. If the previous net was the same
220 * and the interface was a broadcast medium, or
221 * if the previous destination was identical,
222 * then we are ok.
223 *
224 * NB: We don't handle broadcasts because that
225 * would require 3 subroutine calls.
226 */
227 ro = &nsp->nsp_route;
228 #ifdef ancient_history
229 /*
230 * I think that this will all be handled in ns_pcbconnect!
231 */
232 if (ro->ro_rt) {
233 if(ns_neteq(nsp->nsp_lastdst, idp->idp_dna)) {
234 /*
235 * This assumes we have no GH type routes
236 */
237 if (ro->ro_rt->rt_flags & RTF_HOST) {
238 if (!ns_hosteq(nsp->nsp_lastdst, idp->idp_dna))
239 goto re_route;
240
241 }
242 if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) {
243 register struct ns_addr *dst =
244 &satons_addr(ro->ro_dst);
245 dst->x_host = idp->idp_dna.x_host;
246 }
247 /*
248 * Otherwise, we go through the same gateway
249 * and dst is already set up.
250 */
251 } else {
252 re_route:
253 RTFREE(ro->ro_rt);
254 ro->ro_rt = (struct rtentry *)0;
255 }
256 }
257 nsp->nsp_lastdst = idp->idp_dna;
258 #endif /* ancient_history */
259 if (noIdpRoute) ro = 0;
260 return (ns_output(m, ro, so->so_options & SO_BROADCAST));
261 }
262 /* ARGSUSED */
263 idp_ctloutput(req, so, level, name, value)
264 int req, level;
265 struct socket *so;
266 int name;
267 struct mbuf **value;
268 {
269 register struct mbuf *m;
270 struct nspcb *nsp = sotonspcb(so);
271 int mask, error = 0;
272 extern long ns_pexseq;
273
274 if (nsp == 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 = NSP_ALL_PACKETS;
289 goto get_flags;
290
291 case SO_HEADERS_ON_INPUT:
292 mask = NSP_RAWIN;
293 goto get_flags;
294
295 case SO_HEADERS_ON_OUTPUT:
296 mask = NSP_RAWOUT;
297 get_flags:
298 m->m_len = sizeof(short);
299 *mtod(m, short *) = nsp->nsp_flags & mask;
300 break;
301
302 case SO_DEFAULT_HEADERS:
303 m->m_len = sizeof(struct idp);
304 {
305 register struct idp *idp = mtod(m, struct idp *);
306 idp->idp_len = 0;
307 idp->idp_sum = 0;
308 idp->idp_tc = 0;
309 idp->idp_pt = nsp->nsp_dpt;
310 idp->idp_dna = nsp->nsp_faddr;
311 idp->idp_sna = nsp->nsp_laddr;
312 }
313 break;
314
315 case SO_SEQNO:
316 m->m_len = sizeof(long);
317 *mtod(m, long *) = ns_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 = NSP_ALL_PACKETS;
332 goto set_head;
333
334 case SO_HEADERS_ON_INPUT:
335 mask = NSP_RAWIN;
336 goto set_head;
337
338 case SO_HEADERS_ON_OUTPUT:
339 mask = NSP_RAWOUT;
340 set_head:
341 if (value && *value) {
342 ok = mtod(*value, int *);
343 if (*ok)
344 nsp->nsp_flags |= mask;
345 else
346 nsp->nsp_flags &= ~mask;
347 } else error = EINVAL;
348 break;
349
350 case SO_DEFAULT_HEADERS:
351 {
352 register struct idp *idp
353 = mtod(*value, struct idp *);
354 nsp->nsp_dpt = idp->idp_pt;
355 }
356 break;
357 #ifdef NSIP
358
359 case SO_NSIP_ROUTE:
360 error = nsip_route(*value);
361 break;
362 #endif /* NSIP */
363 default:
364 error = EINVAL;
365 }
366 if (value && *value)
367 m_freem(*value);
368 break;
369 }
370 return (error);
371 }
372
373 /*ARGSUSED*/
374 idp_usrreq(so, req, m, nam, control)
375 struct socket *so;
376 int req;
377 struct mbuf *m, *nam, *control;
378 {
379 struct nspcb *nsp = sotonspcb(so);
380 int error = 0;
381
382 if (req == PRU_CONTROL)
383 return (ns_control(so, (int)m, (caddr_t)nam,
384 (struct ifnet *)control));
385 if (control && control->m_len) {
386 error = EINVAL;
387 goto release;
388 }
389 if (nsp == NULL && req != PRU_ATTACH) {
390 error = EINVAL;
391 goto release;
392 }
393 switch (req) {
394
395 case PRU_ATTACH:
396 if (nsp != NULL) {
397 error = EINVAL;
398 break;
399 }
400 error = ns_pcballoc(so, &nspcb);
401 if (error)
402 break;
403 error = soreserve(so, (u_long) 2048, (u_long) 2048);
404 if (error)
405 break;
406 break;
407
408 case PRU_DETACH:
409 if (nsp == NULL) {
410 error = ENOTCONN;
411 break;
412 }
413 ns_pcbdetach(nsp);
414 break;
415
416 case PRU_BIND:
417 error = ns_pcbbind(nsp, nam);
418 break;
419
420 case PRU_LISTEN:
421 error = EOPNOTSUPP;
422 break;
423
424 case PRU_CONNECT:
425 if (!ns_nullhost(nsp->nsp_faddr)) {
426 error = EISCONN;
427 break;
428 }
429 error = ns_pcbconnect(nsp, nam);
430 if (error == 0)
431 soisconnected(so);
432 break;
433
434 case PRU_CONNECT2:
435 error = EOPNOTSUPP;
436 break;
437
438 case PRU_ACCEPT:
439 error = EOPNOTSUPP;
440 break;
441
442 case PRU_DISCONNECT:
443 if (ns_nullhost(nsp->nsp_faddr)) {
444 error = ENOTCONN;
445 break;
446 }
447 ns_pcbdisconnect(nsp);
448 soisdisconnected(so);
449 break;
450
451 case PRU_SHUTDOWN:
452 socantsendmore(so);
453 break;
454
455 case PRU_SEND:
456 {
457 struct ns_addr laddr;
458 int s;
459
460 if (nam) {
461 laddr = nsp->nsp_laddr;
462 if (!ns_nullhost(nsp->nsp_faddr)) {
463 error = EISCONN;
464 break;
465 }
466 /*
467 * Must block input while temporarily connected.
468 */
469 s = splnet();
470 error = ns_pcbconnect(nsp, nam);
471 if (error) {
472 splx(s);
473 break;
474 }
475 } else {
476 if (ns_nullhost(nsp->nsp_faddr)) {
477 error = ENOTCONN;
478 break;
479 }
480 }
481 error = idp_output(nsp, m);
482 m = NULL;
483 if (nam) {
484 ns_pcbdisconnect(nsp);
485 splx(s);
486 nsp->nsp_laddr.x_host = laddr.x_host;
487 nsp->nsp_laddr.x_port = laddr.x_port;
488 }
489 }
490 break;
491
492 case PRU_ABORT:
493 ns_pcbdetach(nsp);
494 sofree(so);
495 soisdisconnected(so);
496 break;
497
498 case PRU_SOCKADDR:
499 ns_setsockaddr(nsp, nam);
500 break;
501
502 case PRU_PEERADDR:
503 ns_setpeeraddr(nsp, nam);
504 break;
505
506 case PRU_SENSE:
507 /*
508 * stat: don't bother with a blocksize.
509 */
510 return (0);
511
512 case PRU_SENDOOB:
513 case PRU_FASTTIMO:
514 case PRU_SLOWTIMO:
515 case PRU_PROTORCV:
516 case PRU_PROTOSEND:
517 error = EOPNOTSUPP;
518 break;
519
520 case PRU_CONTROL:
521 case PRU_RCVD:
522 case PRU_RCVOOB:
523 return (EOPNOTSUPP); /* do not free mbuf's */
524
525 default:
526 panic("idp_usrreq");
527 }
528 release:
529 if (control != NULL)
530 m_freem(control);
531 if (m != NULL)
532 m_freem(m);
533 return (error);
534 }
535 /*ARGSUSED*/
536 idp_raw_usrreq(so, req, m, nam, control)
537 struct socket *so;
538 int req;
539 struct mbuf *m, *nam, *control;
540 {
541 int error = 0;
542 struct nspcb *nsp = sotonspcb(so);
543 extern struct nspcb nsrawpcb;
544
545 switch (req) {
546
547 case PRU_ATTACH:
548
549 if (!(so->so_state & SS_PRIV) || (nsp != NULL)) {
550 error = EINVAL;
551 break;
552 }
553 error = ns_pcballoc(so, &nsrawpcb);
554 if (error)
555 break;
556 error = soreserve(so, (u_long) 2048, (u_long) 2048);
557 if (error)
558 break;
559 nsp = sotonspcb(so);
560 nsp->nsp_faddr.x_host = ns_broadhost;
561 nsp->nsp_flags = NSP_RAWIN | NSP_RAWOUT;
562 break;
563 default:
564 error = idp_usrreq(so, req, m, nam, control);
565 }
566 return (error);
567 }
568
Cache object: ff623f4d3d32f333b30272378610472e
|