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