1: /*
2: * Copyright (c) 1984, 1985, 1986 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: *
6: * @(#)idp_usrreq.c 7.1 (Berkeley) 6/5/86
7: */
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 "ns_if.h"
25: #include "idp.h"
26: #include "idp_var.h"
27: #include "ns_error.h"
28:
29: /*
30: * IDP protocol implementation.
31: */
32:
33: struct sockaddr_ns idp_ns = { AF_NS };
34:
35: /*
36: * This may also be called for raw listeners.
37: */
38: idp_input(m, nsp, ifp)
39: struct mbuf *m;
40: register struct nspcb *nsp;
41: struct ifnet *ifp;
42: {
43: register struct idp *idp = mtod(m, struct idp *);
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 *ia;
54:
55: for (ia = ifp->if_addrlist; ia; ia = ia->ifa_next) {
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: }
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;
73: bad:
74: m_freem(m);
75: }
76:
77: idp_abort(nsp)
78: struct nspcb *nsp;
79: {
80: struct socket *so = nsp->nsp_socket;
81:
82: ns_pcbdisconnect(nsp);
83: soisdisconnected(so);
84: }
85: /*
86: * Drop connection, reporting
87: * the specified error.
88: */
89: struct nspcb *
90: idp_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: }
109:
110: int noIdpRoute;
111: idp_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:
141: if (m1 == 0) {
142: m_freem(m0);
143: return (ENOBUFS);
144: }
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) - 2;
166: /* adjust to start on longword bdry
167: for NSIP on gould */
168: m->m_len = sizeof (struct idp);
169: m->m_next = m0;
170: idp = mtod(m, struct idp *);
171: idp->idp_tc = 0;
172: idp->idp_pt = nsp->nsp_dpt;
173: idp->idp_sna = nsp->nsp_laddr;
174: idp->idp_dna = nsp->nsp_faddr;
175: len += sizeof (struct idp);
176: }
177:
178: idp->idp_len = htons((u_short)len);
179:
180: if (idpcksum) {
181: idp->idp_sum = 0;
182: len = ((len - 1) | 1) + 1;
183: idp->idp_sum = ns_cksum(m, len);
184: } else
185: idp->idp_sum = 0xffff;
186:
187: /*
188: * Output datagram.
189: */
190: so = nsp->nsp_socket;
191: if (so->so_options & SO_DONTROUTE)
192: return (ns_output(m, (struct route *)0,
193: (so->so_options & SO_BROADCAST) | NS_ROUTETOIF));
194: /*
195: * Use cached route for previous datagram if
196: * possible. If the previous net was the same
197: * and the interface was a broadcast medium, or
198: * if the previous destination was identical,
199: * then we are ok.
200: *
201: * NB: We don't handle broadcasts because that
202: * would require 3 subroutine calls.
203: */
204: ro = &nsp->nsp_route;
205: #ifdef ancient_history
206: /*
207: * I think that this will all be handled in ns_pcbconnect!
208: */
209: if (ro->ro_rt) {
210: if(ns_neteq(nsp->nsp_lastdst, idp->idp_dna)) {
211: /*
212: * This assumes we have no GH type routes
213: */
214: if (ro->ro_rt->rt_flags & RTF_HOST) {
215: if (!ns_hosteq(nsp->nsp_lastdst, idp->idp_dna))
216: goto re_route;
217:
218: }
219: if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) {
220: register struct ns_addr *dst =
221: &satons_addr(ro->ro_dst);
222: dst->x_host = idp->idp_dna.x_host;
223: }
224: /*
225: * Otherwise, we go through the same gateway
226: * and dst is already set up.
227: */
228: } else {
229: re_route:
230: RTFREE(ro->ro_rt);
231: ro->ro_rt = (struct rtentry *)0;
232: }
233: }
234: nsp->nsp_lastdst = idp->idp_dna;
235: #endif ancient_history
236: if (noIdpRoute) ro = 0;
237: return (ns_output(m, ro, so->so_options & SO_BROADCAST));
238: }
239: /* ARGSUSED */
240: idp_ctloutput(req, so, level, name, value)
241: int req, level;
242: struct socket *so;
243: int name;
244: struct mbuf **value;
245: {
246: register struct mbuf *m;
247: struct nspcb *nsp = sotonspcb(so);
248: int mask, error = 0;
249: extern long ns_pexseq;
250:
251: if (nsp == NULL)
252: return (EINVAL);
253:
254: switch (req) {
255:
256: case PRCO_GETOPT:
257: if (value==NULL)
258: return (EINVAL);
259: m = m_get(M_DONTWAIT, MT_DATA);
260: if (m==NULL)
261: return (ENOBUFS);
262: switch (name) {
263:
264: case SO_ALL_PACKETS:
265: mask = NSP_ALL_PACKETS;
266: goto get_flags;
267:
268: case :
269: mask = NSP_RAWIN;
270: goto get_flags;
271:
272: case :
273: mask = NSP_RAWOUT;
274: get_flags:
275: m->m_len = sizeof(short);
276: m->m_off = MMAXOFF - sizeof(short);
277: *mtod(m, short *) = nsp->nsp_flags & mask;
278: break;
279:
280: case :
281: m->m_len = sizeof(struct idp);
282: m->m_off = MMAXOFF - sizeof(struct idp);
283: {
284: register struct idp *idp = mtod(m, struct idp *);
285: idp->idp_len = 0;
286: idp->idp_sum = 0;
287: idp->idp_tc = 0;
288: idp->idp_pt = nsp->nsp_dpt;
289: idp->idp_dna = nsp->nsp_faddr;
290: idp->idp_sna = nsp->nsp_laddr;
291: }
292: break;
293:
294: case SO_SEQNO:
295: m->m_len = sizeof(long);
296: m->m_off = MMAXOFF - sizeof(long);
297: *mtod(m, long *) = ns_pexseq++;
298: break;
299:
300: default:
301: error = EINVAL;
302: }
303: *value = m;
304: break;
305:
306: case PRCO_SETOPT:
307: switch (name) {
308: int *ok;
309:
310: case SO_ALL_PACKETS:
311: mask = NSP_ALL_PACKETS;
312: goto set_head;
313:
314: case SO_HEADERS_ON_INPUT:
315: mask = NSP_RAWIN;
316: goto set_head;
317:
318: case SO_HEADERS_ON_OUTPUT:
319: mask = NSP_RAWOUT;
320: set_head:
321: if (value && *value) {
322: ok = mtod(*value, int *);
323: if (*ok)
324: nsp->nsp_flags |= mask;
325: else
326: nsp->nsp_flags &= ~mask;
327: } else error = EINVAL;
328: break;
329:
330: case SO_DEFAULT_HEADERS:
331: {
332: register struct idp *idp
333: = mtod(*value, struct idp *);
334: nsp->nsp_dpt = idp->idp_pt;
335: }
336: break;
337: #ifdef NSIP
338:
339: case SO_NSIP_ROUTE:
340: error = nsip_route(*value);
341: break;
342: #endif NSIP
343: default:
344: error = EINVAL;
345: }
346: if (value && *value)
347: m_freem(*value);
348: break;
349: }
350: return (error);
351: }
352:
353: /*ARGSUSED*/
354: idp_usrreq(so, req, m, nam, rights)
355: struct socket *so;
356: int req;
357: struct mbuf *m, *nam, *rights;
358: {
359: struct nspcb *nsp = sotonspcb(so);
360: int error = 0;
361:
362: if (req == PRU_CONTROL)
363: return (ns_control(so, (int)m, (caddr_t)nam,
364: (struct ifnet *)rights));
365: if (rights && rights->m_len) {
366: error = EINVAL;
367: goto release;
368: }
369: if (nsp == NULL && req != PRU_ATTACH) {
370: error = EINVAL;
371: goto release;
372: }
373: switch (req) {
374:
375: case PRU_ATTACH:
376: if (nsp != NULL) {
377: error = EINVAL;
378: break;
379: }
380: error = ns_pcballoc(so, &nspcb);
381: if (error)
382: break;
383: error = soreserve(so, 2048, 2048);
384: if (error)
385: break;
386: break;
387:
388: case PRU_DETACH:
389: if (nsp == NULL) {
390: error = ENOTCONN;
391: break;
392: }
393: ns_pcbdetach(nsp);
394: break;
395:
396: case PRU_BIND:
397: error = ns_pcbbind(nsp, nam);
398: break;
399:
400: case PRU_LISTEN:
401: error = EOPNOTSUPP;
402: break;
403:
404: case PRU_CONNECT:
405: if (!ns_nullhost(nsp->nsp_faddr)) {
406: error = EISCONN;
407: break;
408: }
409: error = ns_pcbconnect(nsp, nam);
410: if (error == 0)
411: soisconnected(so);
412: break;
413:
414: case PRU_CONNECT2:
415: error = EOPNOTSUPP;
416: break;
417:
418: case PRU_ACCEPT:
419: error = EOPNOTSUPP;
420: break;
421:
422: case PRU_DISCONNECT:
423: if (ns_nullhost(nsp->nsp_faddr)) {
424: error = ENOTCONN;
425: break;
426: }
427: ns_pcbdisconnect(nsp);
428: soisdisconnected(so);
429: break;
430:
431: case PRU_SHUTDOWN:
432: socantsendmore(so);
433: break;
434:
435: case PRU_SEND:
436: {
437: struct ns_addr laddr;
438: int s;
439:
440: if (nam) {
441: laddr = nsp->nsp_laddr;
442: if (!ns_nullhost(nsp->nsp_faddr)) {
443: error = EISCONN;
444: break;
445: }
446: /*
447: * Must block input while temporarily connected.
448: */
449: s = splnet();
450: error = ns_pcbconnect(nsp, nam);
451: if (error) {
452: splx(s);
453: break;
454: }
455: } else {
456: if (ns_nullhost(nsp->nsp_faddr)) {
457: error = ENOTCONN;
458: break;
459: }
460: }
461: error = idp_output(nsp, m);
462: m = NULL;
463: if (nam) {
464: ns_pcbdisconnect(nsp);
465: splx(s);
466: nsp->nsp_laddr.x_host = laddr.x_host;
467: nsp->nsp_laddr.x_port = laddr.x_port;
468: }
469: }
470: break;
471:
472: case PRU_ABORT:
473: ns_pcbdetach(nsp);
474: sofree(so);
475: soisdisconnected(so);
476: break;
477:
478: case PRU_SOCKADDR:
479: ns_setsockaddr(nsp, nam);
480: break;
481:
482: case PRU_PEERADDR:
483: ns_setpeeraddr(nsp, nam);
484: break;
485:
486: case PRU_SENSE:
487: /*
488: * stat: don't bother with a blocksize.
489: */
490: return (0);
491:
492: case PRU_SENDOOB:
493: case PRU_FASTTIMO:
494: case PRU_SLOWTIMO:
495: case PRU_PROTORCV:
496: case PRU_PROTOSEND:
497: error = EOPNOTSUPP;
498: break;
499:
500: case PRU_CONTROL:
501: case PRU_RCVD:
502: case PRU_RCVOOB:
503: return (EOPNOTSUPP); /* do not free mbuf's */
504:
505: default:
506: panic("idp_usrreq");
507: }
508: release:
509: if (m != NULL)
510: m_freem(m);
511: return (error);
512: }
513: /*ARGSUSED*/
514: idp_raw_usrreq(so, req, m, nam, rights)
515: struct socket *so;
516: int req;
517: struct mbuf *m, *nam, *rights;
518: {
519: int error = 0;
520: struct nspcb *nsp = sotonspcb(so);
521: extern struct nspcb nsrawpcb;
522:
523: switch (req) {
524:
525: case PRU_ATTACH:
526:
527: if (!suser() || (nsp != NULL)) {
528: error = EINVAL;
529: break;
530: }
531: error = ns_pcballoc(so, &nsrawpcb);
532: if (error)
533: break;
534: error = soreserve(so, 2048, 2048);
535: if (error)
536: break;
537: nsp = sotonspcb(so);
538: nsp->nsp_faddr.x_host = ns_broadhost;
539: nsp->nsp_flags = NSP_RAWIN | NSP_RAWOUT;
540: break;
541: default:
542: error = idp_usrreq(so, req, m, nam, rights);
543: }
544: return (error);
545: }