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