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