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