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