|
|
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_output.c,v 5.0 89/02/08 12:00:15 hagens Exp $ */
28: /* $Source: /var/src/sys/netiso/RCS/clnp_output.c,v $ */
29: /* @(#)clnp_output.c 7.8 (Berkeley) 6/4/90 */
30:
31: #ifndef lint
32: static char *rcsid = "$Header: /var/src/sys/netiso/RCS/clnp_output.c,v 5.0 89/02/08 12:00:15 hagens Exp $";
33: #endif lint
34:
35: #include "param.h"
36: #include "mbuf.h"
37: #include "domain.h"
38: #include "protosw.h"
39: #include "socket.h"
40: #include "socketvar.h"
41: #include "errno.h"
42: #include "time.h"
43:
44: #include "../net/if.h"
45: #include "../net/route.h"
46:
47: #include "iso.h"
48: #include "iso_var.h"
49: #include "iso_pcb.h"
50: #include "clnp.h"
51: #include "clnp_stat.h"
52: #include "argo_debug.h"
53:
54: static struct clnp_fixed dt_template = {
55: ISO8473_CLNP, /* network identifier */
56: 0, /* length */
57: ISO8473_V1, /* version */
58: CLNP_TTL, /* ttl */
59: CLNP_DT|CNF_SEG_OK|CNF_ERR_OK, /* type */
60: 0, /* segment length */
61: 0 /* checksum */
62: };
63:
64: static struct clnp_fixed raw_template = {
65: ISO8473_CLNP, /* network identifier */
66: 0, /* length */
67: ISO8473_V1, /* version */
68: CLNP_TTL, /* ttl */
69: CLNP_RAW|CNF_SEG_OK|CNF_ERR_OK, /* type */
70: 0, /* segment length */
71: 0 /* checksum */
72: };
73:
74: static struct clnp_fixed echo_template = {
75: ISO8473_CLNP, /* network identifier */
76: 0, /* length */
77: ISO8473_V1, /* version */
78: CLNP_TTL, /* ttl */
79: CLNP_EC|CNF_SEG_OK|CNF_ERR_OK, /* type */
80: 0, /* segment length */
81: 0 /* checksum */
82: };
83:
84: #ifdef DECBIT
85: u_char qos_option[] = {CLNPOVAL_QOS, 1,
86: CLNPOVAL_GLOBAL|CLNPOVAL_SEQUENCING|CLNPOVAL_LOWDELAY};
87: #endif DECBIT
88:
89: int clnp_id = 0; /* id for segmented dgrams */
90:
91: /*
92: * FUNCTION: clnp_output
93: *
94: * PURPOSE: output the data in the mbuf as a clnp datagram
95: *
96: * The data specified by m0 is sent as a clnp datagram.
97: * The mbuf chain m0 will be freed when this routine has
98: * returned.
99: *
100: * If options is non-null, it points to an mbuf which contains
101: * options to be sent with the datagram. The options must
102: * be formatted in the mbuf according to clnp rules. Options
103: * will not be freed.
104: *
105: * Datalen specifies the length of the data in m0.
106: *
107: * Src and dst are the addresses for the packet.
108: *
109: * If route is non-null, it is used as the route for
110: * the packet.
111: *
112: * By default, a DT is sent. However, if flags & CNLP_SEND_ER
113: * then an ER will be sent. If flags & CLNP_SEND_RAW, then
114: * the packet will be send as raw clnp.
115: *
116: * RETURNS: 0 success
117: * appropriate error code
118: *
119: * SIDE EFFECTS: none
120: *
121: * NOTES:
122: * Flags are interpretated as follows:
123: * CLNP_NO_SEG - do not allow this pkt to be segmented.
124: * CLNP_NO_ER - have pkt request ER suppression.
125: * CLNP_SEND_RAW - send pkt as RAW DT rather than TP DT
126: * CLNP_NO_CKSUM - don't compute clnp checksum
127: * CLNP_ECHO - send as ECHO packet
128: *
129: * When checking for a cached packet, clnp checks
130: * that the route taken is still up. It does not
131: * check that the route is still to the same destination.
132: * This means that any entity that alters an existing
133: * route for an isopcb (such as when a redirect arrives)
134: * must invalidate the clnp cache. It might be perferable
135: * to have clnp check that the route has the same dest, but
136: * by avoiding this check, we save a call to iso_addrmatch1.
137: */
138: clnp_output(m0, isop, datalen, flags)
139: struct mbuf *m0; /* data for the packet */
140: struct isopcb *isop; /* iso pcb */
141: int datalen; /* number of bytes of data in m0 */
142: int flags; /* flags */
143: {
144: int error = 0; /* return value of function */
145: register struct mbuf *m = m0; /* mbuf for clnp header chain */
146: register struct clnp_fixed *clnp; /* ptr to fixed part of hdr */
147: register caddr_t hoff; /* offset into header */
148: int total_len; /* total length of packet */
149: struct iso_addr *src; /* ptr to source address */
150: struct iso_addr *dst; /* ptr to destination address */
151: struct clnp_cache clc; /* storage for cache information */
152: struct clnp_cache *clcp = NULL; /* ptr to clc */
153: int hdrlen = 0;
154:
155: dst = &isop->isop_faddr->siso_addr;
156: if (isop->isop_laddr == 0) {
157: struct iso_ifaddr *ia = 0;
158: clnp_route(dst, &isop->isop_route, flags, 0, &ia);
159: if (ia == 0 || ia->ia_ifa.ifa_addr->sa_family != AF_ISO)
160: return (ENETUNREACH);
161: src = &ia->ia_addr.siso_addr;
162: } else
163: src = &isop->isop_laddr->siso_addr;
164:
165: IFDEBUG(D_OUTPUT)
166: printf("clnp_output: to %s", clnp_iso_addrp(dst));
167: printf(" from %s of %d bytes\n", clnp_iso_addrp(src), datalen);
168: printf("\toptions x%x, flags x%x, isop_clnpcache x%x\n",
169: isop->isop_options, flags, isop->isop_clnpcache);
170: ENDDEBUG
171:
172: if (isop->isop_clnpcache != NULL) {
173: clcp = mtod(isop->isop_clnpcache, struct clnp_cache *);
174: }
175:
176: /*
177: * Check if cache is valid ...
178: */
179: IFDEBUG(D_OUTPUT)
180: printf("clnp_output: ck cache: clcp %x\n", clcp);
181: if (clcp != NULL) {
182: printf("\tclc_dst %s\n", clnp_iso_addrp(&clcp->clc_dst));
183: printf("\tisop_opts x%x, clc_opts x%x\n", isop->isop_options,
184: clcp->clc_options);
185: if (isop->isop_route.ro_rt)
186: printf("\tro_rt x%x, rt_flags x%x\n",
187: isop->isop_route.ro_rt, isop->isop_route.ro_rt->rt_flags);
188: printf("\tflags x%x, clc_flags x%x\n", flags, clcp->clc_flags);
189: printf("\tclc_hdr x%x\n", clcp->clc_hdr);
190: }
191: ENDDEBUG
192: if ((clcp != NULL) && /* cache exists */
193: (isop->isop_options == clcp->clc_options) && /* same options */
194: (iso_addrmatch1(dst, &clcp->clc_dst)) && /* dst still same */
195: (isop->isop_route.ro_rt != NULL) && /* route exists */
196: (isop->isop_route.ro_rt == clcp->clc_rt) && /* and is cached */
197: (isop->isop_route.ro_rt->rt_flags & RTF_UP) && /* route still up */
198: (flags == clcp->clc_flags) && /* same flags */
199: (clcp->clc_hdr != NULL)) { /* hdr mbuf exists */
200: /*
201: * The cache is valid
202: */
203:
204: IFDEBUG(D_OUTPUT)
205: printf("clnp_output: using cache\n");
206: ENDDEBUG
207:
208: m = m_copy(clcp->clc_hdr, 0, (int)M_COPYALL);
209: if (m == NULL) {
210: /*
211: * No buffers left to copy cached packet header. Use
212: * the cached packet header this time, and
213: * mark the hdr as vacant
214: */
215: m = clcp->clc_hdr;
216: clcp->clc_hdr = NULL;
217: }
218: m->m_next = m0; /* ASSUMES pkt hdr is 1 mbuf long */
219: clnp = mtod(m, struct clnp_fixed *);
220: } else {
221: struct clnp_optidx *oidx = NULL; /* index to clnp options */
222:
223: /*
224: * The cache is not valid. Allocate an mbuf (if necessary)
225: * to hold cached info. If one is not available, then
226: * don't bother with the cache
227: */
228: INCSTAT(cns_cachemiss);
229: if (flags & CLNP_NOCACHE) {
230: clcp = &clc;
231: } else {
232: if (isop->isop_clnpcache == NULL) {
233: /*
234: * There is no clnpcache. Allocate an mbuf to hold one
235: */
236: if ((isop->isop_clnpcache = m_get(M_DONTWAIT, MT_HEADER))
237: == NULL) {
238: /*
239: * No mbufs available. Pretend that we don't want
240: * caching this time.
241: */
242: IFDEBUG(D_OUTPUT)
243: printf("clnp_output: no mbufs to allocate to cache\n");
244: ENDDEBUG
245: flags |= CLNP_NOCACHE;
246: clcp = &clc;
247: } else {
248: clcp = mtod(isop->isop_clnpcache, struct clnp_cache *);
249: }
250: } else {
251: /*
252: * A clnpcache mbuf exists. If the clc_hdr is not null,
253: * we must free it, as a new one is about to be created.
254: */
255: clcp = mtod(isop->isop_clnpcache, struct clnp_cache *);
256: if (clcp->clc_hdr != NULL) {
257: /*
258: * The clc_hdr is not null but a clnpcache mbuf exists.
259: * This means that there was a cache, but the existing
260: * copy of the hdr is no longer valid. Free it now
261: * before we lose the pointer to it.
262: */
263: IFDEBUG(D_OUTPUT)
264: printf("clnp_output: freeing old clc_hdr 0x%x\n",
265: clcp->clc_hdr);
266: ENDDEBUG
267: m_free(clcp->clc_hdr);
268: IFDEBUG(D_OUTPUT)
269: printf("clnp_output: freed old clc_hdr (done)\n");
270: ENDDEBUG
271: }
272: }
273: }
274: IFDEBUG(D_OUTPUT)
275: printf("clnp_output: NEW clcp x%x\n",clcp);
276: ENDDEBUG
277: bzero((caddr_t)clcp, sizeof(struct clnp_cache));
278:
279: if (isop->isop_optindex)
280: oidx = mtod(isop->isop_optindex, struct clnp_optidx *);
281:
282: /*
283: * Don't allow packets with security, quality of service,
284: * priority, or error report options to be sent.
285: */
286: if ((isop->isop_options) && (oidx)) {
287: if ((oidx->cni_securep) ||
288: (oidx->cni_priorp) ||
289: (oidx->cni_qos_formatp) ||
290: (oidx->cni_er_reason != ER_INVALREAS)) {
291: IFDEBUG(D_OUTPUT)
292: printf("clnp_output: pkt dropped - option unsupported\n");
293: ENDDEBUG
294: m_freem(m0);
295: return(EINVAL);
296: }
297: }
298:
299: /*
300: * Don't allow any invalid flags to be set
301: */
302: if ((flags & (CLNP_VFLAGS)) != flags) {
303: IFDEBUG(D_OUTPUT)
304: printf("clnp_output: packet dropped - flags unsupported\n");
305: ENDDEBUG
306: INCSTAT(cns_odropped);
307: m_freem(m0);
308: return(EINVAL);
309: }
310:
311: /*
312: * Don't allow funny lengths on dst; src may be zero in which
313: * case we insert the source address based upon the interface
314: */
315: if ((src->isoa_len > sizeof(struct iso_addr)) ||
316: (dst->isoa_len == 0) ||
317: (dst->isoa_len > sizeof(struct iso_addr))) {
318: m_freem(m0);
319: INCSTAT(cns_odropped);
320: return(ENAMETOOLONG);
321: }
322:
323: /*
324: * Grab mbuf to contain header
325: */
326: MGETHDR(m, M_DONTWAIT, MT_HEADER);
327: if (m == 0) {
328: m_freem(m0);
329: INCSTAT(cns_odropped);
330: return(ENOBUFS);
331: }
332: INCSTAT(cns_sent);
333: m->m_next = m0;
334: clnp = mtod(m, struct clnp_fixed *);
335: clcp->clc_segoff = 0;
336:
337: /*
338: * Fill in all of fixed hdr except lengths and checksum
339: */
340: if (flags & CLNP_SEND_RAW) {
341: *clnp = raw_template;
342: } else if (flags & CLNP_ECHO) {
343: *clnp = echo_template;
344: } else {
345: *clnp = dt_template;
346: }
347: if (flags & CLNP_NO_SEG)
348: clnp->cnf_type &= ~CNF_SEG_OK;
349: if (flags & CLNP_NO_ER)
350: clnp->cnf_type &= ~CNF_ERR_OK;
351:
352: /*
353: * Route packet; special case for source rt
354: */
355: if ((isop->isop_options) && CLNPSRCRT_VALID(oidx)) {
356: IFDEBUG(D_OUTPUT)
357: printf("clnp_output: calling clnp_srcroute\n");
358: ENDDEBUG
359: error = clnp_srcroute(isop->isop_options, oidx, &isop->isop_route,
360: &clcp->clc_firsthop, &clcp->clc_ifa, dst);
361: } else {
362: IFDEBUG(D_OUTPUT)
363: ENDDEBUG
364: error = clnp_route(dst, &isop->isop_route, flags,
365: &clcp->clc_firsthop, &clcp->clc_ifa);
366: }
367: if (error || (clcp->clc_ifa == 0)) {
368: IFDEBUG(D_OUTPUT)
369: printf("clnp_output: route failed, errno %d\n", error);
370: printf("@clcp:\n");
371: dump_buf(clcp, sizeof (struct clnp_cache));
372: ENDDEBUG
373: goto bad;
374: }
375: clcp->clc_rt = isop->isop_route.ro_rt; /* XXX */
376:
377: IFDEBUG(D_OUTPUT)
378: printf("clnp_output: packet routed to %s\n",
379: clnp_iso_addrp(
380: &((struct sockaddr_iso *)clcp->clc_firsthop)->siso_addr));
381: ENDDEBUG
382:
383: /*
384: * If src address is not yet specified, use address of
385: * interface. NOTE: this will now update the laddr field in
386: * the isopcb. Is this desirable? RAH?
387: */
388: if (src->isoa_len == 0) {
389: src = &(clcp->clc_ifa->ia_addr.siso_addr);
390: IFDEBUG(D_OUTPUT)
391: printf("clnp_output: new src %s\n", clnp_iso_addrp(src));
392: ENDDEBUG
393: }
394:
395: /*
396: * Insert the source and destination address,
397: */
398: hoff = (caddr_t)clnp + sizeof(struct clnp_fixed);
399: CLNP_INSERT_ADDR(hoff, *dst);
400: CLNP_INSERT_ADDR(hoff, *src);
401:
402: /*
403: * Leave room for the segment part, if segmenting is selected
404: */
405: if (clnp->cnf_type & CNF_SEG_OK) {
406: clcp->clc_segoff = hoff - (caddr_t)clnp;
407: hoff += sizeof(struct clnp_segment);
408: }
409:
410: clnp->cnf_hdr_len = m->m_len = (u_char)(hoff - (caddr_t)clnp);
411: hdrlen = clnp->cnf_hdr_len;
412:
413: #ifdef DECBIT
414: /*
415: * Add the globally unique QOS (with room for congestion experienced
416: * bit). I can safely assume that this option is not in the options
417: * mbuf below because I checked that the option was not specified
418: * previously
419: */
420: if ((m->m_len + sizeof(qos_option)) < MLEN) {
421: bcopy((caddr_t)qos_option, hoff, sizeof(qos_option));
422: clnp->cnf_hdr_len += sizeof(qos_option);
423: hdrlen += sizeof(qos_option);
424: m->m_len += sizeof(qos_option);
425: }
426: #endif DECBIT
427:
428: /*
429: * If an options mbuf is present, concatenate a copy to the hdr mbuf.
430: */
431: if (isop->isop_options) {
432: struct mbuf *opt_copy = m_copy(isop->isop_options, 0, (int)M_COPYALL);
433: if (opt_copy == NULL) {
434: error = ENOBUFS;
435: goto bad;
436: }
437: /* Link in place */
438: opt_copy->m_next = m->m_next;
439: m->m_next = opt_copy;
440:
441: /* update size of header */
442: clnp->cnf_hdr_len += opt_copy->m_len;
443: hdrlen += opt_copy->m_len;
444: }
445:
446: if (hdrlen > CLNP_HDR_MAX) {
447: error = EMSGSIZE;
448: goto bad;
449: }
450:
451: /*
452: * Now set up the cache entry in the pcb
453: */
454: if ((flags & CLNP_NOCACHE) == 0) {
455: if (clcp->clc_hdr = m_copy(m, 0, (int)clnp->cnf_hdr_len)) {
456: clcp->clc_dst = *dst;
457: clcp->clc_flags = flags;
458: clcp->clc_options = isop->isop_options;
459: }
460: }
461: }
462: /*
463: * If small enough for interface, send directly
464: * Fill in segmentation part of hdr if using the full protocol
465: */
466: total_len = clnp->cnf_hdr_len + datalen;
467: if (clnp->cnf_type & CNF_SEG_OK) {
468: struct clnp_segment seg_part; /* segment part of hdr */
469: seg_part.cng_id = htons(clnp_id++);
470: seg_part.cng_off = htons(0);
471: seg_part.cng_tot_len = htons(total_len);
472: (void) bcopy((caddr_t)&seg_part, (caddr_t) clnp + clcp->clc_segoff,
473: sizeof(seg_part));
474: }
475: if (total_len <= SN_MTU(clcp->clc_ifa->ia_ifp)) {
476: HTOC(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, total_len);
477: m->m_pkthdr.len = total_len;
478: /*
479: * Compute clnp checksum (on header only)
480: */
481: if (flags & CLNP_NO_CKSUM) {
482: HTOC(clnp->cnf_cksum_msb, clnp->cnf_cksum_lsb, 0);
483: } else {
484: iso_gen_csum(m, CLNP_CKSUM_OFF, (int)clnp->cnf_hdr_len);
485: }
486:
487: IFDEBUG(D_DUMPOUT)
488: struct mbuf *mdump = m;
489: printf("clnp_output: sending dg:\n");
490: while (mdump != NULL) {
491: dump_buf(mtod(mdump, caddr_t), mdump->m_len);
492: mdump = mdump->m_next;
493: }
494: ENDDEBUG
495:
496: error = SN_OUTPUT(clcp, m);
497: goto done;
498: } else {
499: /*
500: * Too large for interface; fragment if possible.
501: */
502: error = clnp_fragment(clcp->clc_ifa->ia_ifp, m, clcp->clc_firsthop,
503: total_len, clcp->clc_segoff, flags, clcp->clc_rt);
504: goto done;
505: }
506: bad:
507: m_freem(m);
508: done:
509: if (error) {
510: clnp_stat.cns_sent--;
511: clnp_stat.cns_odropped++;
512: }
513: return (error);
514: }
515:
516: int clnp_ctloutput()
517: {
518: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.