|
|
1.1 root 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: * @(#)ns_input.c 7.1 (Berkeley) 6/5/86
7: */
8:
9: #include "param.h"
10: #include "systm.h"
11: #include "mbuf.h"
12: #include "domain.h"
13: #include "protosw.h"
14: #include "socket.h"
15: #include "socketvar.h"
16: #include "errno.h"
17: #include "time.h"
18: #include "kernel.h"
19:
20: #include "../net/if.h"
21: #include "../net/route.h"
22: #include "../net/raw_cb.h"
23:
24: #include "ns.h"
25: #include "ns_if.h"
26: #include "ns_pcb.h"
27: #include "idp.h"
28: #include "idp_var.h"
29: #include "ns_error.h"
30:
31: /*
32: * NS initialization.
33: */
34: union ns_host ns_thishost;
35: union ns_host ns_zerohost;
36: union ns_host ns_broadhost;
37: union ns_net ns_zeronet;
38: union ns_net ns_broadnet;
39:
40: static u_short allones[] = {-1, -1, -1};
41:
42: struct nspcb nspcb;
43: struct nspcb nsrawpcb;
44:
45: struct ifqueue nsintrq;
46: int nsqmaxlen = IFQ_MAXLEN;
47:
48: int idpcksum = 1;
49: long ns_pexseq;
50:
51: ns_init()
52: {
53: extern struct timeval time;
54:
55: ns_broadhost = * (union ns_host *) allones;
56: ns_broadnet = * (union ns_net *) allones;
57: nspcb.nsp_next = nspcb.nsp_prev = &nspcb;
58: nsrawpcb.nsp_next = nsrawpcb.nsp_prev = &nsrawpcb;
59: nsintrq.ifq_maxlen = nsqmaxlen;
60: ns_pexseq = time.tv_usec;
61: }
62:
63: /*
64: * Idp input routine. Pass to next level.
65: */
66: int nsintr_getpck = 0;
67: int nsintr_swtch = 0;
68: nsintr()
69: {
70: register struct idp *idp;
71: register struct mbuf *m;
72: register struct nspcb *nsp;
73: struct ifnet *ifp;
74: struct mbuf *m0;
75: register int i;
76: int len, s, error;
77: char oddpacketp;
78:
79: next:
80: /*
81: * Get next datagram off input queue and get IDP header
82: * in first mbuf.
83: */
84: s = splimp();
85: IF_DEQUEUEIF(&nsintrq, m, ifp);
86: splx(s);
87: nsintr_getpck++;
88: if (m == 0)
89: return;
90: if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct idp)) &&
91: (m = m_pullup(m, sizeof (struct idp))) == 0) {
92: idpstat.idps_toosmall++;
93: goto next;
94: }
95:
96: /*
97: * Give any raw listeners a crack at the packet
98: */
99: for (nsp = nsrawpcb.nsp_next; nsp != &nsrawpcb; nsp = nsp->nsp_next) {
100: struct mbuf *m1 = m_copy(m, 0, (int)M_COPYALL);
101: if (m1) idp_input(m1, nsp, ifp);
102: }
103:
104: idp = mtod(m, struct idp *);
105: len = ntohs(idp->idp_len);
106: if (oddpacketp = len & 1) {
107: len++; /* If this packet is of odd length,
108: preserve garbage byte for checksum */
109: }
110:
111: /*
112: * Check that the amount of data in the buffers
113: * is as at least much as the IDP header would have us expect.
114: * Trim mbufs if longer than we expect.
115: * Drop packet if shorter than we expect.
116: */
117: i = -len;
118: m0 = m;
119: for (;;) {
120: i += m->m_len;
121: if (m->m_next == 0)
122: break;
123: m = m->m_next;
124: }
125: if (i != 0) {
126: if (i < 0) {
127: idpstat.idps_tooshort++;
128: m = m0;
129: goto bad;
130: }
131: if (i <= m->m_len)
132: m->m_len -= i;
133: else
134: m_adj(m0, -i);
135: }
136: m = m0;
137: if (idpcksum && ((i = idp->idp_sum)!=0xffff)) {
138: idp->idp_sum = 0;
139: if (i != (idp->idp_sum = ns_cksum(m,len))) {
140: idpstat.idps_badsum++;
141: idp->idp_sum = i;
142: if (ns_hosteqnh(ns_thishost, idp->idp_dna.x_host))
143: error = NS_ERR_BADSUM;
144: else
145: error = NS_ERR_BADSUM_T;
146: ns_error(m, error, 0);
147: goto next;
148: }
149: }
150: /*
151: * Is this a directed broadcast?
152: */
153: if (ns_hosteqnh(ns_broadhost,idp->idp_dna.x_host)) {
154: if ((!ns_neteq(idp->idp_dna, idp->idp_sna)) &&
155: (!ns_neteqnn(idp->idp_dna.x_net, ns_broadnet)) &&
156: (!ns_neteqnn(idp->idp_sna.x_net, ns_zeronet)) &&
157: (!ns_neteqnn(idp->idp_dna.x_net, ns_zeronet)) ) {
158: /*
159: * Look to see if I need to eat this packet.
160: * Algorithm is to forward all young packets
161: * and prematurely age any packets which will
162: * by physically broadcasted.
163: * Any very old packets eaten without forwarding
164: * would die anyway.
165: *
166: * Suggestion of Bill Nesheim, Cornell U.
167: */
168: if (idp->idp_tc < NS_MAXHOPS) {
169: idp_forward(idp);
170: goto next;
171: }
172: }
173: /*
174: * Is this our packet? If not, forward.
175: */
176: } else if (!ns_hosteqnh(ns_thishost,idp->idp_dna.x_host)) {
177: idp_forward(idp);
178: goto next;
179: }
180: /*
181: * Locate pcb for datagram.
182: */
183: nsp = ns_pcblookup(&idp->idp_sna, idp->idp_dna.x_port, NS_WILDCARD);
184: /*
185: * Switch out to protocol's input routine.
186: */
187: nsintr_swtch++;
188: if (nsp) {
189: if (oddpacketp) {
190: m_adj(m0, -1);
191: }
192: if ((nsp->nsp_flags & NSP_ALL_PACKETS)==0)
193: switch (idp->idp_pt) {
194:
195: case NSPROTO_SPP:
196: spp_input(m, nsp, ifp);
197: goto next;
198:
199: case NSPROTO_ERROR:
200: ns_err_input(m);
201: goto next;
202: }
203: idp_input(m, nsp, ifp);
204: } else {
205: ns_error(m, NS_ERR_NOSOCK, 0);
206: }
207: goto next;
208:
209: bad:
210: m_freem(m);
211: goto next;
212: }
213:
214: u_char nsctlerrmap[PRC_NCMDS] = {
215: ECONNABORTED, ECONNABORTED, 0, 0,
216: 0, 0, EHOSTDOWN, EHOSTUNREACH,
217: ENETUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED,
218: EMSGSIZE, 0, 0, 0,
219: 0, 0, 0, 0
220: };
221:
222: idp_donosocks = 1;
223:
224: idp_ctlinput(cmd, arg)
225: int cmd;
226: caddr_t arg;
227: {
228: struct ns_addr *ns;
229: struct nspcb *nsp;
230: struct ns_errp *errp;
231: int idp_abort();
232: extern struct nspcb *idp_drop();
233: int type;
234:
235: if (cmd < 0 || cmd > PRC_NCMDS)
236: return;
237: if (nsctlerrmap[cmd] == 0)
238: return; /* XXX */
239: type = NS_ERR_UNREACH_HOST;
240: switch (cmd) {
241: struct sockaddr_ns *sns;
242:
243: case PRC_IFDOWN:
244: case PRC_HOSTDEAD:
245: case PRC_HOSTUNREACH:
246: sns = (struct sockaddr_ns *)arg;
247: if (sns->sns_family != AF_INET)
248: return;
249: ns = &sns->sns_addr;
250: break;
251:
252: default:
253: errp = (struct ns_errp *)arg;
254: ns = &errp->ns_err_idp.idp_dna;
255: type = errp->ns_err_num;
256: type = ntohs((u_short)type);
257: }
258: switch (type) {
259:
260: case NS_ERR_UNREACH_HOST:
261: ns_pcbnotify(ns, (int)nsctlerrmap[cmd], idp_abort, (long)0);
262: break;
263:
264: case NS_ERR_NOSOCK:
265: nsp = ns_pcblookup(ns, errp->ns_err_idp.idp_sna.x_port,
266: NS_WILDCARD);
267: if(nsp && idp_donosocks && ! ns_nullhost(nsp->nsp_faddr))
268: (void) idp_drop(nsp, (int)nsctlerrmap[cmd]);
269: }
270: }
271:
272: int idpprintfs = 0;
273: int idpforwarding = 1;
274: /*
275: * Forward a packet. If some error occurs return the sender
276: * an error packet. Note we can't always generate a meaningful
277: * error message because the NS errors don't have a large enough repetoire
278: * of codes and types.
279: */
280: struct route idp_droute;
281: struct route idp_sroute;
282:
283: idp_forward(idp)
284: register struct idp *idp;
285: {
286: register int error, type, code;
287: struct mbuf *mcopy = NULL;
288: int agedelta = 1;
289: int flags = NS_FORWARDING;
290: int ok_there = 0;
291: int ok_back = 0;
292:
293: if (idpprintfs) {
294: printf("forward: src ");
295: ns_printhost(&idp->idp_sna);
296: printf(", dst ");
297: ns_printhost(&idp->idp_dna);
298: printf("hop count %d\n", idp->idp_tc);
299: }
300: if (idpforwarding == 0) {
301: /* can't tell difference between net and host */
302: type = NS_ERR_UNREACH_HOST, code = 0;
303: goto senderror;
304: }
305: idp->idp_tc++;
306: if (idp->idp_tc > NS_MAXHOPS) {
307: type = NS_ERR_TOO_OLD, code = 0;
308: goto senderror;
309: }
310: /*
311: * Save at most 42 bytes of the packet in case
312: * we need to generate an NS error message to the src.
313: */
314: mcopy = m_copy(dtom(idp), 0, imin((int)ntohs(idp->idp_len), 42));
315:
316: if ((ok_there = idp_do_route(&idp->idp_dna,&idp_droute))==0) {
317: type = NS_ERR_UNREACH_HOST, code = 0;
318: goto senderror;
319: }
320: /*
321: * Here we think about forwarding broadcast packets,
322: * so we try to insure that it doesn't go back out
323: * on the interface it came in on. Also, if we
324: * are going to physically broadcast this, let us
325: * age the packet so we can eat it safely the second time around.
326: */
327: if (idp->idp_dna.x_host.c_host[0] & 0x1) {
328: struct ns_ifaddr *ia = ns_iaonnetof(&idp->idp_dna);
329: struct ifnet *ifp;
330: if (ia) {
331: /* I'm gonna hafta eat this packet */
332: agedelta += NS_MAXHOPS - idp->idp_tc;
333: idp->idp_tc = NS_MAXHOPS;
334: }
335: if ((ok_back = idp_do_route(&idp->idp_sna,&idp_sroute))==0) {
336: /* error = ENETUNREACH; He'll never get it! */
337: m_freem(dtom(idp));
338: goto cleanup;
339: }
340: if (idp_droute.ro_rt &&
341: (ifp=idp_droute.ro_rt->rt_ifp) &&
342: idp_sroute.ro_rt &&
343: (ifp!=idp_sroute.ro_rt->rt_ifp)) {
344: flags |= NS_ALLOWBROADCAST;
345: } else {
346: type = NS_ERR_UNREACH_HOST, code = 0;
347: goto senderror;
348: }
349: }
350: /* need to adjust checksum */
351: if (idp->idp_sum!=0xffff) {
352: union bytes {
353: u_char c[4];
354: u_short s[2];
355: long l;
356: } x;
357: register int shift;
358: x.l = 0; x.c[0] = agedelta;
359: shift = (((((int)ntohs(idp->idp_len))+1)>>1)-2) & 0xf;
360: x.l = idp->idp_sum + (x.l << shift);
361: x.l = x.s[0] + x.s[1];
362: x.l = x.s[0] + x.s[1];
363: if (x.l==0xffff) idp->idp_sum = 0; else idp->idp_sum = x.l;
364: }
365: if ((error = ns_output(dtom(idp), &idp_droute, flags)) &&
366: (mcopy!=NULL)) {
367: idp = mtod(mcopy, struct idp *);
368: type = NS_ERR_UNSPEC_T, code = 0;
369: switch (error) {
370:
371: case ENETUNREACH:
372: case EHOSTDOWN:
373: case EHOSTUNREACH:
374: case ENETDOWN:
375: case EPERM:
376: type = NS_ERR_UNREACH_HOST;
377: break;
378:
379: case EMSGSIZE:
380: type = NS_ERR_TOO_BIG;
381: code = 576; /* too hard to figure out mtu here */
382: break;
383:
384: case ENOBUFS:
385: type = NS_ERR_UNSPEC_T;
386: break;
387: }
388: mcopy = NULL;
389: senderror:
390: ns_error(dtom(idp), type, code);
391: }
392: cleanup:
393: if (ok_there)
394: idp_undo_route(&idp_droute);
395: if (ok_back)
396: idp_undo_route(&idp_sroute);
397: if (mcopy != NULL)
398: m_freem(mcopy);
399: }
400:
401: idp_do_route(src, ro)
402: struct ns_addr *src;
403: struct route *ro;
404: {
405:
406: struct sockaddr_ns *dst;
407:
408: bzero((caddr_t)ro, sizeof (*ro));
409: dst = (struct sockaddr_ns *)&ro->ro_dst;
410:
411: dst->sns_family = AF_NS;
412: dst->sns_addr = *src;
413: dst->sns_addr.x_port = 0;
414: rtalloc(ro);
415: if (ro->ro_rt == 0 || ro->ro_rt->rt_ifp == 0) {
416: return (0);
417: }
418: ro->ro_rt->rt_use++;
419: return (1);
420: }
421:
422: idp_undo_route(ro)
423: register struct route *ro;
424: {
425: if (ro->ro_rt) {RTFREE(ro->ro_rt);}
426: }
427: static union ns_net
428: ns_zeronet;
429:
430: ns_watch_output(m, ifp)
431: struct mbuf *m;
432: struct ifnet *ifp;
433: {
434: register struct nspcb *nsp;
435: register struct ifaddr *ia;
436: /*
437: * Give any raw listeners a crack at the packet
438: */
439: for (nsp = nsrawpcb.nsp_next; nsp != &nsrawpcb; nsp = nsp->nsp_next) {
440: struct mbuf *m0 = m_copy(m, 0, (int)M_COPYALL);
441: if (m0) {
442: struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);
443:
444: if(m1 == NULL)
445: m_freem(m0);
446: else {
447: register struct idp *idp;
448:
449: m1->m_off = MMINOFF;
450: m1->m_len = sizeof (*idp);
451: m1->m_next = m0;
452: idp = mtod(m1, struct idp *);
453: idp->idp_sna.x_net = ns_zeronet;
454: idp->idp_sna.x_host = ns_thishost;
455: if (ifp && (ifp->if_flags & IFF_POINTOPOINT))
456: for(ia = ifp->if_addrlist; ia;
457: ia = ia->ifa_next) {
458: if (ia->ifa_addr.sa_family==AF_NS) {
459: idp->idp_sna =
460: satons_addr(ia->ifa_dstaddr);
461: break;
462: }
463: }
464: idp->idp_len = 0xffff;
465: idp_input(m1, nsp, ifp);
466: }
467: }
468: }
469: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.