Reflow to < 80 chars.
[netbsd-mini2440.git] / sys / netiso / clnp_output.c
blob60703d53eda546fe847ff5982a3d2329fbe05da7
1 /* $NetBSD: clnp_output.c,v 1.24 2009/03/18 17:06:52 cegger Exp $ */
3 /*-
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
31 * @(#)clnp_output.c 8.1 (Berkeley) 6/10/93
34 /***********************************************************
35 Copyright IBM Corporation 1987
37 All Rights Reserved
39 Permission to use, copy, modify, and distribute this software and its
40 documentation for any purpose and without fee is hereby granted,
41 provided that the above copyright notice appear in all copies and that
42 both that copyright notice and this permission notice appear in
43 supporting documentation, and that the name of IBM not be
44 used in advertising or publicity pertaining to distribution of the
45 software without specific, written prior permission.
47 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
48 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
49 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
50 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
51 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
52 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
53 SOFTWARE.
55 ******************************************************************/
58 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
61 #include <sys/cdefs.h>
62 __KERNEL_RCSID(0, "$NetBSD: clnp_output.c,v 1.24 2009/03/18 17:06:52 cegger Exp $");
64 #include <sys/param.h>
65 #include <sys/mbuf.h>
66 #include <sys/domain.h>
67 #include <sys/protosw.h>
68 #include <sys/socket.h>
69 #include <sys/socketvar.h>
70 #include <sys/errno.h>
71 #include <sys/time.h>
72 #include <sys/systm.h>
74 #include <net/if.h>
75 #include <net/route.h>
77 #include <netiso/iso.h>
78 #include <netiso/iso_var.h>
79 #include <netiso/iso_pcb.h>
80 #include <netiso/clnp.h>
81 #include <netiso/clnp_stat.h>
82 #include <netiso/argo_debug.h>
84 #include <machine/stdarg.h>
86 static struct clnp_fixed dt_template = {
87 ISO8473_CLNP, /* network identifier */
88 0, /* length */
89 ISO8473_V1, /* version */
90 CLNP_TTL, /* ttl */
91 CLNP_DT | CNF_SEG_OK | CNF_ERR_OK, /* type */
92 0, /* segment length msb */
93 0, /* segment length lsb */
94 0, /* checksum msb */
95 0, /* checksum lmsb */
98 static struct clnp_fixed raw_template = {
99 ISO8473_CLNP, /* network identifier */
100 0, /* length */
101 ISO8473_V1, /* version */
102 CLNP_TTL, /* ttl */
103 CLNP_RAW | CNF_SEG_OK | CNF_ERR_OK, /* type */
104 0, /* segment length msb */
105 0, /* segment length lsb */
106 0, /* checksum msb */
107 0, /* checksum lmsb */
110 static struct clnp_fixed echo_template = {
111 ISO8473_CLNP, /* network identifier */
112 0, /* length */
113 ISO8473_V1, /* version */
114 CLNP_TTL, /* ttl */
115 CLNP_EC | CNF_SEG_OK | CNF_ERR_OK, /* type */
116 0, /* segment length msb */
117 0, /* segment length lsb */
118 0, /* checksum msb */
119 0, /* checksum lmsb */
122 static struct clnp_fixed echor_template = {
123 ISO8473_CLNP, /* network identifier */
124 0, /* length */
125 ISO8473_V1, /* version */
126 CLNP_TTL, /* ttl */
127 CLNP_ECR | CNF_SEG_OK | CNF_ERR_OK, /* type */
128 0, /* segment length msb */
129 0, /* segment length lsb */
130 0, /* checksum msb */
131 0, /* checksum lmsb */
134 #ifdef DECBIT
135 u_char qos_option[] = {CLNPOVAL_QOS, 1,
136 CLNPOVAL_GLOBAL | CLNPOVAL_SEQUENCING | CLNPOVAL_LOWDELAY};
137 #endif /* DECBIT */
139 int clnp_id = 0; /* id for segmented dgrams */
142 * FUNCTION: clnp_output
144 * PURPOSE: output the data in the mbuf as a clnp datagram
146 * The data specified by m0 is sent as a clnp datagram.
147 * The mbuf chain m0 will be freed when this routine has
148 * returned.
150 * If options is non-null, it points to an mbuf which
151 * contains options to be sent with the datagram. The
152 * options must be formatted in the mbuf according to
153 * clnp rules. Options will not be freed.
155 * Datalen specifies the length of the data in m0.
157 * Src and dst are the addresses for the packet.
159 * If route is non-null, it is used as the route for
160 * the packet.
162 * By default, a DT is sent. However,
163 * if flags & CNLP_SEND_ER then an ER will be sent.
164 * If flags & CLNP_SEND_RAW, then the packet will
165 * be send as raw clnp.
167 * RETURNS: 0 success
168 * appropriate error code
170 * SIDE EFFECTS: none
172 * NOTES: Flags are interpretated as follows:
173 * CLNP_NO_SEG - do not allow this pkt to be segmented.
174 * CLNP_NO_ER - have pkt request ER suppression.
175 * CLNP_SEND_RAW - send pkt as RAW DT rather than TP DT
176 * CLNP_NO_CKSUM - don't compute clnp checksum
177 * CLNP_ECHO - send as ECHO packet
179 * When checking for a cached packet, clnp checks
180 * that the route taken is still up. It does not
181 * check that the route is still to the same destination.
182 * This means that any entity that alters an existing
183 * route for an isopcb (such as when a redirect arrives)
184 * must invalidate the clnp cache. It might be perferable
185 * to have clnp check that the route has the same dest, but
186 * by avoiding this check, we save a call to
187 * iso_addrmatch1.
190 clnp_output(struct mbuf *m0, ...)
192 struct rtentry *rt;
193 struct isopcb *isop; /* iso pcb */
194 int datalen;/* number of bytes of data in m0 */
195 int flags; /* flags */
196 int error = 0; /* return value of function */
197 struct mbuf *m = m0; /* mbuf for clnp header chain */
198 struct clnp_fixed *clnp; /* ptr to fixed part of hdr */
199 char *hoff; /* offset into header */
200 int total_len; /* total length of packet */
201 struct iso_addr *src; /* ptr to source address */
202 struct iso_addr *dst; /* ptr to destination address */
203 struct clnp_cache clc; /* storage for cache information */
204 struct clnp_cache *clcp = NULL; /* ptr to clc */
205 int hdrlen = 0;
206 va_list ap;
208 va_start(ap, m0);
209 isop = va_arg(ap, struct isopcb *);
210 datalen = va_arg(ap, int);
211 flags = va_arg(ap, int);
212 va_end(ap);
214 dst = &isop->isop_faddr->siso_addr;
215 if (isop->isop_laddr == 0) {
216 struct iso_ifaddr *ia = 0;
217 clnp_route(dst, &isop->isop_route, flags, 0, &ia);
218 if (ia == 0 || ia->ia_ifa.ifa_addr->sa_family != AF_ISO)
219 return (ENETUNREACH);
220 src = &ia->ia_addr.siso_addr;
221 } else
222 src = &isop->isop_laddr->siso_addr;
224 #ifdef ARGO_DEBUG
225 if (argo_debug[D_OUTPUT]) {
226 printf("clnp_output: to %s", clnp_iso_addrp(dst));
227 printf(" from %s of %d bytes\n", clnp_iso_addrp(src), datalen);
228 printf("\toptions %p, flags x%x, isop_clnpcache %p\n",
229 isop->isop_options, flags, isop->isop_clnpcache);
231 #endif
233 if (isop->isop_clnpcache != NULL) {
234 clcp = mtod(isop->isop_clnpcache, struct clnp_cache *);
237 * Check if cache is valid ...
239 #ifdef ARGO_DEBUG
240 if (argo_debug[D_OUTPUT]) {
241 printf("clnp_output: ck cache: clcp %p\n", clcp);
242 if (clcp != NULL) {
243 printf("\tclc_dst %s\n", clnp_iso_addrp(&clcp->clc_dst));
244 printf("\tisop_opts %p, clc_opts %p\n",
245 isop->isop_options, clcp->clc_options);
246 if ((rt = rtcache_validate(&isop->isop_route)) != NULL)
247 printf("\trt %p, rt_flags x%x\n",
248 rt, rt->rt_flags);
249 printf("\tflags x%x, clc_flags x%x\n", flags,
250 clcp->clc_flags);
251 printf("\tclc_hdr %p\n", clcp->clc_hdr);
254 #endif
255 if ((clcp != NULL) && /* cache exists */
256 (isop->isop_options == clcp->clc_options) && /* same options */
257 (iso_addrmatch1(dst, &clcp->clc_dst)) && /* dst still same */
258 (rt = rtcache_validate(&isop->isop_route)) != NULL && /* route exists */
259 rt == clcp->clc_rt && /* and is cached */
260 (rt->rt_flags & RTF_UP) && /* route still up */
261 (flags == clcp->clc_flags) && /* same flags */
262 (clcp->clc_hdr != NULL)) { /* hdr mbuf exists */
264 * The cache is valid
267 #ifdef ARGO_DEBUG
268 if (argo_debug[D_OUTPUT]) {
269 printf("clnp_output: using cache\n");
271 #endif
273 m = m_copy(clcp->clc_hdr, 0, (int) M_COPYALL);
274 if (m == NULL) {
276 * No buffers left to copy cached packet header. Use
277 * the cached packet header this time, and
278 * mark the hdr as vacant
280 m = clcp->clc_hdr;
281 clcp->clc_hdr = NULL;
283 m->m_next = m0; /* ASSUMES pkt hdr is 1 mbuf long */
284 clnp = mtod(m, struct clnp_fixed *);
285 } else {
286 struct clnp_optidx *oidx = NULL; /* index to clnp options */
289 * The cache is not valid. Allocate an mbuf (if necessary)
290 * to hold cached info. If one is not available, then
291 * don't bother with the cache
293 INCSTAT(cns_cachemiss);
294 if (flags & CLNP_NOCACHE) {
295 clcp = &clc;
296 } else {
297 if (isop->isop_clnpcache == NULL) {
299 * There is no clnpcache. Allocate an mbuf
300 * to hold one
302 if ((isop->isop_clnpcache = m_get(M_DONTWAIT, MT_HEADER))
303 == NULL) {
305 * No mbufs available. Pretend that we
306 * don't want caching this time.
308 #ifdef ARGO_DEBUG
309 if (argo_debug[D_OUTPUT]) {
310 printf("clnp_output: no mbufs to allocate to cache\n");
312 #endif
313 flags |= CLNP_NOCACHE;
314 clcp = &clc;
315 } else {
316 clcp = mtod(isop->isop_clnpcache, struct clnp_cache *);
318 } else {
320 * A clnpcache mbuf exists. If the clc_hdr
321 * is not null, we must free it, as a new one
322 * is about to be created.
324 clcp = mtod(isop->isop_clnpcache, struct clnp_cache *);
325 if (clcp->clc_hdr != NULL) {
327 * The clc_hdr is not null but a
328 * clnpcache mbuf exists. This means
329 * that there was a cache, but the
330 * existing copy of the hdr is no
331 * longer valid. Free it now
332 * before we lose the pointer to it.
334 #ifdef ARGO_DEBUG
335 if (argo_debug[D_OUTPUT]) {
336 printf(
337 "clnp_output: freeing old clc_hdr %p\n",
338 clcp->clc_hdr);
340 #endif
341 m_free(clcp->clc_hdr);
342 #ifdef ARGO_DEBUG
343 if (argo_debug[D_OUTPUT]) {
344 printf("clnp_output: freed old clc_hdr (done)\n");
346 #endif
350 #ifdef ARGO_DEBUG
351 if (argo_debug[D_OUTPUT]) {
352 printf("clnp_output: NEW clcp %p\n", clcp);
354 #endif
355 memset((void *) clcp, 0, sizeof(struct clnp_cache));
357 if (isop->isop_optindex)
358 oidx = mtod(isop->isop_optindex, struct clnp_optidx *);
361 * Don't allow packets with security, quality of service,
362 * priority, or error report options to be sent.
364 if ((isop->isop_options) && (oidx)) {
365 if ((oidx->cni_securep) ||
366 (oidx->cni_priorp) ||
367 (oidx->cni_qos_formatp) ||
368 (oidx->cni_er_reason != ER_INVALREAS)) {
369 #ifdef ARGO_DEBUG
370 if (argo_debug[D_OUTPUT]) {
371 printf("clnp_output: pkt dropped - option unsupported\n");
373 #endif
374 m_freem(m0);
375 return (EINVAL);
379 * Don't allow any invalid flags to be set
381 if ((flags & (CLNP_VFLAGS)) != flags) {
382 #ifdef ARGO_DEBUG
383 if (argo_debug[D_OUTPUT]) {
384 printf("clnp_output: packet dropped - flags unsupported\n");
386 #endif
387 INCSTAT(cns_odropped);
388 m_freem(m0);
389 return (EINVAL);
392 * Don't allow funny lengths on dst; src may be zero in which
393 * case we insert the source address based upon the interface
395 if ((src->isoa_len > sizeof(struct iso_addr)) ||
396 (dst->isoa_len == 0) ||
397 (dst->isoa_len > sizeof(struct iso_addr))) {
398 m_freem(m0);
399 INCSTAT(cns_odropped);
400 return (ENAMETOOLONG);
403 * Grab mbuf to contain header
405 MGETHDR(m, M_DONTWAIT, MT_HEADER);
406 if (m == 0) {
407 m_freem(m0);
408 INCSTAT(cns_odropped);
409 return (ENOBUFS);
411 INCSTAT(cns_sent);
412 m->m_next = m0;
413 clnp = mtod(m, struct clnp_fixed *);
414 clcp->clc_segoff = 0;
417 * Fill in all of fixed hdr except lengths and checksum
419 if (flags & CLNP_SEND_RAW) {
420 *clnp = raw_template;
421 } else if (flags & CLNP_ECHO) {
422 *clnp = echo_template;
423 } else if (flags & CLNP_ECHOR) {
424 *clnp = echor_template;
425 } else {
426 *clnp = dt_template;
428 if (flags & CLNP_NO_SEG)
429 clnp->cnf_type &= ~CNF_SEG_OK;
430 if (flags & CLNP_NO_ER)
431 clnp->cnf_type &= ~CNF_ERR_OK;
434 * Route packet; special case for source rt
436 if ((isop->isop_options) && CLNPSRCRT_VALID(oidx)) {
437 #ifdef ARGO_DEBUG
438 if (argo_debug[D_OUTPUT]) {
439 printf("clnp_output: calling clnp_srcroute\n");
441 #endif
442 error = clnp_srcroute(isop->isop_options, oidx, &isop->isop_route,
443 &clcp->clc_firsthop, &clcp->clc_ifa, dst);
444 } else {
445 #ifdef ARGO_DEBUG
446 if (argo_debug[D_OUTPUT]) {
448 #endif
449 error = clnp_route(dst, &isop->isop_route, flags,
450 &clcp->clc_firsthop, &clcp->clc_ifa);
452 if (error || (clcp->clc_ifa == 0)) {
453 #ifdef ARGO_DEBUG
454 if (argo_debug[D_OUTPUT]) {
455 printf("clnp_output: route failed, errno %d\n", error);
456 printf("@clcp:\n");
457 dump_buf(clcp, sizeof(struct clnp_cache));
459 #endif
460 goto bad;
462 clcp->clc_rt = rtcache_validate(&isop->isop_route);/* XXX */
463 clcp->clc_ifp = clcp->clc_ifa->ia_ifp; /* XXX */
465 #ifdef ARGO_DEBUG
466 if (argo_debug[D_OUTPUT]) {
467 printf("clnp_output: packet routed to %s\n",
468 clnp_iso_addrp(
469 &satocsiso(clcp->clc_firsthop)->siso_addr));
471 #endif
474 * If src address is not yet specified, use address of
475 * interface. NOTE: this will now update the laddr field in
476 * the isopcb. Is this desirable? RAH?
478 if (src->isoa_len == 0) {
479 src = &(clcp->clc_ifa->ia_addr.siso_addr);
480 #ifdef ARGO_DEBUG
481 if (argo_debug[D_OUTPUT]) {
482 printf("clnp_output: new src %s\n", clnp_iso_addrp(src));
484 #endif
487 * Insert the source and destination address,
489 hoff = (char *) clnp + sizeof(struct clnp_fixed);
490 CLNP_INSERT_ADDR(hoff, *dst);
491 CLNP_INSERT_ADDR(hoff, *src);
494 * Leave room for the segment part, if segmenting is selected
496 if (clnp->cnf_type & CNF_SEG_OK) {
497 clcp->clc_segoff = hoff - (char *)clnp;
498 hoff += sizeof(struct clnp_segment);
500 clnp->cnf_hdr_len = m->m_len = (u_char)(hoff - (char *)clnp);
501 hdrlen = clnp->cnf_hdr_len;
503 #ifdef DECBIT
505 * Add the globally unique QOS (with room for congestion
506 * experienced bit). I can safely assume that this option
507 * is not in the options mbuf below because I checked that
508 * the option was not specified previously
510 if ((m->m_len + sizeof(qos_option)) < MLEN) {
511 memcpy(hoff, (void *) qos_option, sizeof(qos_option));
512 clnp->cnf_hdr_len += sizeof(qos_option);
513 hdrlen += sizeof(qos_option);
514 m->m_len += sizeof(qos_option);
516 #endif /* DECBIT */
519 * If an options mbuf is present, concatenate a copy to the hdr mbuf.
521 if (isop->isop_options) {
522 struct mbuf *opt_copy =
523 m_copy(isop->isop_options, 0, (int) M_COPYALL);
524 if (opt_copy == NULL) {
525 error = ENOBUFS;
526 goto bad;
528 /* Link in place */
529 opt_copy->m_next = m->m_next;
530 m->m_next = opt_copy;
532 /* update size of header */
533 clnp->cnf_hdr_len += opt_copy->m_len;
534 hdrlen += opt_copy->m_len;
536 if (hdrlen > CLNP_HDR_MAX) {
537 error = EMSGSIZE;
538 goto bad;
541 * Now set up the cache entry in the pcb
543 if ((flags & CLNP_NOCACHE) == 0) {
544 clcp->clc_hdr = m_copy(m, 0, (int) clnp->cnf_hdr_len);
545 if (clcp->clc_hdr) {
546 clcp->clc_dst = *dst;
547 clcp->clc_flags = flags;
548 clcp->clc_options = isop->isop_options;
553 * If small enough for interface, send directly
554 * Fill in segmentation part of hdr if using the full protocol
556 total_len = clnp->cnf_hdr_len + datalen;
557 if (clnp->cnf_type & CNF_SEG_OK) {
558 struct clnp_segment seg_part; /* segment part of hdr */
559 seg_part.cng_id = htons(clnp_id++);
560 seg_part.cng_off = htons(0);
561 seg_part.cng_tot_len = htons(total_len);
562 (void)memcpy((char *)clnp + clcp->clc_segoff, &seg_part,
563 sizeof(seg_part));
565 if (total_len <= SN_MTU(clcp->clc_ifp, clcp->clc_rt)) {
566 HTOC(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, total_len);
567 m->m_pkthdr.len = total_len;
569 * Compute clnp checksum (on header only)
571 if (flags & CLNP_NO_CKSUM) {
572 HTOC(clnp->cnf_cksum_msb, clnp->cnf_cksum_lsb, 0);
573 } else {
574 iso_gen_csum(m, CLNP_CKSUM_OFF, (int) clnp->cnf_hdr_len);
577 #ifdef ARGO_DEBUG
578 if (argo_debug[D_DUMPOUT]) {
579 struct mbuf *mdump = m;
580 printf("clnp_output: sending dg:\n");
581 while (mdump != NULL) {
582 dump_buf(mtod(mdump, void *), mdump->m_len);
583 mdump = mdump->m_next;
586 #endif
588 error = SN_OUTPUT(clcp, m);
589 goto done;
590 } else {
592 * Too large for interface; fragment if possible.
594 error = clnp_fragment(clcp->clc_ifp, m, clcp->clc_firsthop,
595 total_len, clcp->clc_segoff, flags, clcp->clc_rt);
596 goto done;
598 bad:
599 m_freem(m);
600 done:
601 if (error) {
602 clnp_stat.cns_sent--;
603 clnp_stat.cns_odropped++;
605 return (error);
608 #ifdef notyet
609 void
610 clnp_ctloutput(void)
613 #endif