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