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