Kernel should return error on illegal socket option requests.
[unix-history] / usr / src / sys / netns / idp_usrreq.c
CommitLineData
8ae0e4b4 1/*
f2412db0 2 * Copyright (c) 1984,1985 Regents of the University of California.
8ae0e4b4
KM
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
41df24f9 6 * @(#)idp_usrreq.c 6.11 (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;
dac1d492 52 if (ns_netof(idp->idp_sna)==0 && ifp) {
d2ec0713
KS
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 109
dac1d492 110int noIdpRoute;
b1fca4bf
KS
111idp_output(nsp, m0)
112 struct nspcb *nsp;
113 struct mbuf *m0;
114{
115 register struct mbuf *m;
116 register struct idp *idp;
117 register struct socket *so;
118 register int len = 0;
119 register struct route *ro;
120 struct mbuf *mprev;
121 extern int idpcksum;
122
123 /*
124 * Calculate data length.
125 */
126 for (m = m0; m; m = m->m_next) {
127 mprev = m;
128 len += m->m_len;
129 }
130 /*
131 * Make sure packet is actually of even length.
132 */
133
134 if (len & 1) {
135 m = mprev;
136 if (m->m_len + m->m_off < MMAXOFF) {
137 m->m_len++;
138 } else {
139 struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);
140
14bdc762
KS
141 if (m1 == 0) {
142 m_freem(m0);
143 return (ENOBUFS);
144 }
b1fca4bf
KS
145 m1->m_len = 1;
146 m1->m_off = MMAXOFF - 1;
147 * mtod(m1, char *) = 0;
148 m->m_next = m1;
149 }
150 }
151
152 /*
153 * Fill in mbuf with extended IDP header
154 * and addresses and length put into network format.
155 */
156 if (nsp->nsp_flags & NSP_RAWOUT) {
157 m = m0;
158 idp = mtod(m, struct idp *);
159 } else {
160 m = m_get(M_DONTWAIT, MT_HEADER);
161 if (m == 0) {
162 m_freem(m0);
163 return (ENOBUFS);
164 }
165 m->m_off = MMAXOFF - sizeof (struct idp);
166 m->m_len = sizeof (struct idp);
167 m->m_next = m0;
168 idp = mtod(m, struct idp *);
169 idp->idp_tc = 0;
170 idp->idp_pt = nsp->nsp_dpt;
171 idp->idp_sna = nsp->nsp_laddr;
172 idp->idp_dna = nsp->nsp_faddr;
173 len += sizeof (struct idp);
174 }
175
176 idp->idp_len = htons((u_short)len);
177
178 if (idpcksum) {
179 idp->idp_sum = 0;
180 len = ((len - 1) | 1) + 1;
181 idp->idp_sum = ns_cksum(m, len);
182 } else
183 idp->idp_sum = 0xffff;
184
185 /*
186 * Output datagram.
187 */
188 so = nsp->nsp_socket;
189 if (so->so_options & SO_DONTROUTE)
190 return (ns_output(m, (struct route *)0,
191 (so->so_options & SO_BROADCAST) | NS_ROUTETOIF));
192 /*
193 * Use cached route for previous datagram if
dac1d492
KS
194 * possible. If the previous net was the same
195 * and the interface was a broadcast medium, or
196 * if the previous destination was identical,
197 * then we are ok.
b1fca4bf
KS
198 *
199 * NB: We don't handle broadcasts because that
200 * would require 3 subroutine calls.
201 */
202 ro = &nsp->nsp_route;
dac1d492
KS
203#ifdef ancient_history
204 /*
205 * I think that this will all be handled in ns_pcbconnect!
206 */
207 if (ro->ro_rt) {
208 if(ns_neteq(nsp->nsp_lastdst, idp->idp_dna)) {
209 /*
210 * This assumes we have no GH type routes
211 */
212 if (ro->ro_rt->rt_flags & RTF_HOST) {
213 if (!ns_hosteq(nsp->nsp_lastdst, idp->idp_dna))
214 goto re_route;
215
216 }
217 if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) {
218 register struct ns_addr *dst =
219 &satons_addr(ro->ro_dst);
220 dst->x_host = idp->idp_dna.x_host;
221 }
222 /*
223 * Otherwise, we go through the same gateway
224 * and dst is already set up.
225 */
226 } else {
227 re_route:
228 RTFREE(ro->ro_rt);
229 ro->ro_rt = (struct rtentry *)0;
230 }
b1fca4bf 231 }
dac1d492
KS
232 nsp->nsp_lastdst = idp->idp_dna;
233#endif ancient_history
234 if (noIdpRoute) ro = 0;
b1fca4bf
KS
235 return (ns_output(m, ro, so->so_options & SO_BROADCAST));
236}
f97be0c9 237/* ARGSUSED */
b1fca4bf
KS
238idp_ctloutput(req, so, level, name, value)
239 int req, level;
240 struct socket *so;
241 int name;
242 struct mbuf **value;
243{
244 register struct mbuf *m;
245 struct nspcb *nsp = sotonspcb(so);
246 int mask, error = 0;
2b169881 247 extern long ns_pexseq;
b1fca4bf 248
f72426ee
KS
249 if (nsp == NULL)
250 return (EINVAL);
b1fca4bf
KS
251
252 switch (req) {
f72426ee 253
b1fca4bf 254 case PRCO_GETOPT:
f72426ee
KS
255 if (value==NULL)
256 return (EINVAL);
b1fca4bf 257 m = m_get(M_DONTWAIT, MT_DATA);
f72426ee
KS
258 if (m==NULL)
259 return (ENOBUFS);
b1fca4bf 260 switch (name) {
f72426ee 261
19d8bb77
KS
262 case SO_ALL_PACKETS:
263 mask = NSP_ALL_PACKETS;
264 goto get_flags;
265
b1fca4bf
KS
266 case SO_HEADERS_ON_INPUT:
267 mask = NSP_RAWIN;
268 goto get_flags;
f72426ee 269
b1fca4bf
KS
270 case SO_HEADERS_ON_OUTPUT:
271 mask = NSP_RAWOUT;
272 get_flags:
273 m->m_len = sizeof(short);
274 m->m_off = MMAXOFF - sizeof(short);
275 *mtod(m, short *) = nsp->nsp_flags & mask;
276 break;
f72426ee 277
b1fca4bf
KS
278 case SO_DEFAULT_HEADERS:
279 m->m_len = sizeof(struct idp);
280 m->m_off = MMAXOFF - sizeof(struct idp);
281 {
282 register struct idp *idp = mtod(m, struct idp *);
283 idp->idp_len = 0;
284 idp->idp_sum = 0;
285 idp->idp_tc = 0;
286 idp->idp_pt = nsp->nsp_dpt;
287 idp->idp_dna = nsp->nsp_faddr;
288 idp->idp_sna = nsp->nsp_laddr;
289 }
2b169881
KS
290 break;
291
292 case SO_SEQNO:
293 m->m_len = sizeof(long);
294 m->m_off = MMAXOFF - sizeof(long);
295 *mtod(m, long *) = ns_pexseq++;
f2412db0
KS
296 break;
297
298 default:
299 error = EINVAL;
b1fca4bf
KS
300 }
301 *value = m;
302 break;
f72426ee 303
b1fca4bf
KS
304 case PRCO_SETOPT:
305 switch (name) {
f97be0c9 306 int *ok;
b1fca4bf 307
19d8bb77
KS
308 case SO_ALL_PACKETS:
309 mask = NSP_ALL_PACKETS;
310 goto set_head;
311
b1fca4bf
KS
312 case SO_HEADERS_ON_INPUT:
313 mask = NSP_RAWIN;
314 goto set_head;
f72426ee 315
b1fca4bf
KS
316 case SO_HEADERS_ON_OUTPUT:
317 mask = NSP_RAWOUT;
318 set_head:
319 if (value && *value) {
320 ok = mtod(*value, int *);
321 if (*ok)
322 nsp->nsp_flags |= mask;
323 else
324 nsp->nsp_flags &= ~mask;
325 } else error = EINVAL;
326 break;
f72426ee 327
b1fca4bf
KS
328 case SO_DEFAULT_HEADERS:
329 {
330 register struct idp *idp
331 = mtod(*value, struct idp *);
332 nsp->nsp_dpt = idp->idp_pt;
333 }
b1fca4bf 334 break;
f2412db0 335#ifdef NSIP
f72426ee 336
b1fca4bf
KS
337 case SO_NSIP_ROUTE:
338 error = nsip_route(*value);
f2412db0 339 break;
b1fca4bf 340#endif NSIP
f2412db0
KS
341 default:
342 error = EINVAL;
b1fca4bf
KS
343 }
344 if (value && *value)
345 m_freem(*value);
346 break;
347 }
f72426ee 348 return (error);
b1fca4bf
KS
349}
350
351/*ARGSUSED*/
352idp_usrreq(so, req, m, nam, rights)
353 struct socket *so;
354 int req;
355 struct mbuf *m, *nam, *rights;
356{
357 struct nspcb *nsp = sotonspcb(so);
358 int error = 0;
359
360 if (req == PRU_CONTROL)
361 return (ns_control(so, (int)m, (caddr_t)nam,
362 (struct ifnet *)rights));
363 if (rights && rights->m_len) {
364 error = EINVAL;
365 goto release;
366 }
367 if (nsp == NULL && req != PRU_ATTACH) {
368 error = EINVAL;
369 goto release;
370 }
371 switch (req) {
372
373 case PRU_ATTACH:
374 if (nsp != NULL) {
375 error = EINVAL;
376 break;
377 }
378 error = ns_pcballoc(so, &nspcb);
379 if (error)
380 break;
381 error = soreserve(so, 2048, 2048);
382 if (error)
383 break;
384 break;
385
386 case PRU_DETACH:
387 if (nsp == NULL) {
388 error = ENOTCONN;
389 break;
390 }
391 ns_pcbdetach(nsp);
392 break;
393
394 case PRU_BIND:
395 error = ns_pcbbind(nsp, nam);
396 break;
397
398 case PRU_LISTEN:
399 error = EOPNOTSUPP;
400 break;
401
402 case PRU_CONNECT:
403 if (!ns_nullhost(nsp->nsp_faddr)) {
404 error = EISCONN;
405 break;
406 }
407 error = ns_pcbconnect(nsp, nam);
408 if (error == 0)
409 soisconnected(so);
410 break;
411
412 case PRU_CONNECT2:
413 error = EOPNOTSUPP;
414 break;
415
416 case PRU_ACCEPT:
417 error = EOPNOTSUPP;
418 break;
419
420 case PRU_DISCONNECT:
421 if (ns_nullhost(nsp->nsp_faddr)) {
422 error = ENOTCONN;
423 break;
424 }
425 ns_pcbdisconnect(nsp);
426 soisdisconnected(so);
427 break;
428
429 case PRU_SHUTDOWN:
430 socantsendmore(so);
431 break;
432
433 case PRU_SEND:
434 {
435 struct ns_addr laddr;
436 int s;
437
438 if (nam) {
439 laddr = nsp->nsp_laddr;
440 if (!ns_nullhost(nsp->nsp_faddr)) {
441 error = EISCONN;
442 break;
443 }
444 /*
445 * Must block input while temporarily connected.
446 */
447 s = splnet();
448 error = ns_pcbconnect(nsp, nam);
449 if (error) {
450 splx(s);
451 break;
452 }
453 } else {
454 if (ns_nullhost(nsp->nsp_faddr)) {
455 error = ENOTCONN;
456 break;
457 }
458 }
459 error = idp_output(nsp, m);
460 m = NULL;
461 if (nam) {
462 ns_pcbdisconnect(nsp);
463 splx(s);
464 nsp->nsp_laddr.x_host = laddr.x_host;
465 nsp->nsp_laddr.x_port = laddr.x_port;
466 }
467 }
468 break;
469
470 case PRU_ABORT:
471 ns_pcbdetach(nsp);
472 sofree(so);
473 soisdisconnected(so);
474 break;
475
476 case PRU_SOCKADDR:
477 ns_setsockaddr(nsp, nam);
478 break;
479
480 case PRU_PEERADDR:
481 ns_setpeeraddr(nsp, nam);
482 break;
483
484 case PRU_SENSE:
485 /*
486 * stat: don't bother with a blocksize.
487 */
488 return (0);
489
490 case PRU_SENDOOB:
491 case PRU_FASTTIMO:
492 case PRU_SLOWTIMO:
493 case PRU_PROTORCV:
494 case PRU_PROTOSEND:
495 error = EOPNOTSUPP;
496 break;
497
498 case PRU_CONTROL:
499 case PRU_RCVD:
500 case PRU_RCVOOB:
501 return (EOPNOTSUPP); /* do not free mbuf's */
502
503 default:
504 panic("idp_usrreq");
505 }
506release:
507 if (m != NULL)
508 m_freem(m);
509 return (error);
510}
511/*ARGSUSED*/
512idp_raw_usrreq(so, req, m, nam, rights)
513 struct socket *so;
514 int req;
515 struct mbuf *m, *nam, *rights;
516{
517 int error = 0;
518 struct nspcb *nsp = sotonspcb(so);
519 extern struct nspcb nsrawpcb;
520
521 switch (req) {
522
523 case PRU_ATTACH:
524
14bdc762 525 if (!suser() || (nsp != NULL)) {
b1fca4bf
KS
526 error = EINVAL;
527 break;
528 }
529 error = ns_pcballoc(so, &nsrawpcb);
530 if (error)
531 break;
532 error = soreserve(so, 2048, 2048);
533 if (error)
534 break;
535 nsp = sotonspcb(so);
536 nsp->nsp_faddr.x_host = ns_broadhost;
537 nsp->nsp_flags = NSP_RAWIN | NSP_RAWOUT;
538 break;
539 default:
540 error = idp_usrreq(so, req, m, nam, rights);
541 }
f72426ee 542 return (error);
b1fca4bf
KS
543}
544