|
|
1.1 root 1: /***********************************************************
2: Copyright IBM Corporation 1987
3:
4: All Rights Reserved
5:
6: Permission to use, copy, modify, and distribute this software and its
7: documentation for any purpose and without fee is hereby granted,
8: provided that the above copyright notice appear in all copies and that
9: both that copyright notice and this permission notice appear in
10: supporting documentation, and that the name of IBM not be
11: used in advertising or publicity pertaining to distribution of the
12: software without specific, written prior permission.
13:
14: IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15: ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16: IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17: ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18: WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19: ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20: SOFTWARE.
21:
22: ******************************************************************/
23:
24: /*
25: * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
26: */
27: /* $Header: /var/src/sys/netiso/RCS/clnp_input.c,v 5.1 89/02/09 16:20:32 hagens Exp $ */
28: /* $Source: /var/src/sys/netiso/RCS/clnp_input.c,v $ */
29: /* @(#)clnp_input.c 7.12 (Berkeley) 6/20/90 */
30:
31: #ifndef lint
32: static char *rcsid = "$Header: /var/src/sys/netiso/RCS/clnp_input.c,v 5.1 89/02/09 16:20:32 hagens Exp $";
33: #endif lint
34:
35: #include "types.h"
36: #include "param.h"
37: #include "mbuf.h"
38: #include "domain.h"
39: #include "protosw.h"
40: #include "socket.h"
41: #include "socketvar.h"
42: #include "errno.h"
43: #include "time.h"
44:
45: #include "../net/if.h"
46: #include "../net/if_types.h"
47: #include "../net/route.h"
48:
49: #include "iso.h"
50: #include "iso_var.h"
51: #include "iso_snpac.h"
52: #include "clnp.h"
53: #include "clnl.h"
54: #include "esis.h"
55: #include "../netinet/in_systm.h"
56: #include "../netinet/ip.h"
57: #include "../netinet/if_ether.h"
58: #include "eonvar.h"
59: #include "clnp_stat.h"
60: #include "argo_debug.h"
61:
62: #ifdef ISO
63: u_char clnp_protox[ISOPROTO_MAX];
64: struct clnl_protosw clnl_protox[256];
65: int clnpqmaxlen = IFQ_MAXLEN; /* RAH? why is this a variable */
66: struct mbuf *clnp_data_ck();
67:
68: int clnp_input();
69:
70: int esis_input();
71:
72: #ifdef ISO_X25ESIS
73: int x25esis_input();
74: #endif ISO_X25ESIS
75:
76: /*
77: * FUNCTION: clnp_init
78: *
79: * PURPOSE: clnp initialization. Fill in clnp switch tables.
80: *
81: * RETURNS: none
82: *
83: * SIDE EFFECTS: fills in clnp_protox table with correct offsets into
84: * the isosw table.
85: *
86: * NOTES:
87: */
88: clnp_init()
89: {
90: register struct protosw *pr;
91:
92: /*
93: * CLNP protox initialization
94: */
95: if ((pr = pffindproto(PF_ISO, ISOPROTO_RAW, SOCK_RAW)) == 0)
96: printf("clnl_init: no raw CLNP\n");
97: else
98: clnp_protox[ISOPROTO_RAW] = pr - isosw;
99:
100: if ((pr = pffindproto(PF_ISO, ISOPROTO_TP, SOCK_SEQPACKET)) == 0)
101: printf("clnl_init: no tp/clnp\n");
102: else
103: clnp_protox[ISOPROTO_TP] = pr - isosw;
104:
105: /*
106: * CLNL protox initialization
107: */
108: clnl_protox[ISO8473_CLNP].clnl_input = clnp_input;
109:
110: clnlintrq.ifq_maxlen = clnpqmaxlen;
111: }
112:
113: /*
114: * FUNCTION: clnlintr
115: *
116: * PURPOSE: Process a packet on the clnl input queue
117: *
118: * RETURNS: nothing.
119: *
120: * SIDE EFFECTS:
121: *
122: * NOTES:
123: */
124: clnlintr()
125: {
126: register struct mbuf *m; /* ptr to first mbuf of pkt */
127: register struct clnl_fixed *clnl; /* ptr to fixed part of clnl hdr */
128: int s; /* save and restore priority */
129: struct clnl_protosw *clnlsw;/* ptr to protocol switch */
130: struct snpa_hdr sh; /* subnetwork hdr */
131:
132: /*
133: * Get next datagram off clnl input queue
134: */
135: next:
136: s = splimp();
137: /* IF_DEQUEUESNPAHDR(&clnlintrq, m, sh);*/
138: IF_DEQUEUE(&clnlintrq, m);
139: splx(s);
140:
141:
142: if (m == 0) /* nothing to do */
143: return;
144: if ((m->m_flags & M_PKTHDR) == 0 || m->m_pkthdr.rcvif == 0) {
145: m_freem(m);
146: goto next;
147: } else {
148: register struct ifaddr *ifa;
149: for (ifa = m->m_pkthdr.rcvif->if_addrlist; ifa; ifa = ifa->ifa_next)
150: if (ifa->ifa_addr->sa_family == AF_ISO)
151: break;
152: if (ifa == 0) {
153: m_freem(m);
154: goto next;
155: }
156: }
157: bzero((caddr_t)&sh, sizeof(sh));
158: sh.snh_flags = m->m_flags & (M_MCAST|M_BCAST);
159: switch((sh.snh_ifp = m->m_pkthdr.rcvif)->if_type) {
160: extern int ether_output();
161: case IFT_EON:
162: bcopy(mtod(m, caddr_t), (caddr_t)sh.snh_dhost, sizeof(u_long));
163: bcopy(sizeof(u_long) + mtod(m, caddr_t),
164: (caddr_t)sh.snh_shost, sizeof(u_long));
165: sh.snh_dhost[4] = mtod(m, u_char *)[sizeof(struct ip) +
166: _offsetof(struct eon_hdr, eonh_class)];
167: m->m_data += EONIPLEN;
168: m->m_len -= EONIPLEN;
169: m->m_pkthdr.len -= EONIPLEN;
170: break;
171:
172: default:
173: if (sh.snh_ifp->if_output == ether_output) {
174: bcopy((caddr_t)(mtod(m, struct ether_header *)->ether_dhost),
175: (caddr_t)sh.snh_dhost, 2*sizeof(sh.snh_dhost));
176: m->m_data += sizeof (struct ether_header);
177: m->m_len -= sizeof (struct ether_header);
178: m->m_pkthdr.len -= sizeof (struct ether_header);
179: }
180: }
181: IFDEBUG(D_INPUT)
182: int i;
183: printf("clnlintr: src:");
184: for (i=0; i<6; i++)
185: printf("%x%c", sh.snh_shost[i] & 0xff, (i<5) ? ':' : ' ');
186: printf(" dst:");
187: for (i=0; i<6; i++)
188: printf("%x%c", sh.snh_dhost[i] & 0xff, (i<5) ? ':' : ' ');
189: printf("\n");
190: ENDDEBUG
191:
192: /*
193: * Get the fixed part of the clnl header into the first mbuf.
194: * Drop the packet if this fails.
195: * Do not call m_pullup if we have a cluster mbuf or the
196: * data is not there.
197: */
198: if ((IS_CLUSTER(m) || (m->m_len < sizeof(struct clnl_fixed))) &&
199: ((m = m_pullup(m, sizeof(struct clnl_fixed))) == 0)) {
200: INCSTAT(cns_toosmall); /* TODO: use clnl stats */
201: goto next; /* m_pullup discards mbuf */
202: }
203:
204: clnl = mtod(m, struct clnl_fixed *);
205:
206: /*
207: * Drop packet if the length of the header is not reasonable.
208: */
209: if ((clnl->cnf_hdr_len < CLNP_HDR_MIN) ||
210: (clnl->cnf_hdr_len > CLNP_HDR_MAX)) {
211: INCSTAT(cns_badhlen); /* TODO: use clnl stats */
212: m_freem(m);
213: goto next;
214: }
215:
216: /*
217: * If the header is not contained in this mbuf, make it so.
218: * Drop packet if this fails.
219: * Note: m_pullup will allocate a cluster mbuf if necessary
220: */
221: if (clnl->cnf_hdr_len > m->m_len) {
222: if ((m = m_pullup(m, (int)clnl->cnf_hdr_len)) == 0) {
223: INCSTAT(cns_badhlen); /* TODO: use clnl stats */
224: goto next; /* m_pullup discards mbuf */
225: }
226: clnl = mtod(m, struct clnl_fixed *);
227: }
228:
229: clnlsw = &clnl_protox[clnl->cnf_proto_id];
230:
231:
232: if (clnlsw->clnl_input)
233: (*clnlsw->clnl_input) (m, &sh);
234: else
235: m_freem(m);
236:
237: goto next;
238: }
239:
240: /*
241: * FUNCTION: clnp_input
242: *
243: * PURPOSE: process an incoming clnp packet
244: *
245: * RETURNS: nothing
246: *
247: * SIDE EFFECTS: increments fields of clnp_stat structure.
248: *
249: * NOTES:
250: * TODO: I would like to make seg_part a pointer into the mbuf, but
251: * will it be correctly aligned?
252: */
253: clnp_input(m, shp)
254: struct mbuf *m; /* ptr to first mbuf of pkt */
255: struct snpa_hdr *shp; /* subnetwork header */
256: {
257: register struct clnp_fixed *clnp; /* ptr to fixed part of header */
258: struct sockaddr_iso source; /* source address of pkt */
259: struct sockaddr_iso target; /* destination address of pkt */
260: #define src source.siso_addr
261: #define dst target.siso_addr
262: caddr_t hoff; /* current offset in packet */
263: caddr_t hend; /* address of end of header info */
264: struct clnp_segment seg_part; /* segment part of hdr */
265: int seg_off=0; /* offset of segment part of hdr */
266: int seg_len;/* length of packet data&hdr in bytes */
267: struct clnp_optidx oidx, *oidxp = NULL; /* option index */
268: extern int iso_systype; /* used by ESIS config resp */
269: extern struct sockaddr_iso blank_siso; /* used for initializing */
270: int need_afrin = 0;
271: /* true if congestion experienced */
272: /* which means you need afrin nose */
273: /* spray. How clever! */
274:
275: IFDEBUG(D_INPUT)
276: printf(
277: "clnp_input: proccessing dg; First mbuf m_len %d, m_type x%x, %s\n",
278: m->m_len, m->m_type, IS_CLUSTER(m) ? "cluster" : "normal");
279: ENDDEBUG
280: need_afrin = 0;
281:
282: /*
283: * If no iso addresses have been set, there is nothing
284: * to do with the packet.
285: */
286: if (iso_ifaddr == NULL) {
287: clnp_discard(m, ADDR_DESTUNREACH);
288: return;
289: }
290:
291: INCSTAT(cns_total);
292: clnp = mtod(m, struct clnp_fixed *);
293:
294: IFDEBUG(D_DUMPIN)
295: struct mbuf *mhead;
296: int total_len = 0;
297: printf("clnp_input: clnp header:\n");
298: dump_buf(mtod(m, caddr_t), clnp->cnf_hdr_len);
299: printf("clnp_input: mbuf chain:\n");
300: for (mhead = m; mhead != NULL; mhead=mhead->m_next) {
301: printf("m x%x, len %d\n", mhead, mhead->m_len);
302: total_len += mhead->m_len;
303: }
304: printf("clnp_input: total length of mbuf chain %d:\n", total_len);
305: ENDDEBUG
306:
307: /*
308: * Compute checksum (if necessary) and drop packet if
309: * checksum does not match
310: */
311: if (CKSUM_REQUIRED(clnp) && iso_check_csum(m, (int)clnp->cnf_hdr_len)) {
312: INCSTAT(cns_badcsum);
313: clnp_discard(m, GEN_BADCSUM);
314: return;
315: }
316:
317: if (clnp->cnf_vers != ISO8473_V1) {
318: INCSTAT(cns_badvers);
319: clnp_discard(m, DISC_UNSUPPVERS);
320: return;
321: }
322:
323:
324: /* check mbuf data length: clnp_data_ck will free mbuf upon error */
325: CTOH(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, seg_len);
326: if ((m = clnp_data_ck(m, seg_len)) == 0)
327: return;
328:
329: clnp = mtod(m, struct clnp_fixed *);
330: hend = (caddr_t)clnp + clnp->cnf_hdr_len;
331:
332: /*
333: * extract the source and destination address
334: * drop packet on failure
335: */
336: source = target = blank_siso;
337:
338: hoff = (caddr_t)clnp + sizeof(struct clnp_fixed);
339: CLNP_EXTRACT_ADDR(dst, hoff, hend);
340: if (hoff == (caddr_t)0) {
341: INCSTAT(cns_badaddr);
342: clnp_discard(m, GEN_INCOMPLETE);
343: return;
344: }
345: CLNP_EXTRACT_ADDR(src, hoff, hend);
346: if (hoff == (caddr_t)0) {
347: INCSTAT(cns_badaddr);
348: clnp_discard(m, GEN_INCOMPLETE);
349: return;
350: }
351:
352: IFDEBUG(D_INPUT)
353: printf("clnp_input: from %s", clnp_iso_addrp(&src));
354: printf(" to %s\n", clnp_iso_addrp(&dst));
355: ENDDEBUG
356:
357: /*
358: * extract the segmentation information, if it is present.
359: * drop packet on failure
360: */
361: if (((clnp->cnf_type & CNF_TYPE) != CLNP_ER) &&
362: (clnp->cnf_type & CNF_SEG_OK)) {
363: if (hoff + sizeof(struct clnp_segment) > hend) {
364: INCSTAT(cns_noseg);
365: clnp_discard(m, GEN_INCOMPLETE);
366: return;
367: } else {
368: (void) bcopy(hoff, (caddr_t)&seg_part, sizeof(struct clnp_segment));
369: /* make sure segmentation fields are in host order */
370: seg_part.cng_id = ntohs(seg_part.cng_id);
371: seg_part.cng_off = ntohs(seg_part.cng_off);
372: seg_part.cng_tot_len = ntohs(seg_part.cng_tot_len);
373: seg_off = hoff - (caddr_t)clnp;
374: hoff += sizeof(struct clnp_segment);
375: }
376: }
377:
378: /*
379: * process options if present. If clnp_opt_sanity returns
380: * false (indicating an error was found in the options) or
381: * an unsupported option was found
382: * then drop packet and emit an ER.
383: */
384: if (hoff < hend) {
385: int errcode;
386:
387: oidxp = &oidx;
388: errcode = clnp_opt_sanity(m, hoff, hend-hoff, oidxp);
389:
390: /* we do not support security */
391: if ((errcode == 0) && (oidxp->cni_securep))
392: errcode = DISC_UNSUPPSECURE;
393:
394: /* the er option is valid with ER pdus only */
395: if ((errcode == 0) && (oidxp->cni_er_reason != ER_INVALREAS) &&
396: ((clnp->cnf_type & CNF_TYPE) != CLNP_ER))
397: errcode = DISC_UNSUPPOPT;
398:
399: #ifdef DECBIT
400: /* check if the congestion experienced bit is set */
401: if (oidxp->cni_qos_formatp) {
402: caddr_t qosp = CLNP_OFFTOOPT(m, oidxp->cni_qos_formatp);
403: u_char qos = *qosp;
404:
405: need_afrin = ((qos & (CLNPOVAL_GLOBAL|CLNPOVAL_CONGESTED)) ==
406: (CLNPOVAL_GLOBAL|CLNPOVAL_CONGESTED));
407: if (need_afrin)
408: INCSTAT(cns_congest_rcvd);
409: }
410: #endif DECBIT
411:
412: if (errcode != 0) {
413: clnp_discard(m, (char)errcode);
414: IFDEBUG(D_INPUT)
415: printf("clnp_input: dropped (err x%x) due to bad options\n",
416: errcode);
417: ENDDEBUG
418: return;
419: }
420: }
421:
422: /*
423: * check if this packet is for us. if not, then forward
424: */
425: if (clnp_ours(&dst) == 0) {
426: IFDEBUG(D_INPUT)
427: printf("clnp_input: forwarding packet not for us\n");
428: ENDDEBUG
429: clnp_forward(m, seg_len, &dst, oidxp, seg_off, shp);
430: return;
431: }
432:
433: /*
434: * ESIS Configuration Response Function
435: *
436: * If the packet received was sent to the multicast address
437: * all end systems, then send an esh to the source
438: */
439: if ((shp->snh_flags & M_MCAST) && (iso_systype == SNPA_ES)) {
440: extern short esis_holding_time;
441:
442: esis_shoutput(shp->snh_ifp, ESIS_ESH, esis_holding_time,
443: shp->snh_shost, 6, &dst);
444: }
445:
446: /*
447: * If this is a fragment, then try to reassemble it. If clnp_reass
448: * returns non NULL, the packet has been reassembled, and should
449: * be give to TP. Otherwise the fragment has been delt with
450: * by the reassembly code (either stored or deleted). In either case
451: * we should have nothing more to do with it.
452: */
453: if (((clnp->cnf_type & CNF_TYPE) != CLNP_ER) &&
454: (clnp->cnf_type & CNF_SEG_OK) &&
455: (seg_len != seg_part.cng_tot_len)) {
456: struct mbuf *m0;
457:
458: if ((m0 = clnp_reass(m, &src, &dst, &seg_part)) != NULL) {
459: m = m0;
460: clnp = mtod(m, struct clnp_fixed *);
461: INCSTAT(cns_reassembled);
462: } else {
463: return;
464: }
465: }
466:
467: /*
468: * give the packet to the higher layer
469: *
470: * Note: the total length of packet
471: * is the total length field of the segmentation part,
472: * or, if absent, the segment length field of the
473: * header.
474: */
475: INCSTAT(cns_delivered);
476: switch (clnp->cnf_type & CNF_TYPE) {
477: case CLNP_ER:
478: /*
479: * This ER must have the er option.
480: * If the option is not present, discard datagram.
481: */
482: if (oidxp == NULL || oidxp->cni_er_reason == ER_INVALREAS) {
483: clnp_discard(m, GEN_HDRSYNTAX);
484: } else {
485: clnp_er_input(m, &src, oidxp->cni_er_reason);
486: }
487: break;
488:
489: case CLNP_DT:
490: (*isosw[clnp_protox[ISOPROTO_TP]].pr_input)(m, &source, &target,
491: clnp->cnf_hdr_len, need_afrin);
492: break;
493:
494: case CLNP_RAW:
495: case CLNP_ECR:
496: IFDEBUG(D_INPUT)
497: printf("clnp_input: raw input of %d bytes\n",
498: clnp->cnf_type & CNF_SEG_OK ? seg_part.cng_tot_len : seg_len);
499: ENDDEBUG
500: (*isosw[clnp_protox[ISOPROTO_RAW]].pr_input)(m, &source, &target,
501: clnp->cnf_hdr_len);
502: break;
503:
504: case CLNP_EC:
505: IFDEBUG(D_INPUT)
506: printf("clnp_input: echoing packet\n");
507: ENDDEBUG
508: /*
509: * Switch the source and destination address,
510: */
511: hoff = (caddr_t)clnp + sizeof(struct clnp_fixed);
512: CLNP_INSERT_ADDR(hoff, src);
513: CLNP_INSERT_ADDR(hoff, dst);
514: clnp->cnf_type &= ~CNF_TYPE;
515: clnp->cnf_type |= CLNP_ECR;
516:
517: /*
518: * Forward back to sender
519: */
520: clnp_forward(m, (int)
521: (clnp->cnf_type & CNF_SEG_OK ? seg_part.cng_tot_len : seg_len),
522: &src, oidxp, seg_off, 0);
523: break;
524:
525: default:
526: printf("clnp_input: unknown clnp pkt type %d\n",
527: clnp->cnf_type & CNF_TYPE);
528: clnp_stat.cns_delivered--;
529: clnp_stat.cns_noproto++;
530: clnp_discard(m, GEN_HDRSYNTAX);
531: break;
532: }
533: }
534: #endif ISO
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.