|
|
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_subr.c,v 5.1 89/02/09 16:20:46 hagens Exp $ */
28: /* $Source: /var/src/sys/netiso/RCS/clnp_subr.c,v $ */
29: /* @(#)clnp_subr.c 7.11 (Berkeley) 6/20/90 */
30:
31: #ifndef lint
32: static char *rcsid = "$Header: /var/src/sys/netiso/RCS/clnp_subr.c,v 5.1 89/02/09 16:20:46 hagens Exp $";
33: #endif lint
34:
35: #ifdef ISO
36:
37: #include "types.h"
38: #include "param.h"
39: #include "mbuf.h"
40: #include "domain.h"
41: #include "protosw.h"
42: #include "socket.h"
43: #include "socketvar.h"
44: #include "errno.h"
45: #include "time.h"
46:
47: #include "../net/if.h"
48: #include "../net/route.h"
49: #include "../net/if_dl.h"
50:
51: #include "iso.h"
52: #include "iso_var.h"
53: #include "iso_pcb.h"
54: #include "iso_snpac.h"
55: #include "clnp.h"
56: #include "clnp_stat.h"
57: #include "argo_debug.h"
58:
59: /*
60: * FUNCTION: clnp_data_ck
61: *
62: * PURPOSE: Check that the amount of data in the mbuf chain is
63: * at least as much as the clnp header would have us
64: * expect. Trim mbufs if longer than expected, drop
65: * packet if shorter than expected.
66: *
67: * RETURNS: success - ptr to mbuf chain
68: * failure - 0
69: *
70: * SIDE EFFECTS:
71: *
72: * NOTES:
73: */
74: struct mbuf *
75: clnp_data_ck(m, length)
76: register struct mbuf *m; /* ptr to mbuf chain containing hdr & data */
77: int length; /* length (in bytes) of packet */
78: {
79: register int len; /* length of data */
80: register struct mbuf *mhead; /* ptr to head of chain */
81:
82: len = -length;
83: mhead = m;
84: for (;;) {
85: len += m->m_len;
86: if (m->m_next == 0)
87: break;
88: m = m->m_next;
89: }
90: if (len != 0) {
91: if (len < 0) {
92: INCSTAT(cns_toosmall);
93: clnp_discard(mhead, GEN_INCOMPLETE);
94: return 0;
95: }
96: if (len <= m->m_len)
97: m->m_len -= len;
98: else
99: m_adj(mhead, -len);
100: }
101: return mhead;
102: }
103:
104: #ifdef ndef
105: /*
106: * FUNCTION: clnp_extract_addr
107: *
108: * PURPOSE: Extract the source and destination address from the
109: * supplied buffer. Place them in the supplied address buffers.
110: * If insufficient data is supplied, then fail.
111: *
112: * RETURNS: success - Address of first byte in the packet past
113: * the address part.
114: * failure - 0
115: *
116: * SIDE EFFECTS:
117: *
118: * NOTES:
119: */
120: caddr_t
121: clnp_extract_addr(bufp, buflen, srcp, destp)
122: caddr_t bufp; /* ptr to buffer containing addresses */
123: int buflen; /* length of buffer */
124: register struct iso_addr *srcp; /* ptr to source address buffer */
125: register struct iso_addr *destp; /* ptr to destination address buffer */
126: {
127: int len; /* argument to bcopy */
128:
129: /*
130: * check that we have enough data. Plus1 is for length octet
131: */
132: if ((u_char)*bufp + 1 > buflen) {
133: return((caddr_t)0);
134: }
135: len = destp->isoa_len = (u_char)*bufp++;
136: (void) bcopy(bufp, (caddr_t)destp, len);
137: buflen -= len;
138: bufp += len;
139:
140: /*
141: * check that we have enough data. Plus1 is for length octet
142: */
143: if ((u_char)*bufp + 1 > buflen) {
144: return((caddr_t)0);
145: }
146: len = srcp->isoa_len = (u_char)* bufp++;
147: (void) bcopy(bufp, (caddr_t)srcp, len);
148: bufp += len;
149:
150: /*
151: * Insure that the addresses make sense
152: */
153: if (iso_ck_addr(srcp) && iso_ck_addr(destp))
154: return bufp;
155: else
156: return (caddr_t) 0;
157: }
158: #endif ndef
159:
160: /*
161: * FUNCTION: clnp_ours
162: *
163: * PURPOSE: Decide whether the supplied packet is destined for
164: * us, or that it should be forwarded on.
165: *
166: * RETURNS: packet is for us - 1
167: * packet is not for us - 0
168: *
169: * SIDE EFFECTS:
170: *
171: * NOTES:
172: */
173: clnp_ours(dst)
174: register struct iso_addr *dst; /* ptr to destination address */
175: {
176: register struct iso_ifaddr *ia; /* scan through interface addresses */
177:
178: for (ia = iso_ifaddr; ia; ia = ia->ia_next) {
179: IFDEBUG(D_ROUTE)
180: printf("clnp_ours: ia_sis x%x, dst x%x\n", &ia->ia_addr,
181: dst);
182: ENDDEBUG
183: /*
184: * XXX Warning:
185: * We are overloading siso_tlen in the if's address, as an nsel length.
186: */
187: if (dst->isoa_len == ia->ia_addr.siso_nlen &&
188: bcmp((caddr_t)ia->ia_addr.siso_addr.isoa_genaddr,
189: (caddr_t)dst->isoa_genaddr,
190: ia->ia_addr.siso_nlen - ia->ia_addr.siso_tlen) == 0)
191: return 1;
192: }
193: return 0;
194: }
195:
196: /* Dec bit set if ifp qlen is greater than congest_threshold */
197: int congest_threshold = 0;
198:
199: /*
200: * FUNCTION: clnp_forward
201: *
202: * PURPOSE: Forward the datagram passed
203: * clnpintr guarantees that the header will be
204: * contigious (a cluster mbuf will be used if necessary).
205: *
206: * If oidx is NULL, no options are present.
207: *
208: * RETURNS: nothing
209: *
210: * SIDE EFFECTS:
211: *
212: * NOTES:
213: */
214: clnp_forward(m, len, dst, oidx, seg_off, inbound_shp)
215: struct mbuf *m; /* pkt to forward */
216: int len; /* length of pkt */
217: struct iso_addr *dst; /* destination address */
218: struct clnp_optidx *oidx; /* option index */
219: int seg_off;/* offset of segmentation part */
220: struct snpa_hdr *inbound_shp; /* subnetwork header of inbound packet */
221: {
222: struct clnp_fixed *clnp; /* ptr to fixed part of header */
223: int error; /* return value of route function */
224: struct sockaddr *next_hop; /* next hop for dgram */
225: struct ifnet *ifp; /* ptr to outgoing interface */
226: struct iso_ifaddr *ia = 0;/* ptr to iso name for ifp */
227: struct route_iso route; /* filled in by clnp_route */
228: extern int iso_systype;
229:
230: clnp = mtod(m, struct clnp_fixed *);
231: bzero((caddr_t)&route, sizeof(route)); /* MUST be done before "bad:" */
232:
233: /*
234: * Don't forward multicast or broadcast packets
235: */
236: if ((inbound_shp) && (IS_MULTICAST(inbound_shp->snh_dhost))) {
237: IFDEBUG(D_FORWARD)
238: printf("clnp_forward: dropping multicast packet\n");
239: ENDDEBUG
240: clnp->cnf_type &= ~CNF_ERR_OK; /* so we don't generate an ER */
241: clnp_discard(m, 0);
242: INCSTAT(cns_cantforward);
243: goto done;
244: }
245:
246: IFDEBUG(D_FORWARD)
247: printf("clnp_forward: %d bytes, to %s, options x%x\n", len,
248: clnp_iso_addrp(dst), oidx);
249: ENDDEBUG
250:
251: /*
252: * Decrement ttl, and if zero drop datagram
253: * Can't compare ttl as less than zero 'cause its a unsigned
254: */
255: if ((clnp->cnf_ttl == 0) || (--clnp->cnf_ttl == 0)) {
256: IFDEBUG(D_FORWARD)
257: printf("clnp_forward: discarding datagram because ttl is zero\n");
258: ENDDEBUG
259: INCSTAT(cns_ttlexpired);
260: clnp_discard(m, TTL_EXPTRANSIT);
261: goto done;
262: }
263: /*
264: * Route packet; special case for source rt
265: */
266: if CLNPSRCRT_VALID(oidx) {
267: /*
268: * Update src route first
269: */
270: clnp_update_srcrt(m, oidx);
271: error = clnp_srcroute(m, oidx, &route, &next_hop, &ia, dst);
272: } else {
273: error = clnp_route(dst, &route, 0, &next_hop, &ia);
274: }
275: if (error || ia == 0) {
276: IFDEBUG(D_FORWARD)
277: printf("clnp_forward: can't route packet (errno %d)\n", error);
278: ENDDEBUG
279: clnp_discard(m, ADDR_DESTUNREACH);
280: INCSTAT(cns_cantforward);
281: goto done;
282: }
283: ifp = ia->ia_ifp;
284:
285: IFDEBUG(D_FORWARD)
286: printf("clnp_forward: packet routed to %s\n",
287: clnp_iso_addrp(&((struct sockaddr_iso *)next_hop)->siso_addr));
288: ENDDEBUG
289:
290: INCSTAT(cns_forward);
291:
292: /*
293: * If we are an intermediate system and
294: * we are routing outbound on the same ifp that the packet
295: * arrived upon, and we know the next hop snpa,
296: * then generate a redirect request
297: */
298: if ((iso_systype & SNPA_IS) && (inbound_shp) &&
299: (ifp == inbound_shp->snh_ifp))
300: esis_rdoutput(inbound_shp, m, oidx, dst, route.ro_rt);
301: /*
302: * If options are present, update them
303: */
304: if (oidx) {
305: struct iso_addr *mysrc = &ia->ia_addr.siso_addr;
306: if (mysrc == NULL) {
307: clnp_discard(m, ADDR_DESTUNREACH);
308: INCSTAT(cns_cantforward);
309: clnp_stat.cns_forward--;
310: goto done;
311: } else {
312: (void) clnp_dooptions(m, oidx, ifp, mysrc);
313: }
314: }
315:
316: #ifdef DECBIT
317: if (ifp->if_snd.ifq_len > congest_threshold) {
318: /*
319: * Congestion! Set the Dec Bit and thank Dave Oran
320: */
321: IFDEBUG(D_FORWARD)
322: printf("clnp_forward: congestion experienced\n");
323: ENDDEBUG
324: if ((oidx) && (oidx->cni_qos_formatp)) {
325: caddr_t qosp = CLNP_OFFTOOPT(m, oidx->cni_qos_formatp);
326: u_char qos = *qosp;
327: IFDEBUG(D_FORWARD)
328: printf("clnp_forward: setting congestion bit (qos x%x)\n", qos);
329: ENDDEBUG
330: if ((qos & CLNPOVAL_GLOBAL) == CLNPOVAL_GLOBAL) {
331: qos |= CLNPOVAL_CONGESTED;
332: INCSTAT(cns_congest_set);
333: *qosp = qos;
334: }
335: }
336: }
337: #endif DECBIT
338:
339: /*
340: * Dispatch the datagram if it is small enough, otherwise fragment
341: */
342: if (len <= SN_MTU(ifp)) {
343: iso_gen_csum(m, CLNP_CKSUM_OFF, (int)clnp->cnf_hdr_len);
344: (void) (*ifp->if_output)(ifp, m, next_hop, route.ro_rt);
345: } else {
346: (void) clnp_fragment(ifp, m, next_hop, len, seg_off, /* flags */0, route.ro_rt);
347: }
348:
349: done:
350: /*
351: * Free route
352: */
353: if (route.ro_rt != NULL) {
354: RTFREE(route.ro_rt);
355: }
356: }
357:
358: #ifdef ndef
359: /*
360: * FUNCTION: clnp_insert_addr
361: *
362: * PURPOSE: Insert the address part into a clnp datagram.
363: *
364: * RETURNS: Address of first byte after address part in datagram.
365: *
366: * SIDE EFFECTS:
367: *
368: * NOTES: Assume that there is enough space for the address part.
369: */
370: caddr_t
371: clnp_insert_addr(bufp, srcp, dstp)
372: caddr_t bufp; /* address of where addr part goes */
373: register struct iso_addr *srcp; /* ptr to src addr */
374: register struct iso_addr *dstp; /* ptr to dst addr */
375: {
376: *bufp++ = dstp->isoa_len;
377: (void) bcopy((caddr_t)dstp, bufp, dstp->isoa_len);
378: bufp += dstp->isoa_len;
379:
380: *bufp++ = srcp->isoa_len;
381: (void) bcopy((caddr_t)srcp, bufp, srcp->isoa_len);
382: bufp += srcp->isoa_len;
383:
384: return bufp;
385: }
386:
387: #endif ndef
388:
389: /*
390: * FUNCTION: clnp_route
391: *
392: * PURPOSE: Route a clnp datagram to the first hop toward its
393: * destination. In many cases, the first hop will be
394: * the destination. The address of a route
395: * is specified. If a routing entry is present in
396: * that route, and it is still up to the same destination,
397: * then no further action is necessary. Otherwise, a
398: * new routing entry will be allocated.
399: *
400: * RETURNS: route found - 0
401: * unix error code
402: *
403: * SIDE EFFECTS:
404: *
405: * NOTES: It is up to the caller to free the routing entry
406: * allocated in route.
407: */
408: clnp_route(dst, ro, flags, first_hop, ifa)
409: struct iso_addr *dst; /* ptr to datagram destination */
410: register struct route_iso *ro; /* existing route structure */
411: int flags; /* flags for routing */
412: struct sockaddr **first_hop; /* result: fill in with ptr to firsthop */
413: struct iso_ifaddr **ifa; /* result: fill in with ptr to interface */
414: {
415: if (flags & SO_DONTROUTE) {
416: struct iso_ifaddr *ia;
417:
418: if (ro->ro_rt) {
419: RTFREE(ro->ro_rt);
420: ro->ro_rt = 0;
421: }
422: bzero((caddr_t)&ro->ro_dst, sizeof(ro->ro_dst));
423: bcopy((caddr_t)dst, (caddr_t)&ro->ro_dst.siso_addr,
424: 1 + (unsigned)dst->isoa_len);
425: ro->ro_dst.siso_family = AF_ISO;
426: ro->ro_dst.siso_len = sizeof(ro->ro_dst);
427: ia = iso_localifa(&ro->ro_dst);
428: if (ia == 0)
429: return EADDRNOTAVAIL;
430: if (ifa)
431: *ifa = ia;
432: if (first_hop)
433: *first_hop = (struct sockaddr *)&ro->ro_dst;
434: return 0;
435: }
436: /*
437: * If there is a cached route, check that it is still up and to
438: * the same destination. If not, free it and try again.
439: */
440: if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
441: (Bcmp(ro->ro_dst.siso_data, dst->isoa_genaddr, dst->isoa_len)))) {
442: IFDEBUG(D_ROUTE)
443: printf("clnp_route: freeing old route: ro->ro_rt 0x%x\n",
444: ro->ro_rt);
445: printf("clnp_route: old route refcnt: 0x%x\n",
446: ro->ro_rt->rt_refcnt);
447: ENDDEBUG
448:
449: /* free old route entry */
450: RTFREE(ro->ro_rt);
451: ro->ro_rt = (struct rtentry *)0;
452: } else {
453: IFDEBUG(D_ROUTE)
454: printf("clnp_route: OK route exists\n");
455: ENDDEBUG
456: }
457:
458: if (ro->ro_rt == 0) {
459: /* set up new route structure */
460: bzero((caddr_t)&ro->ro_dst, sizeof(ro->ro_dst));
461: ro->ro_dst.siso_len = sizeof(ro->ro_dst);
462: ro->ro_dst.siso_family = AF_ISO;
463: Bcopy(dst, &ro->ro_dst.siso_addr, 1 + dst->isoa_len);
464: /* allocate new route */
465: IFDEBUG(D_ROUTE)
466: printf("clnp_route: allocating new route to %s\n",
467: clnp_iso_addrp(dst));
468: ENDDEBUG
469: rtalloc((struct route *)ro);
470: }
471: if (ro->ro_rt == 0)
472: return(ENETUNREACH); /* rtalloc failed */
473: ro->ro_rt->rt_use++;
474: if (ifa)
475: if ((*ifa = (struct iso_ifaddr *)ro->ro_rt->rt_ifa) == 0)
476: panic("clnp_route");
477: if (first_hop) {
478: if (ro->ro_rt->rt_flags & RTF_GATEWAY)
479: *first_hop = ro->ro_rt->rt_gateway;
480: else
481: *first_hop = (struct sockaddr *)&ro->ro_dst;
482: }
483: return(0);
484: }
485:
486: /*
487: * FUNCTION: clnp_srcroute
488: *
489: * PURPOSE: Source route the datagram. If complete source
490: * routing is specified but not possible, then
491: * return an error. If src routing is terminated, then
492: * try routing on destination.
493: * Usage of first_hop,
494: * ifp, and error return is identical to clnp_route.
495: *
496: * RETURNS: 0 or unix error code
497: *
498: * SIDE EFFECTS:
499: *
500: * NOTES: Remember that option index pointers are really
501: * offsets from the beginning of the mbuf.
502: */
503: clnp_srcroute(options, oidx, ro, first_hop, ifa, final_dst)
504: struct mbuf *options; /* ptr to options */
505: struct clnp_optidx *oidx; /* index to options */
506: struct route_iso *ro; /* route structure */
507: struct sockaddr **first_hop; /* RETURN: fill in with ptr to firsthop */
508: struct iso_ifaddr **ifa; /* RETURN: fill in with ptr to interface */
509: struct iso_addr *final_dst; /* final destination */
510: {
511: struct iso_addr dst; /* first hop specified by src rt */
512: int error = 0; /* return code */
513:
514: /*
515: * Check if we have run out of routes
516: * If so, then try to route on destination.
517: */
518: if CLNPSRCRT_TERM(oidx, options) {
519: dst.isoa_len = final_dst->isoa_len;
520: bcopy(final_dst->isoa_genaddr, dst.isoa_genaddr, dst.isoa_len);
521: } else {
522: /*
523: * setup dst based on src rt specified
524: */
525: dst.isoa_len = CLNPSRCRT_CLEN(oidx, options);
526: bcopy(CLNPSRCRT_CADDR(oidx, options), dst.isoa_genaddr, dst.isoa_len);
527: }
528:
529: /*
530: * try to route it
531: */
532: error = clnp_route(&dst, ro, 0, first_hop, ifa);
533: if (error != 0)
534: return error;
535:
536: /*
537: * If complete src rt, first hop must be equal to dst
538: */
539: if ((CLNPSRCRT_TYPE(oidx, options) == CLNPOVAL_COMPRT) &&
540: (!iso_addrmatch1(&(*(struct sockaddr_iso **)first_hop)->siso_addr,&dst))){
541: IFDEBUG(D_OPTIONS)
542: printf("clnp_srcroute: complete src route failed\n");
543: ENDDEBUG
544: return EHOSTUNREACH; /* RAH? would like ESRCRTFAILED */
545: }
546:
547: return error;
548: }
549:
550: /*
551: * FUNCTION: clnp_ypocb - backwards bcopy
552: *
553: * PURPOSE: bcopy starting at end of src rather than beginning.
554: *
555: * RETURNS: none
556: *
557: * SIDE EFFECTS:
558: *
559: * NOTES: No attempt has been made to make this efficient
560: */
561: clnp_ypocb(from, to, len)
562: caddr_t from; /* src buffer */
563: caddr_t to; /* dst buffer */
564: u_int len; /* number of bytes */
565: {
566: while (len--)
567: *(to + len) = *(from + len);
568: }
569:
570: /*
571: * FUNCTION: clnp_hdrsize
572: *
573: * PURPOSE: Return the size of a typical clnp hdr.
574: *
575: * RETURNS: Size of hdr in bytes.
576: *
577: * SIDE EFFECTS:
578: *
579: * NOTES: Assumes segmenting subset. If addrlen is
580: * zero, default to largest nsap address size.
581: */
582: clnp_hdrsize(addrlen)
583: u_char addrlen; /* length of nsap address */
584: {
585: if (addrlen == 0)
586: addrlen = 20;
587:
588: addrlen++; /* length of address byte */
589: addrlen *= 2; /* src and dst addresses */
590: addrlen += sizeof(struct clnp_fixed) + sizeof(struct clnp_segment);
591:
592: return(addrlen);
593: }
594: #endif ISO
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.