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