]>
git.saurik.com Git - apple/xnu.git/blob - bsd/netiso/clnp_subr.c
11e1ad7423ca757660050597daecdcc9bce018ac
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright (c) 1991, 1993
24 * The Regents of the University of California. All rights reserved.
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions
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.
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
54 * @(#)clnp_subr.c 8.1 (Berkeley) 6/10/93
57 /***********************************************************
58 Copyright IBM Corporation 1987
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.
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
78 ******************************************************************/
81 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
86 #include <sys/param.h>
88 #include <sys/domain.h>
89 #include <sys/protosw.h>
90 #include <sys/socket.h>
91 #include <sys/socketvar.h>
92 #include <sys/errno.h>
96 #include <net/route.h>
97 #include <net/if_dl.h>
99 #include <netiso/iso.h>
100 #include <netiso/iso_var.h>
101 #include <netiso/iso_pcb.h>
102 #include <netiso/iso_snpac.h>
103 #include <netiso/clnp.h>
104 #include <netiso/clnp_stat.h>
105 #include <netiso/argo_debug.h>
108 * FUNCTION: clnp_data_ck
110 * PURPOSE: Check that the amount of data in the mbuf chain is
111 * at least as much as the clnp header would have us
112 * expect. Trim mbufs if longer than expected, drop
113 * packet if shorter than expected.
115 * RETURNS: success - ptr to mbuf chain
123 clnp_data_ck(m
, length
)
124 register struct mbuf
*m
; /* ptr to mbuf chain containing hdr & data */
125 int length
; /* length (in bytes) of packet */
127 register int len
; /* length of data */
128 register struct mbuf
*mhead
; /* ptr to head of chain */
140 INCSTAT(cns_toosmall
);
141 clnp_discard(mhead
, GEN_INCOMPLETE
);
154 * FUNCTION: clnp_extract_addr
156 * PURPOSE: Extract the source and destination address from the
157 * supplied buffer. Place them in the supplied address buffers.
158 * If insufficient data is supplied, then fail.
160 * RETURNS: success - Address of first byte in the packet past
169 clnp_extract_addr(bufp
, buflen
, srcp
, destp
)
170 caddr_t bufp
; /* ptr to buffer containing addresses */
171 int buflen
; /* length of buffer */
172 register struct iso_addr
*srcp
; /* ptr to source address buffer */
173 register struct iso_addr
*destp
; /* ptr to destination address buffer */
175 int len
; /* argument to bcopy */
178 * check that we have enough data. Plus1 is for length octet
180 if ((u_char
)*bufp
+ 1 > buflen
) {
183 len
= destp
->isoa_len
= (u_char
)*bufp
++;
184 (void) bcopy(bufp
, (caddr_t
)destp
, len
);
189 * check that we have enough data. Plus1 is for length octet
191 if ((u_char
)*bufp
+ 1 > buflen
) {
194 len
= srcp
->isoa_len
= (u_char
)* bufp
++;
195 (void) bcopy(bufp
, (caddr_t
)srcp
, len
);
199 * Insure that the addresses make sense
201 if (iso_ck_addr(srcp
) && iso_ck_addr(destp
))
209 * FUNCTION: clnp_ours
211 * PURPOSE: Decide whether the supplied packet is destined for
212 * us, or that it should be forwarded on.
214 * RETURNS: packet is for us - 1
215 * packet is not for us - 0
222 register struct iso_addr
*dst
; /* ptr to destination address */
224 register struct iso_ifaddr
*ia
; /* scan through interface addresses */
226 for (ia
= iso_ifaddr
; ia
; ia
= ia
->ia_next
) {
228 printf("clnp_ours: ia_sis x%x, dst x%x\n", &ia
->ia_addr
,
233 * We are overloading siso_tlen in the if's address, as an nsel length.
235 if (dst
->isoa_len
== ia
->ia_addr
.siso_nlen
&&
236 bcmp((caddr_t
)ia
->ia_addr
.siso_addr
.isoa_genaddr
,
237 (caddr_t
)dst
->isoa_genaddr
,
238 ia
->ia_addr
.siso_nlen
- ia
->ia_addr
.siso_tlen
) == 0)
244 /* Dec bit set if ifp qlen is greater than congest_threshold */
245 int congest_threshold
= 0;
248 * FUNCTION: clnp_forward
250 * PURPOSE: Forward the datagram passed
251 * clnpintr guarantees that the header will be
252 * contigious (a cluster mbuf will be used if necessary).
254 * If oidx is NULL, no options are present.
262 clnp_forward(m
, len
, dst
, oidx
, seg_off
, inbound_shp
)
263 struct mbuf
*m
; /* pkt to forward */
264 int len
; /* length of pkt */
265 struct iso_addr
*dst
; /* destination address */
266 struct clnp_optidx
*oidx
; /* option index */
267 int seg_off
;/* offset of segmentation part */
268 struct snpa_hdr
*inbound_shp
; /* subnetwork header of inbound packet */
270 struct clnp_fixed
*clnp
; /* ptr to fixed part of header */
271 int error
; /* return value of route function */
272 struct sockaddr
*next_hop
; /* next hop for dgram */
273 struct ifnet
*ifp
; /* ptr to outgoing interface */
274 struct iso_ifaddr
*ia
= 0;/* ptr to iso name for ifp */
275 struct route_iso route
; /* filled in by clnp_route */
276 extern int iso_systype
;
278 clnp
= mtod(m
, struct clnp_fixed
*);
279 bzero((caddr_t
)&route
, sizeof(route
)); /* MUST be done before "bad:" */
282 * Don't forward multicast or broadcast packets
284 if ((inbound_shp
) && (IS_MULTICAST(inbound_shp
->snh_dhost
))) {
286 printf("clnp_forward: dropping multicast packet\n");
288 clnp
->cnf_type
&= ~CNF_ERR_OK
; /* so we don't generate an ER */
290 INCSTAT(cns_cantforward
);
295 printf("clnp_forward: %d bytes, to %s, options x%x\n", len
,
296 clnp_iso_addrp(dst
), oidx
);
300 * Decrement ttl, and if zero drop datagram
301 * Can't compare ttl as less than zero 'cause its a unsigned
303 if ((clnp
->cnf_ttl
== 0) || (--clnp
->cnf_ttl
== 0)) {
305 printf("clnp_forward: discarding datagram because ttl is zero\n");
307 INCSTAT(cns_ttlexpired
);
308 clnp_discard(m
, TTL_EXPTRANSIT
);
312 * Route packet; special case for source rt
314 if CLNPSRCRT_VALID(oidx
) {
316 * Update src route first
318 clnp_update_srcrt(m
, oidx
);
319 error
= clnp_srcroute(m
, oidx
, &route
, &next_hop
, &ia
, dst
);
321 error
= clnp_route(dst
, &route
, 0, &next_hop
, &ia
);
323 if (error
|| ia
== 0) {
325 printf("clnp_forward: can't route packet (errno %d)\n", error
);
327 clnp_discard(m
, ADDR_DESTUNREACH
);
328 INCSTAT(cns_cantforward
);
334 printf("clnp_forward: packet routed to %s\n",
335 clnp_iso_addrp(&((struct sockaddr_iso
*)next_hop
)->siso_addr
));
338 INCSTAT(cns_forward
);
341 * If we are an intermediate system and
342 * we are routing outbound on the same ifp that the packet
343 * arrived upon, and we know the next hop snpa,
344 * then generate a redirect request
346 if ((iso_systype
& SNPA_IS
) && (inbound_shp
) &&
347 (ifp
== inbound_shp
->snh_ifp
))
348 esis_rdoutput(inbound_shp
, m
, oidx
, dst
, route
.ro_rt
);
350 * If options are present, update them
353 struct iso_addr
*mysrc
= &ia
->ia_addr
.siso_addr
;
355 clnp_discard(m
, ADDR_DESTUNREACH
);
356 INCSTAT(cns_cantforward
);
357 clnp_stat
.cns_forward
--;
360 (void) clnp_dooptions(m
, oidx
, ifp
, mysrc
);
365 if (ifp
->if_snd
.ifq_len
> congest_threshold
) {
367 * Congestion! Set the Dec Bit and thank Dave Oran
370 printf("clnp_forward: congestion experienced\n");
372 if ((oidx
) && (oidx
->cni_qos_formatp
)) {
373 caddr_t qosp
= CLNP_OFFTOOPT(m
, oidx
->cni_qos_formatp
);
376 printf("clnp_forward: setting congestion bit (qos x%x)\n", qos
);
378 if ((qos
& CLNPOVAL_GLOBAL
) == CLNPOVAL_GLOBAL
) {
379 qos
|= CLNPOVAL_CONGESTED
;
380 INCSTAT(cns_congest_set
);
388 * Dispatch the datagram if it is small enough, otherwise fragment
390 if (len
<= SN_MTU(ifp
, route
.ro_rt
)) {
391 iso_gen_csum(m
, CLNP_CKSUM_OFF
, (int)clnp
->cnf_hdr_len
);
392 (void) (*ifp
->if_output
)(ifp
, m
, next_hop
, route
.ro_rt
);
394 (void) clnp_fragment(ifp
, m
, next_hop
, len
, seg_off
, /* flags */0, route
.ro_rt
);
401 if (route
.ro_rt
!= NULL
) {
408 * FUNCTION: clnp_insert_addr
410 * PURPOSE: Insert the address part into a clnp datagram.
412 * RETURNS: Address of first byte after address part in datagram.
416 * NOTES: Assume that there is enough space for the address part.
419 clnp_insert_addr(bufp
, srcp
, dstp
)
420 caddr_t bufp
; /* address of where addr part goes */
421 register struct iso_addr
*srcp
; /* ptr to src addr */
422 register struct iso_addr
*dstp
; /* ptr to dst addr */
424 *bufp
++ = dstp
->isoa_len
;
425 (void) bcopy((caddr_t
)dstp
, bufp
, dstp
->isoa_len
);
426 bufp
+= dstp
->isoa_len
;
428 *bufp
++ = srcp
->isoa_len
;
429 (void) bcopy((caddr_t
)srcp
, bufp
, srcp
->isoa_len
);
430 bufp
+= srcp
->isoa_len
;
438 * FUNCTION: clnp_route
440 * PURPOSE: Route a clnp datagram to the first hop toward its
441 * destination. In many cases, the first hop will be
442 * the destination. The address of a route
443 * is specified. If a routing entry is present in
444 * that route, and it is still up to the same destination,
445 * then no further action is necessary. Otherwise, a
446 * new routing entry will be allocated.
448 * RETURNS: route found - 0
453 * NOTES: It is up to the caller to free the routing entry
454 * allocated in route.
456 clnp_route(dst
, ro
, flags
, first_hop
, ifa
)
457 struct iso_addr
*dst
; /* ptr to datagram destination */
458 register struct route_iso
*ro
; /* existing route structure */
459 int flags
; /* flags for routing */
460 struct sockaddr
**first_hop
; /* result: fill in with ptr to firsthop */
461 struct iso_ifaddr
**ifa
; /* result: fill in with ptr to interface */
463 if (flags
& SO_DONTROUTE
) {
464 struct iso_ifaddr
*ia
;
470 bzero((caddr_t
)&ro
->ro_dst
, sizeof(ro
->ro_dst
));
471 bcopy((caddr_t
)dst
, (caddr_t
)&ro
->ro_dst
.siso_addr
,
472 1 + (unsigned)dst
->isoa_len
);
473 ro
->ro_dst
.siso_family
= AF_ISO
;
474 ro
->ro_dst
.siso_len
= sizeof(ro
->ro_dst
);
475 ia
= iso_localifa(&ro
->ro_dst
);
477 return EADDRNOTAVAIL
;
481 *first_hop
= (struct sockaddr
*)&ro
->ro_dst
;
485 * If there is a cached route, check that it is still up and to
486 * the same destination. If not, free it and try again.
488 if (ro
->ro_rt
&& ((ro
->ro_rt
->rt_flags
& RTF_UP
) == 0 ||
489 (Bcmp(ro
->ro_dst
.siso_data
, dst
->isoa_genaddr
, dst
->isoa_len
)))) {
491 printf("clnp_route: freeing old route: ro->ro_rt 0x%x\n",
493 printf("clnp_route: old route refcnt: 0x%x\n",
494 ro
->ro_rt
->rt_refcnt
);
497 /* free old route entry */
499 ro
->ro_rt
= (struct rtentry
*)0;
502 printf("clnp_route: OK route exists\n");
506 if (ro
->ro_rt
== 0) {
507 /* set up new route structure */
508 bzero((caddr_t
)&ro
->ro_dst
, sizeof(ro
->ro_dst
));
509 ro
->ro_dst
.siso_len
= sizeof(ro
->ro_dst
);
510 ro
->ro_dst
.siso_family
= AF_ISO
;
511 Bcopy(dst
, &ro
->ro_dst
.siso_addr
, 1 + dst
->isoa_len
);
512 /* allocate new route */
514 printf("clnp_route: allocating new route to %s\n",
515 clnp_iso_addrp(dst
));
517 rtalloc((struct route
*)ro
);
520 return(ENETUNREACH
); /* rtalloc failed */
523 if ((*ifa
= (struct iso_ifaddr
*)ro
->ro_rt
->rt_ifa
) == 0)
526 if (ro
->ro_rt
->rt_flags
& RTF_GATEWAY
)
527 *first_hop
= ro
->ro_rt
->rt_gateway
;
529 *first_hop
= (struct sockaddr
*)&ro
->ro_dst
;
535 * FUNCTION: clnp_srcroute
537 * PURPOSE: Source route the datagram. If complete source
538 * routing is specified but not possible, then
539 * return an error. If src routing is terminated, then
540 * try routing on destination.
541 * Usage of first_hop,
542 * ifp, and error return is identical to clnp_route.
544 * RETURNS: 0 or unix error code
548 * NOTES: Remember that option index pointers are really
549 * offsets from the beginning of the mbuf.
551 clnp_srcroute(options
, oidx
, ro
, first_hop
, ifa
, final_dst
)
552 struct mbuf
*options
; /* ptr to options */
553 struct clnp_optidx
*oidx
; /* index to options */
554 struct route_iso
*ro
; /* route structure */
555 struct sockaddr
**first_hop
; /* RETURN: fill in with ptr to firsthop */
556 struct iso_ifaddr
**ifa
; /* RETURN: fill in with ptr to interface */
557 struct iso_addr
*final_dst
; /* final destination */
559 struct iso_addr dst
; /* first hop specified by src rt */
560 int error
= 0; /* return code */
563 * Check if we have run out of routes
564 * If so, then try to route on destination.
566 if CLNPSRCRT_TERM(oidx
, options
) {
567 dst
.isoa_len
= final_dst
->isoa_len
;
568 bcopy(final_dst
->isoa_genaddr
, dst
.isoa_genaddr
, dst
.isoa_len
);
571 * setup dst based on src rt specified
573 dst
.isoa_len
= CLNPSRCRT_CLEN(oidx
, options
);
574 bcopy(CLNPSRCRT_CADDR(oidx
, options
), dst
.isoa_genaddr
, dst
.isoa_len
);
580 error
= clnp_route(&dst
, ro
, 0, first_hop
, ifa
);
585 * If complete src rt, first hop must be equal to dst
587 if ((CLNPSRCRT_TYPE(oidx
, options
) == CLNPOVAL_COMPRT
) &&
588 (!iso_addrmatch1(&(*(struct sockaddr_iso
**)first_hop
)->siso_addr
,&dst
))){
590 printf("clnp_srcroute: complete src route failed\n");
592 return EHOSTUNREACH
; /* RAH? would like ESRCRTFAILED */
599 * FUNCTION: clnp_echoreply
601 * PURPOSE: generate an echo reply packet and transmit
603 * RETURNS: result of clnp_output
607 clnp_echoreply(ec_m
, ec_len
, ec_src
, ec_dst
, ec_oidxp
)
608 struct mbuf
*ec_m
; /* echo request */
609 int ec_len
; /* length of ec */
610 struct sockaddr_iso
*ec_src
; /* src of ec */
611 struct sockaddr_iso
*ec_dst
; /* destination of ec (i.e., us) */
612 struct clnp_optidx
*ec_oidxp
; /* options index to ec packet */
614 struct isopcb isopcb
;
615 int flags
= CLNP_NOCACHE
|CLNP_ECHOR
;
618 /* fill in fake isopcb to pass to output function */
619 bzero(&isopcb
, sizeof(isopcb
));
620 isopcb
.isop_laddr
= ec_dst
;
621 isopcb
.isop_faddr
= ec_src
;
623 /* forget copying the options for now. If implemented, need only
624 * copy record route option, but it must be reset to zero length */
626 ret
= clnp_output(ec_m
, &isopcb
, ec_len
, flags
);
629 printf("clnp_echoreply: output returns %d\n", ret
);
635 * FUNCTION: clnp_badmtu
637 * PURPOSE: print notice of route with mtu not initialized.
639 * RETURNS: mtu of ifp.
641 * SIDE EFFECTS: prints notice, slows down system.
643 clnp_badmtu(ifp
, rt
, line
, file
)
644 struct ifnet
*ifp
; /* outgoing interface */
645 struct rtentry
*rt
; /* dst route */
646 int line
; /* where the dirty deed occured */
647 char *file
; /* where the dirty deed occured */
649 printf("sending on route 0x%x with no mtu, line %d of file %s\n",
652 printf("route dst is ");
653 dump_isoaddr(rt_key(rt
));
659 * FUNCTION: clnp_ypocb - backwards bcopy
661 * PURPOSE: bcopy starting at end of src rather than beginning.
667 * NOTES: No attempt has been made to make this efficient
669 clnp_ypocb(from
, to
, len
)
670 caddr_t from
; /* src buffer */
671 caddr_t to
; /* dst buffer */
672 u_int len
; /* number of bytes */
675 *(to
+ len
) = *(from
+ len
);