1 /* $NetBSD: clnp_output.c,v 1.24 2009/03/18 17:06:52 cegger Exp $ */
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
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
31 * @(#)clnp_output.c 8.1 (Berkeley) 6/10/93
34 /***********************************************************
35 Copyright IBM Corporation 1987
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
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>
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>
72 #include <sys/systm.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 */
89 ISO8473_V1
, /* version */
91 CLNP_DT
| CNF_SEG_OK
| CNF_ERR_OK
, /* type */
92 0, /* segment length msb */
93 0, /* segment length lsb */
95 0, /* checksum lmsb */
98 static struct clnp_fixed raw_template
= {
99 ISO8473_CLNP
, /* network identifier */
101 ISO8473_V1
, /* version */
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 */
113 ISO8473_V1
, /* version */
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 */
125 ISO8473_V1
, /* version */
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 */
135 u_char qos_option
[] = {CLNPOVAL_QOS
, 1,
136 CLNPOVAL_GLOBAL
| CLNPOVAL_SEQUENCING
| CLNPOVAL_LOWDELAY
};
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
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
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.
168 * appropriate error code
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
190 clnp_output(struct mbuf
*m0
, ...)
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 */
209 isop
= va_arg(ap
, struct isopcb
*);
210 datalen
= va_arg(ap
, int);
211 flags
= va_arg(ap
, int);
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
;
222 src
= &isop
->isop_laddr
->siso_addr
;
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
);
233 if (isop
->isop_clnpcache
!= NULL
) {
234 clcp
= mtod(isop
->isop_clnpcache
, struct clnp_cache
*);
237 * Check if cache is valid ...
240 if (argo_debug
[D_OUTPUT
]) {
241 printf("clnp_output: ck cache: clcp %p\n", clcp
);
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",
249 printf("\tflags x%x, clc_flags x%x\n", flags
,
251 printf("\tclc_hdr %p\n", clcp
->clc_hdr
);
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 */
268 if (argo_debug
[D_OUTPUT
]) {
269 printf("clnp_output: using cache\n");
273 m
= m_copy(clcp
->clc_hdr
, 0, (int) M_COPYALL
);
276 * No buffers left to copy cached packet header. Use
277 * the cached packet header this time, and
278 * mark the hdr as vacant
281 clcp
->clc_hdr
= NULL
;
283 m
->m_next
= m0
; /* ASSUMES pkt hdr is 1 mbuf long */
284 clnp
= mtod(m
, struct clnp_fixed
*);
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
) {
297 if (isop
->isop_clnpcache
== NULL
) {
299 * There is no clnpcache. Allocate an mbuf
302 if ((isop
->isop_clnpcache
= m_get(M_DONTWAIT
, MT_HEADER
))
305 * No mbufs available. Pretend that we
306 * don't want caching this time.
309 if (argo_debug
[D_OUTPUT
]) {
310 printf("clnp_output: no mbufs to allocate to cache\n");
313 flags
|= CLNP_NOCACHE
;
316 clcp
= mtod(isop
->isop_clnpcache
, struct clnp_cache
*);
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.
335 if (argo_debug
[D_OUTPUT
]) {
337 "clnp_output: freeing old clc_hdr %p\n",
341 m_free(clcp
->clc_hdr
);
343 if (argo_debug
[D_OUTPUT
]) {
344 printf("clnp_output: freed old clc_hdr (done)\n");
351 if (argo_debug
[D_OUTPUT
]) {
352 printf("clnp_output: NEW clcp %p\n", clcp
);
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
)) {
370 if (argo_debug
[D_OUTPUT
]) {
371 printf("clnp_output: pkt dropped - option unsupported\n");
379 * Don't allow any invalid flags to be set
381 if ((flags
& (CLNP_VFLAGS
)) != flags
) {
383 if (argo_debug
[D_OUTPUT
]) {
384 printf("clnp_output: packet dropped - flags unsupported\n");
387 INCSTAT(cns_odropped
);
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
))) {
399 INCSTAT(cns_odropped
);
400 return (ENAMETOOLONG
);
403 * Grab mbuf to contain header
405 MGETHDR(m
, M_DONTWAIT
, MT_HEADER
);
408 INCSTAT(cns_odropped
);
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
;
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
)) {
438 if (argo_debug
[D_OUTPUT
]) {
439 printf("clnp_output: calling clnp_srcroute\n");
442 error
= clnp_srcroute(isop
->isop_options
, oidx
, &isop
->isop_route
,
443 &clcp
->clc_firsthop
, &clcp
->clc_ifa
, dst
);
446 if (argo_debug
[D_OUTPUT
]) {
449 error
= clnp_route(dst
, &isop
->isop_route
, flags
,
450 &clcp
->clc_firsthop
, &clcp
->clc_ifa
);
452 if (error
|| (clcp
->clc_ifa
== 0)) {
454 if (argo_debug
[D_OUTPUT
]) {
455 printf("clnp_output: route failed, errno %d\n", error
);
457 dump_buf(clcp
, sizeof(struct clnp_cache
));
462 clcp
->clc_rt
= rtcache_validate(&isop
->isop_route
);/* XXX */
463 clcp
->clc_ifp
= clcp
->clc_ifa
->ia_ifp
; /* XXX */
466 if (argo_debug
[D_OUTPUT
]) {
467 printf("clnp_output: packet routed to %s\n",
469 &satocsiso(clcp
->clc_firsthop
)->siso_addr
));
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
);
481 if (argo_debug
[D_OUTPUT
]) {
482 printf("clnp_output: new src %s\n", clnp_iso_addrp(src
));
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
;
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
);
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
) {
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
) {
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
);
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
,
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);
574 iso_gen_csum(m
, CLNP_CKSUM_OFF
, (int) clnp
->cnf_hdr_len
);
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
;
588 error
= SN_OUTPUT(clcp
, m
);
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
);
602 clnp_stat
.cns_sent
--;
603 clnp_stat
.cns_odropped
++;