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