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