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