Reflow to < 80 chars.
[netbsd-mini2440.git] / sys / netiso / clnp_subr.c
blob8b05bced84859f0322c2ca83dc3d9570c755e828
1 /* $NetBSD: clnp_subr.c,v 1.32 2009/03/18 15:14:32 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_subr.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_subr.c,v 1.32 2009/03/18 15:14:32 cegger Exp $");
64 #include "opt_iso.h"
66 #ifdef ISO
68 #include <sys/param.h>
69 #include <sys/mbuf.h>
70 #include <sys/domain.h>
71 #include <sys/protosw.h>
72 #include <sys/socket.h>
73 #include <sys/socketvar.h>
74 #include <sys/errno.h>
75 #include <sys/time.h>
76 #include <sys/systm.h>
78 #include <net/if.h>
79 #include <net/route.h>
80 #include <net/if_dl.h>
82 #include <netiso/iso.h>
83 #include <netiso/iso_var.h>
84 #include <netiso/iso_pcb.h>
85 #include <netiso/iso_snpac.h>
86 #include <netiso/clnp.h>
87 #include <netiso/clnp_stat.h>
88 #include <netiso/argo_debug.h>
89 #include <netiso/esis.h>
92 * FUNCTION: clnp_data_ck
94 * PURPOSE: Check that the amount of data in the mbuf chain is
95 * at least as much as the clnp header would have us
96 * expect. Trim mbufs if longer than expected, drop
97 * packet if shorter than expected.
99 * RETURNS: success - ptr to mbuf chain
100 * failure - 0
102 * SIDE EFFECTS:
104 * NOTES:
106 struct mbuf *
107 clnp_data_ck(
108 struct mbuf *m, /* ptr to mbuf chain containing hdr & data */
109 int length) /* length (in bytes) of packet */
111 int len; /* length of data */
112 struct mbuf *mhead; /* ptr to head of chain */
114 len = -length;
115 mhead = m;
116 for (;;) {
117 len += m->m_len;
118 if (m->m_next == 0)
119 break;
120 m = m->m_next;
122 if (len != 0) {
123 if (len < 0) {
124 INCSTAT(cns_toosmall);
125 clnp_discard(mhead, GEN_INCOMPLETE);
126 return 0;
128 if (len <= m->m_len)
129 m->m_len -= len;
130 else
131 m_adj(mhead, -len);
133 return mhead;
136 #ifdef notdef
138 * FUNCTION: clnp_extract_addr
140 * PURPOSE: Extract the source and destination address from the
141 * supplied buffer. Place them in the supplied address buffers.
142 * If insufficient data is supplied, then fail.
144 * RETURNS: success - Address of first byte in the packet past
145 * the address part.
146 * failure - 0
148 * SIDE EFFECTS:
150 * NOTES:
152 void *
153 clnp_extract_addr(
154 void * bufp, /* ptr to buffer containing addresses */
155 int buflen, /* length of buffer */
156 struct iso_addr *srcp, /* ptr to source address buffer */
157 struct iso_addr *destp) /* ptr to destination address
158 * buffer */
160 size_t len; /* argument to memcpy */
163 * check that we have enough data. Plus1 is for length octet
165 len = (u_char)*bufp++;
166 if (len > buflen)
167 return NULL;
168 destp->isoa_len = len;
169 (void)memcpy(destp, bufp, len);
170 buflen -= len;
171 bufp += len;
174 * check that we have enough data. Plus1 is for length octet
176 len = (u_char)*bufp++;
177 if (len > buflen)
178 return NULL;
179 srcp->isoa_len = len;
180 (void)memcpy(srcp, bufp, len);
181 bufp += len;
184 * Insure that the addresses make sense
186 if (iso_ck_addr(srcp) && iso_ck_addr(destp))
187 return bufp;
188 else
189 return NULL;
191 #endif /* notdef */
194 * FUNCTION: clnp_ours
196 * PURPOSE: Decide whether the supplied packet is destined for
197 * us, or that it should be forwarded on.
199 * RETURNS: packet is for us - 1
200 * packet is not for us - 0
202 * SIDE EFFECTS:
204 * NOTES:
207 clnp_ours(
208 struct iso_addr *dst) /* ptr to destination address */
210 struct iso_ifaddr *ia; /* scan through interface addresses */
212 for (ia = iso_ifaddr.tqh_first; ia != 0; ia = ia->ia_list.tqe_next) {
213 #ifdef ARGO_DEBUG
214 if (argo_debug[D_ROUTE]) {
215 printf("clnp_ours: ia_sis %p, dst %p\n",
216 &ia->ia_addr, dst);
218 #endif
220 * XXX Warning:
221 * We are overloading siso_tlen in the if's address, as an nsel length.
223 if (dst->isoa_len == ia->ia_addr.siso_nlen &&
224 memcmp((void *) ia->ia_addr.siso_addr.isoa_genaddr,
225 (void *) dst->isoa_genaddr,
226 ia->ia_addr.siso_nlen - ia->ia_addr.siso_tlen) == 0)
227 return 1;
229 return 0;
232 /* Dec bit set if ifp qlen is greater than congest_threshold */
233 int congest_threshold = 0;
236 * FUNCTION: clnp_forward
238 * PURPOSE: Forward the datagram passed
239 * clnpintr guarantees that the header will be
240 * contigious (a cluster mbuf will be used if necessary).
242 * If oidx is NULL, no options are present.
244 * RETURNS: nothing
246 * SIDE EFFECTS:
248 * NOTES:
250 void
251 clnp_forward(
252 struct mbuf *m, /* pkt to forward */
253 int len, /* length of pkt */
254 struct iso_addr *dst, /* destination address */
255 struct clnp_optidx *oidx, /* option index */
256 int seg_off, /* offset of segmentation part */
257 struct snpa_hdr *inbound_shp) /* subnetwork header of inbound
258 * packet */
260 struct clnp_fixed *clnp; /* ptr to fixed part of header */
261 int error; /* return value of route function */
262 const struct sockaddr *next_hop; /* next hop for dgram */
263 struct ifnet *ifp; /* ptr to outgoing interface */
264 struct iso_ifaddr *ia = 0; /* ptr to iso name for ifp */
265 struct route route; /* filled in by clnp_route */
266 struct rtentry *rt;
267 extern int iso_systype;
269 clnp = mtod(m, struct clnp_fixed *);
270 memset((void *) & route, 0, sizeof(route)); /* MUST be done before
271 * "bad:" */
274 * Don't forward multicast or broadcast packets
276 if ((inbound_shp) && (IS_MULTICAST(inbound_shp->snh_dhost))) {
277 #ifdef ARGO_DEBUG
278 if (argo_debug[D_FORWARD]) {
279 printf("clnp_forward: dropping multicast packet\n");
281 #endif
282 clnp->cnf_type &= ~CNF_ERR_OK; /* so we don't generate an ER */
283 clnp_discard(m, 0);
284 INCSTAT(cns_cantforward);
285 goto done;
287 #ifdef ARGO_DEBUG
288 if (argo_debug[D_FORWARD]) {
289 printf("clnp_forward: %d bytes, to %s, options %p\n", len,
290 clnp_iso_addrp(dst), oidx);
292 #endif
295 * Decrement ttl, and if zero drop datagram
296 * Can't compare ttl as less than zero 'cause its a unsigned
298 if ((clnp->cnf_ttl == 0) || (--clnp->cnf_ttl == 0)) {
299 #ifdef ARGO_DEBUG
300 if (argo_debug[D_FORWARD]) {
301 printf("clnp_forward: discarding datagram because ttl is zero\n");
303 #endif
304 INCSTAT(cns_ttlexpired);
305 clnp_discard(m, TTL_EXPTRANSIT);
306 goto done;
309 * Route packet; special case for source rt
311 if CLNPSRCRT_VALID
312 (oidx) {
314 * Update src route first
316 clnp_update_srcrt(m, oidx);
317 error = clnp_srcroute(m, oidx, &route, &next_hop, &ia, dst);
318 } else {
319 error = clnp_route(dst, &route, 0, &next_hop, &ia);
321 if (error || ia == 0) {
322 #ifdef ARGO_DEBUG
323 if (argo_debug[D_FORWARD]) {
324 printf("clnp_forward: can't route packet (errno %d)\n", error);
326 #endif
327 clnp_discard(m, ADDR_DESTUNREACH);
328 INCSTAT(cns_cantforward);
329 goto done;
331 ifp = ia->ia_ifp;
333 #ifdef ARGO_DEBUG
334 if (argo_debug[D_FORWARD]) {
335 printf("clnp_forward: packet routed to %s\n",
336 clnp_iso_addrp(&satocsiso(next_hop)->siso_addr));
338 #endif
340 INCSTAT(cns_forward);
343 * If we are an intermediate system and
344 * we are routing outbound on the same ifp that the packet
345 * arrived upon, and we know the next hop snpa,
346 * then generate a redirect request
348 if ((iso_systype & SNPA_IS) && (inbound_shp) &&
349 (ifp == inbound_shp->snh_ifp))
350 esis_rdoutput(inbound_shp, m, oidx, dst, rtcache_validate(&route));
352 * If options are present, update them
354 if (oidx) {
355 struct iso_addr *mysrc = &ia->ia_addr.siso_addr;
356 if (mysrc == NULL) {
357 clnp_discard(m, ADDR_DESTUNREACH);
358 INCSTAT(cns_cantforward);
359 clnp_stat.cns_forward--;
360 goto done;
361 } else {
362 (void) clnp_dooptions(m, oidx, ifp, mysrc);
365 #ifdef DECBIT
366 if (ifp->if_snd.ifq_len > congest_threshold) {
368 * Congestion! Set the Dec Bit and thank Dave Oran
370 #ifdef ARGO_DEBUG
371 if (argo_debug[D_FORWARD]) {
372 printf("clnp_forward: congestion experienced\n");
374 #endif
375 if ((oidx) && (oidx->cni_qos_formatp)) {
376 char * qosp = CLNP_OFFTOOPT(m, oidx->cni_qos_formatp);
377 u_char qos = *qosp;
378 #ifdef ARGO_DEBUG
379 if (argo_debug[D_FORWARD]) {
380 printf("clnp_forward: setting congestion bit (qos x%x)\n", qos);
382 #endif
383 if ((qos & CLNPOVAL_GLOBAL) == CLNPOVAL_GLOBAL) {
384 qos |= CLNPOVAL_CONGESTED;
385 INCSTAT(cns_congest_set);
386 *qosp = qos;
390 #endif /* DECBIT */
393 * Dispatch the datagram if it is small enough, otherwise fragment
395 if ((rt = rtcache_validate(&route)) == NULL)
397 else if (len <= SN_MTU(ifp, rt)) {
398 iso_gen_csum(m, CLNP_CKSUM_OFF, (int) clnp->cnf_hdr_len);
399 (void) (*ifp->if_output) (ifp, m, next_hop, rt);
400 } else {
401 (void) clnp_fragment(ifp, m, next_hop, len, seg_off, /* flags */ 0, rt);
404 done:
406 * Free route
408 rtcache_free(&route);
411 #ifdef notdef
413 * FUNCTION: clnp_insert_addr
415 * PURPOSE: Insert the address part into a clnp datagram.
417 * RETURNS: Address of first byte after address part in datagram.
419 * SIDE EFFECTS:
421 * NOTES: Assume that there is enough space for the address part.
423 void *
424 clnp_insert_addr(
425 void * bufp, /* address of where addr part goes */
426 struct iso_addr *srcp, /* ptr to src addr */
427 struct iso_addr *dstp) /* ptr to dst addr */
429 *bufp++ = dstp->isoa_len;
430 (void)memcpy(bufp, dstp, dstp->isoa_len);
431 bufp += dstp->isoa_len;
433 *bufp++ = srcp->isoa_len;
434 (void)memcpy(bufp, srcp, srcp->isoa_len);
435 bufp += srcp->isoa_len;
437 return bufp;
440 #endif /* notdef */
443 * FUNCTION: clnp_route
445 * PURPOSE: Route a clnp datagram to the first hop toward its
446 * destination. In many cases, the first hop will be
447 * the destination. The address of a route
448 * is specified. If a routing entry is present in
449 * that route, and it is still up to the same destination,
450 * then no further action is necessary. Otherwise, a
451 * new routing entry will be allocated.
453 * RETURNS: route found - 0
454 * unix error code
456 * SIDE EFFECTS:
458 * NOTES: It is up to the caller to free the routing entry
459 * allocated in route.
462 clnp_route(
463 struct iso_addr *dst, /* ptr to datagram destination */
464 struct route *ro, /* existing route structure */
465 int flags, /* flags for routing */
466 const struct sockaddr **first_hop, /* result: fill in with ptr to
467 * firsthop */
468 struct iso_ifaddr **ifa) /* result: fill in with ptr to ifa */
470 struct rtentry *rt;
471 int rc;
472 union {
473 struct sockaddr dst;
474 struct sockaddr_iso dsti;
475 } u;
477 if (flags & SO_DONTROUTE) {
478 struct iso_ifaddr *ia;
480 if ((rc = sockaddr_iso_init(&u.dsti, dst)) != 0)
481 return rc;
482 rtcache_setdst(ro, &u.dst);
484 if (rtcache_getdst(ro) == NULL)
485 return EADDRNOTAVAIL;
486 ia = iso_localifa(satocsiso(rtcache_getdst(ro)));
487 if (ia == NULL)
488 return EADDRNOTAVAIL;
489 if (ifa != NULL)
490 *ifa = ia;
491 if (first_hop != NULL)
492 *first_hop = rtcache_getdst(ro);
493 return 0;
496 /* set up new route structure */
497 if ((rc = sockaddr_iso_init(&u.dsti, dst)) != 0)
498 return rc;
499 if ((rt = rtcache_lookup(ro, &u.dst)) == NULL) {
500 rtcache_free(ro);
501 return ENETUNREACH;
503 rt->rt_use++;
504 if (ifa != NULL)
505 if ((*ifa = (struct iso_ifaddr *)rt->rt_ifa) == NULL)
506 panic("clnp_route");
507 if (first_hop != NULL) {
508 if (rt->rt_flags & RTF_GATEWAY)
509 *first_hop = rt->rt_gateway;
510 else
511 *first_hop = rtcache_getdst(ro);
513 return 0;
517 * FUNCTION: clnp_srcroute
519 * PURPOSE: Source route the datagram. If complete source
520 * routing is specified but not possible, then
521 * return an error. If src routing is terminated, then
522 * try routing on destination.
523 * Usage of first_hop,
524 * ifp, and error return is identical to clnp_route.
526 * RETURNS: 0 or unix error code
528 * SIDE EFFECTS:
530 * NOTES: Remember that option index pointers are really
531 * offsets from the beginning of the mbuf.
534 clnp_srcroute(
535 struct mbuf *options, /* ptr to options */
536 struct clnp_optidx *oidx, /* index to options */
537 struct route *ro, /* route structure */
538 const struct sockaddr **first_hop, /* RETURN: fill in with ptr to
539 * firsthop */
540 struct iso_ifaddr **ifa, /* RETURN: fill in with ptr to ifa */
541 struct iso_addr *final_dst) /* final destination */
543 struct iso_addr dst; /* first hop specified by src rt */
544 int error = 0; /* return code */
547 * Check if we have run out of routes
548 * If so, then try to route on destination.
550 if CLNPSRCRT_TERM
551 (oidx, options) {
552 dst.isoa_len = final_dst->isoa_len;
553 if (sizeof(dst.isoa_genaddr) < (size_t)dst.isoa_len)
554 return EINVAL;
555 (void)memcpy(dst.isoa_genaddr, final_dst->isoa_genaddr,
556 (size_t)dst.isoa_len);
557 } else {
559 * setup dst based on src rt specified
561 dst.isoa_len = CLNPSRCRT_CLEN(oidx, options);
562 if (sizeof(dst.isoa_genaddr) < (unsigned)dst.isoa_len)
563 return EINVAL;
564 (void)memcpy(dst.isoa_genaddr, CLNPSRCRT_CADDR(oidx, options),
565 (size_t)dst.isoa_len);
569 * try to route it
571 error = clnp_route(&dst, ro, 0, first_hop, ifa);
572 if (error != 0)
573 return error;
576 * If complete src rt, first hop must be equal to dst
578 if ((CLNPSRCRT_TYPE(oidx, options) == CLNPOVAL_COMPRT) &&
579 (!iso_addrmatch1(&satocsiso(*first_hop)->siso_addr, &dst))) {
580 #ifdef ARGO_DEBUG
581 if (argo_debug[D_OPTIONS]) {
582 printf("clnp_srcroute: complete src route failed\n");
584 #endif
585 return EHOSTUNREACH; /* RAH? would like ESRCRTFAILED */
587 return error;
591 * FUNCTION: clnp_echoreply
593 * PURPOSE: generate an echo reply packet and transmit
595 * RETURNS: result of clnp_output
597 * SIDE EFFECTS:
600 clnp_echoreply(
601 struct mbuf *ec_m, /* echo request */
602 int ec_len, /* length of ec */
603 struct sockaddr_iso *ec_src, /* src of ec */
604 struct sockaddr_iso *ec_dst, /* destination of ec (i.e., us) */
605 struct clnp_optidx *ec_oidxp) /* options index to ec packet */
607 struct isopcb isopcb;
608 int flags = CLNP_NOCACHE | CLNP_ECHOR;
609 int ret;
611 /* fill in fake isopcb to pass to output function */
612 memset(&isopcb, 0, sizeof(isopcb));
613 isopcb.isop_laddr = ec_dst;
614 isopcb.isop_faddr = ec_src;
617 * forget copying the options for now. If implemented, need only copy
618 * record route option, but it must be reset to zero length
621 ret = clnp_output(ec_m, &isopcb, ec_len, flags);
623 #ifdef ARGO_DEBUG
624 if (argo_debug[D_OUTPUT]) {
625 printf("clnp_echoreply: output returns %d\n", ret);
627 #endif
628 return ret;
632 * FUNCTION: clnp_badmtu
634 * PURPOSE: print notice of route with mtu not initialized.
636 * RETURNS: mtu of ifp.
638 * SIDE EFFECTS: prints notice, slows down system.
641 clnp_badmtu(
642 struct ifnet *ifp, /* outgoing interface */
643 struct rtentry *rt, /* dst route */
644 int line, /* where the dirty deed occurred */
645 const char *file) /* where the dirty deed occurred */
647 printf("sending on route %p with no mtu, line %d of file %s\n",
648 rt, line, file);
649 #ifdef ARGO_DEBUG
650 printf("route dst is ");
651 dump_isoaddr(satocsiso(rt_getkey(rt)));
652 #endif
653 return ifp->if_mtu;
657 * FUNCTION: clnp_ypocb - backwards bcopy
659 * PURPOSE: bcopy starting at end of src rather than beginning.
661 * RETURNS: none
663 * SIDE EFFECTS:
665 * NOTES: No attempt has been made to make this efficient
667 void
668 clnp_ypocb(
669 void * from, /* src buffer */
670 void * to, /* dst buffer */
671 u_int len) /* number of bytes */
673 while (len--)
674 *((char *)to + len) = *((char *)from + len);
676 #endif /* ISO */