1 /* $NetBSD: clnp_subr.c,v 1.32 2009/03/18 15:14:32 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_subr.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_subr.c,v 1.32 2009/03/18 15:14:32 cegger Exp $");
68 #include <sys/param.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>
76 #include <sys/systm.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
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 */
124 INCSTAT(cns_toosmall
);
125 clnp_discard(mhead
, GEN_INCOMPLETE
);
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
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
160 size_t len
; /* argument to memcpy */
163 * check that we have enough data. Plus1 is for length octet
165 len
= (u_char
)*bufp
++;
168 destp
->isoa_len
= len
;
169 (void)memcpy(destp
, bufp
, len
);
174 * check that we have enough data. Plus1 is for length octet
176 len
= (u_char
)*bufp
++;
179 srcp
->isoa_len
= len
;
180 (void)memcpy(srcp
, bufp
, len
);
184 * Insure that the addresses make sense
186 if (iso_ck_addr(srcp
) && iso_ck_addr(destp
))
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
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
) {
214 if (argo_debug
[D_ROUTE
]) {
215 printf("clnp_ours: ia_sis %p, dst %p\n",
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)
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.
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
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 */
267 extern int iso_systype
;
269 clnp
= mtod(m
, struct clnp_fixed
*);
270 memset((void *) & route
, 0, sizeof(route
)); /* MUST be done before
274 * Don't forward multicast or broadcast packets
276 if ((inbound_shp
) && (IS_MULTICAST(inbound_shp
->snh_dhost
))) {
278 if (argo_debug
[D_FORWARD
]) {
279 printf("clnp_forward: dropping multicast packet\n");
282 clnp
->cnf_type
&= ~CNF_ERR_OK
; /* so we don't generate an ER */
284 INCSTAT(cns_cantforward
);
288 if (argo_debug
[D_FORWARD
]) {
289 printf("clnp_forward: %d bytes, to %s, options %p\n", len
,
290 clnp_iso_addrp(dst
), oidx
);
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)) {
300 if (argo_debug
[D_FORWARD
]) {
301 printf("clnp_forward: discarding datagram because ttl is zero\n");
304 INCSTAT(cns_ttlexpired
);
305 clnp_discard(m
, TTL_EXPTRANSIT
);
309 * Route packet; special case for source rt
314 * Update src route first
316 clnp_update_srcrt(m
, oidx
);
317 error
= clnp_srcroute(m
, oidx
, &route
, &next_hop
, &ia
, dst
);
319 error
= clnp_route(dst
, &route
, 0, &next_hop
, &ia
);
321 if (error
|| ia
== 0) {
323 if (argo_debug
[D_FORWARD
]) {
324 printf("clnp_forward: can't route packet (errno %d)\n", error
);
327 clnp_discard(m
, ADDR_DESTUNREACH
);
328 INCSTAT(cns_cantforward
);
334 if (argo_debug
[D_FORWARD
]) {
335 printf("clnp_forward: packet routed to %s\n",
336 clnp_iso_addrp(&satocsiso(next_hop
)->siso_addr
));
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
355 struct iso_addr
*mysrc
= &ia
->ia_addr
.siso_addr
;
357 clnp_discard(m
, ADDR_DESTUNREACH
);
358 INCSTAT(cns_cantforward
);
359 clnp_stat
.cns_forward
--;
362 (void) clnp_dooptions(m
, oidx
, ifp
, mysrc
);
366 if (ifp
->if_snd
.ifq_len
> congest_threshold
) {
368 * Congestion! Set the Dec Bit and thank Dave Oran
371 if (argo_debug
[D_FORWARD
]) {
372 printf("clnp_forward: congestion experienced\n");
375 if ((oidx
) && (oidx
->cni_qos_formatp
)) {
376 char * qosp
= CLNP_OFFTOOPT(m
, oidx
->cni_qos_formatp
);
379 if (argo_debug
[D_FORWARD
]) {
380 printf("clnp_forward: setting congestion bit (qos x%x)\n", qos
);
383 if ((qos
& CLNPOVAL_GLOBAL
) == CLNPOVAL_GLOBAL
) {
384 qos
|= CLNPOVAL_CONGESTED
;
385 INCSTAT(cns_congest_set
);
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
);
401 (void) clnp_fragment(ifp
, m
, next_hop
, len
, seg_off
, /* flags */ 0, rt
);
408 rtcache_free(&route
);
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.
421 * NOTES: Assume that there is enough space for the address part.
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
;
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
458 * NOTES: It is up to the caller to free the routing entry
459 * allocated in 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
468 struct iso_ifaddr
**ifa
) /* result: fill in with ptr to ifa */
474 struct sockaddr_iso dsti
;
477 if (flags
& SO_DONTROUTE
) {
478 struct iso_ifaddr
*ia
;
480 if ((rc
= sockaddr_iso_init(&u
.dsti
, dst
)) != 0)
482 rtcache_setdst(ro
, &u
.dst
);
484 if (rtcache_getdst(ro
) == NULL
)
485 return EADDRNOTAVAIL
;
486 ia
= iso_localifa(satocsiso(rtcache_getdst(ro
)));
488 return EADDRNOTAVAIL
;
491 if (first_hop
!= NULL
)
492 *first_hop
= rtcache_getdst(ro
);
496 /* set up new route structure */
497 if ((rc
= sockaddr_iso_init(&u
.dsti
, dst
)) != 0)
499 if ((rt
= rtcache_lookup(ro
, &u
.dst
)) == NULL
) {
505 if ((*ifa
= (struct iso_ifaddr
*)rt
->rt_ifa
) == NULL
)
507 if (first_hop
!= NULL
) {
508 if (rt
->rt_flags
& RTF_GATEWAY
)
509 *first_hop
= rt
->rt_gateway
;
511 *first_hop
= rtcache_getdst(ro
);
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
530 * NOTES: Remember that option index pointers are really
531 * offsets from the beginning of the mbuf.
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
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.
552 dst
.isoa_len
= final_dst
->isoa_len
;
553 if (sizeof(dst
.isoa_genaddr
) < (size_t)dst
.isoa_len
)
555 (void)memcpy(dst
.isoa_genaddr
, final_dst
->isoa_genaddr
,
556 (size_t)dst
.isoa_len
);
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
)
564 (void)memcpy(dst
.isoa_genaddr
, CLNPSRCRT_CADDR(oidx
, options
),
565 (size_t)dst
.isoa_len
);
571 error
= clnp_route(&dst
, ro
, 0, first_hop
, ifa
);
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
))) {
581 if (argo_debug
[D_OPTIONS
]) {
582 printf("clnp_srcroute: complete src route failed\n");
585 return EHOSTUNREACH
; /* RAH? would like ESRCRTFAILED */
591 * FUNCTION: clnp_echoreply
593 * PURPOSE: generate an echo reply packet and transmit
595 * RETURNS: result of clnp_output
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
;
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
);
624 if (argo_debug
[D_OUTPUT
]) {
625 printf("clnp_echoreply: output returns %d\n", 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.
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",
650 printf("route dst is ");
651 dump_isoaddr(satocsiso(rt_getkey(rt
)));
657 * FUNCTION: clnp_ypocb - backwards bcopy
659 * PURPOSE: bcopy starting at end of src rather than beginning.
665 * NOTES: No attempt has been made to make this efficient
669 void * from
, /* src buffer */
670 void * to
, /* dst buffer */
671 u_int len
) /* number of bytes */
674 *((char *)to
+ len
) = *((char *)from
+ len
);