date and time created 88/12/14 15:29:39 by sklower
[unix-history] / usr / src / sys / netiso / clnp_subr.c
CommitLineData
e832ea14
KS
1/***********************************************************
2 Copyright IBM Corporation 1987
3
4 All Rights Reserved
5
6Permission to use, copy, modify, and distribute this software and its
7documentation for any purpose and without fee is hereby granted,
8provided that the above copyright notice appear in all copies and that
9both that copyright notice and this permission notice appear in
10supporting documentation, and that the name of IBM not be
11used in advertising or publicity pertaining to distribution of the
12software without specific, written prior permission.
13
14IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20SOFTWARE.
21
22******************************************************************/
23
24/*
25 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
26 */
27/* $Header: clnp_subr.c,v 4.10 88/09/14 11:31:33 hagens Exp $ */
28/* $Source: /usr/argo/sys/netiso/RCS/clnp_subr.c,v $ */
29
30#ifndef lint
31static char *rcsid = "$Header: clnp_subr.c,v 4.10 88/09/14 11:31:33 hagens Exp $";
32#endif lint
33
34#ifdef ISO
35
36#include "../h/types.h"
37#include "../h/param.h"
38#include "../h/mbuf.h"
39#include "../h/domain.h"
40#include "../h/protosw.h"
41#include "../h/socket.h"
42#include "../h/socketvar.h"
43#include "../h/errno.h"
44#include "../h/time.h"
45
46#include "../net/if.h"
47#include "../net/route.h"
48
49#include "../netiso/iso.h"
50#include "../netiso/iso_var.h"
51#include "../netiso/clnp.h"
52#include "../netiso/clnp_stat.h"
53#include "../netiso/argo_debug.h"
54#include "../netiso/iso_snpac.h"
55
56/*
57 * FUNCTION: clnp_data_ck
58 *
59 * PURPOSE: Check that the amount of data in the mbuf chain is
60 * at least as much as the clnp header would have us
61 * expect. Trim mbufs if longer than expected, drop
62 * packet if shorter than expected.
63 *
64 * RETURNS: success - ptr to mbuf chain
65 * failure - 0
66 *
67 * SIDE EFFECTS:
68 *
69 * NOTES:
70 */
71struct mbuf *
72clnp_data_ck(m, length)
73register struct mbuf *m; /* ptr to mbuf chain containing hdr & data */
74int length; /* length (in bytes) of packet */
75 {
76 register int len; /* length of data */
77 register struct mbuf *mhead; /* ptr to head of chain */
78
79 len = -length;
80 mhead = m;
81 for (;;) {
82 len += m->m_len;
83 if (m->m_next == 0)
84 break;
85 m = m->m_next;
86 }
87 if (len != 0) {
88 if (len < 0) {
89 INCSTAT(cns_toosmall);
90 clnp_discard(mhead, GEN_INCOMPLETE);
91 return 0;
92 }
93 if (len <= m->m_len)
94 m->m_len -= len;
95 else
96 m_adj(mhead, -len);
97 }
98 return mhead;
99}
100
101#ifdef ndef
102/*
103 * FUNCTION: clnp_extract_addr
104 *
105 * PURPOSE: Extract the source and destination address from the
106 * supplied buffer. Place them in the supplied address buffers.
107 * If insufficient data is supplied, then fail.
108 *
109 * RETURNS: success - Address of first byte in the packet past
110 * the address part.
111 * failure - 0
112 *
113 * SIDE EFFECTS:
114 *
115 * NOTES:
116 */
117caddr_t
118clnp_extract_addr(bufp, buflen, srcp, destp)
119caddr_t bufp; /* ptr to buffer containing addresses */
120int buflen; /* length of buffer */
121register struct iso_addr *srcp; /* ptr to source address buffer */
122register struct iso_addr *destp; /* ptr to destination address buffer */
123 {
124 int len; /* argument to bcopy */
125
126 /*
127 * check that we have enough data. Plus1 is for length octet
128 */
129 if ((u_char)*bufp + 1 > buflen) {
130 return((caddr_t)0);
131 }
132 len = destp->isoa_len = (u_char)*bufp++;
133 (void) bcopy(bufp, (caddr_t)destp, len);
134 buflen -= len;
135 bufp += len;
136
137 /*
138 * check that we have enough data. Plus1 is for length octet
139 */
140 if ((u_char)*bufp + 1 > buflen) {
141 return((caddr_t)0);
142 }
143 len = srcp->isoa_len = (u_char)* bufp++;
144 (void) bcopy(bufp, (caddr_t)srcp, len);
145 bufp += len;
146
147 /*
148 * Insure that the addresses make sense
149 */
150 if (iso_ck_addr(srcp) && iso_ck_addr(destp))
151 return bufp;
152 else
153 return (caddr_t) 0;
154}
155#endif ndef
156
157/*
158 * FUNCTION: clnp_ours
159 *
160 * PURPOSE: Decide whether the supplied packet is destined for
161 * us, or that it should be forwarded on.
162 *
163 * RETURNS: packet is for us - 1
164 * packet is not for us - 0
165 *
166 * SIDE EFFECTS:
167 *
168 * NOTES:
169 */
170clnp_ours(dst)
171register struct iso_addr *dst; /* ptr to destination address */
172{
173 register struct iso_ifaddr *ia; /* scan through interface addresses */
174
175 for (ia = iso_ifaddr; ia; ia = ia->ia_next) {
176 IFDEBUG(D_ROUTE)
177 printf("clnp_ours: ia_sis x%x, dst x%x\n", &IA_SIS(ia)->siso_addr,
178 dst);
179 ENDDEBUG
180 /* PHASE 2: uses iso_addrmatch & mask from iso_ifaddr */
181 if (iso_addrmatch1(&IA_SIS(ia)->siso_addr, dst))
182 return 1;
183 }
184 return 0;
185}
186
187/*
188 * FUNCTION: clnp_forward
189 *
190 * PURPOSE: Forward the datagram passed
191 * clnpintr guarantees that the header will be
192 * contigious (a cluster mbuf will be used if necessary).
193 *
194 * If oidx is NULL, no options are present.
195 *
196 * RETURNS: nothing
197 *
198 * SIDE EFFECTS:
199 *
200 * NOTES:
201 */
202clnp_forward(m, len, dst, oidx, seg_off, inbound_shp)
203struct mbuf *m; /* pkt to forward */
204int len; /* length of pkt */
205struct iso_addr *dst; /* destination address */
206struct clnp_optidx *oidx; /* option index */
207int seg_off;/* offset of segmentation part */
208struct snpa_hdr *inbound_shp; /* subnetwork header of inbound packet */
209{
210 struct clnp_fixed *clnp; /* ptr to fixed part of header */
211 int error; /* return value of route function */
212 struct sockaddr *next_hop; /* next hop for dgram */
213 struct ifnet *ifp; /* ptr to outgoing interface */
214 struct route route; /* filled in by clnp_route */
215 extern int iso_systype;
216
217 clnp = mtod(m, struct clnp_fixed *);
218 bzero((caddr_t)&route, sizeof(route)); /* MUST be done before "bad:" */
219
220 /*
221 * Don't forward multicast or broadcast packets
222 */
223 if ((inbound_shp) && (IS_MULTICAST(inbound_shp->snh_dhost))) {
224 IFDEBUG(D_FORWARD)
225 printf("clnp_forward: dropping multicast packet\n");
226 ENDDEBUG
227 clnp->cnf_err_ok = 0; /* so we don't generate an ER */
228 clnp_discard(m, 0);
229 goto done;
230 }
231
232 IFDEBUG(D_FORWARD)
233 printf("clnp_forward: %d bytes, to %s, options x%x\n", len,
234 clnp_iso_addrp(dst), oidx);
235 ENDDEBUG
236
237 /*
238 * Decrement ttl, and if zero drop datagram
239 * Can't compare ttl as less than zero 'cause its a unsigned
240 */
241 if ((clnp->cnf_ttl == 0) || (--clnp->cnf_ttl == 0)) {
242 IFDEBUG(D_FORWARD)
243 printf("clnp_forward: discarding datagram because ttl is zero\n");
244 ENDDEBUG
245 INCSTAT(cns_ttlexpired);
246 clnp_discard(m, TTL_EXPTRANSIT);
247 goto done;
248 }
249
250 /*
251 * Route packet; special case for source rt
252 */
253 if CLNPSRCRT_VALID(oidx) {
254 /*
255 * Update src route first
256 */
257 clnp_update_srcrt(m, oidx);
258 error = clnp_srcroute(m, oidx, &route, &next_hop, &ifp, dst);
259 } else {
260 error = clnp_route(dst, &route, 0, &next_hop, &ifp);
261 }
262 if (error) {
263 IFDEBUG(D_FORWARD)
264 printf("clnp_forward: can't route packet (errno %d)\n", error);
265 ENDDEBUG
266 clnp_discard(m, ADDR_DESTUNREACH);
267 goto done;
268 }
269
270 IFDEBUG(D_FORWARD)
271 printf("clnp_forward: packet routed to %s\n",
272 clnp_iso_addrp(&((struct sockaddr_iso *)next_hop)->siso_addr));
273 ENDDEBUG
274
275 INCSTAT(cns_forward);
276
277 /*
278 * If we are an intermediate system and
279 * we are routing outbound on the same ifp that the packet
280 * arrived upon, and we know the next hop snpa,
281 * then generate a redirect request
282 */
283 if ((iso_systype & SNPA_IS) && (inbound_shp) &&
284 (ifp == inbound_shp->snh_ifp)) {
285 struct snpa_cache *sc;
286
287 sc = snpac_look(&((struct sockaddr_iso *)next_hop)->siso_addr);
288 if (sc != NULL) {
289 esis_rdoutput(inbound_shp, m, oidx, dst, sc);
290 }
291 }
292
293 /*
294 * If options are present, update them
295 */
296 if (oidx) {
297 struct iso_addr *mysrc =
298 clnp_srcaddr(ifp, &((struct sockaddr_iso *)next_hop)->siso_addr);
299 if (mysrc == NULL) {
300 clnp_discard(m, ADDR_DESTUNREACH);
301 goto done;
302 } else {
303 (void) clnp_dooptions(m, oidx, ifp, mysrc);
304 }
305 }
306
307 /*
308 * Dispatch the datagram if it is small enough, otherwise fragment
309 */
310 if (len <= SN_MTU(ifp)) {
311 iso_gen_csum(m, CLNP_CKSUM_OFF, (int)clnp->cnf_hdr_len);
312 (void) (*ifp->if_output)(ifp, m, next_hop);
313 } else {
314 (void) clnp_fragment(ifp, m, next_hop, len, seg_off, /* flags */0);
315 }
316
317done:
318 /*
319 * Free route
320 */
321 if (route.ro_rt != NULL) {
322 RTFREE(route.ro_rt);
323 }
324}
325
326#ifdef ndef
327/*
328 * FUNCTION: clnp_insert_addr
329 *
330 * PURPOSE: Insert the address part into a clnp datagram.
331 *
332 * RETURNS: Address of first byte after address part in datagram.
333 *
334 * SIDE EFFECTS:
335 *
336 * NOTES: Assume that there is enough space for the address part.
337 */
338caddr_t
339clnp_insert_addr(bufp, srcp, dstp)
340caddr_t bufp; /* address of where addr part goes */
341register struct iso_addr *srcp; /* ptr to src addr */
342register struct iso_addr *dstp; /* ptr to dst addr */
343{
344 *bufp++ = dstp->isoa_len;
345 (void) bcopy((caddr_t)dstp, bufp, dstp->isoa_len);
346 bufp += dstp->isoa_len;
347
348 *bufp++ = srcp->isoa_len;
349 (void) bcopy((caddr_t)srcp, bufp, srcp->isoa_len);
350 bufp += srcp->isoa_len;
351
352 return bufp;
353}
354
355#endif ndef
356
357/*
358 * FUNCTION: clnp_route
359 *
360 * PURPOSE: Route a clnp datagram to the first hop toward its
361 * destination. In many cases, the first hop will be
362 * the destination. The address of a route
363 * is specified. If a routing entry is present in
364 * that route, and it is still up to the same destination,
365 * then no further action is necessary. Otherwise, a
366 * new routing entry will be allocated.
367 *
368 * RETURNS: route found - 0
369 * unix error code
370 *
371 * SIDE EFFECTS:
372 *
373 * NOTES: It is up to the caller to free the routing entry
374 * allocated in route.
375 */
376clnp_route(dst, ro, flags, first_hop, ifp)
377struct iso_addr *dst; /* ptr to datagram destination */
378struct route *ro; /* existing route structure */
379int flags; /* flags for routing */
380struct sockaddr **first_hop; /* result: fill in with ptr to firsthop */
381struct ifnet **ifp; /* result: fill in with ptr to interface */
382{
383 register struct sockaddr_iso *ro_dst; /* ptr to route's destination */
384
385 ro_dst = (struct sockaddr_iso *)&ro->ro_dst;
386
387 /*
388 * If there is a cached route, check that it is still up and to
389 * the same destination. If not, free it and try again.
390 */
391 if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
392 (!iso_addrmatch1(&ro_dst->siso_addr, dst)))) {
393 IFDEBUG(D_ROUTE)
394 printf("clnp_route: freeing old route: ro->ro_rt 0x%x\n",
395 ro->ro_rt);
396 printf("clnp_route: old route refcnt: 0x%x\n",
397 ro->ro_rt->rt_refcnt);
398 ENDDEBUG
399
400 /* free old route entry */
401 RTFREE(ro->ro_rt);
402 ro->ro_rt = (struct rtentry *)0;
403 } else {
404 IFDEBUG(D_ROUTE)
405 printf("clnp_route: OK route exists\n");
406 ENDDEBUG
407 }
408
409 if (ro->ro_rt == 0) {
410 /* set up new route structure */
411 ro_dst->siso_family = AF_ISO;
412 ro_dst->siso_addr = *dst;
413
414 /* allocate new route */
415 IFDEBUG(D_ROUTE)
416 printf("clnp_route: allocating new route to %s\n",
417 clnp_iso_addrp(dst));
418 ENDDEBUG
419 rtalloc(ro);
420 }
421
422 if ((ro->ro_rt == 0) || ((*ifp = ro->ro_rt->rt_ifp) == 0)) {
423 return(ENETUNREACH); /* rtalloc failed */
424 }
425
426 ro->ro_rt->rt_use++;
427 if (ro->ro_rt->rt_flags & (RTF_GATEWAY|RTF_HOST))
428 *first_hop = &ro->ro_rt->rt_gateway;
429 else
430 *first_hop = (struct sockaddr *)ro_dst;
431
432 return(0);
433}
434
435/*
436 * FUNCTION: clnp_srcroute
437 *
438 * PURPOSE: Source route the datagram. If complete source
439 * routing is specified but not possible, then
440 * return an error. If src routing is terminated, then
441 * try routing on destination.
442 * Usage of first_hop,
443 * ifp, and error return is identical to clnp_route.
444 *
445 * RETURNS: 0 or unix error code
446 *
447 * SIDE EFFECTS:
448 *
449 * NOTES: Remember that option index pointers are really
450 * offsets from the beginning of the mbuf.
451 */
452clnp_srcroute(options, oidx, route, first_hop, ifp, final_dst)
453struct mbuf *options; /* ptr to options */
454struct clnp_optidx *oidx; /* index to options */
455struct route *route; /* route structure */
456struct sockaddr **first_hop; /* RETURN: fill in with ptr to firsthop */
457struct ifnet **ifp; /* RETURN: fill in with ptr to interface */
458struct iso_addr *final_dst; /* final destination */
459{
460 struct iso_addr dst; /* first hop specified by src rt */
461 int error = 0; /* return code */
462
463 /*
464 * Check if we have run out of routes
465 * If so, then try to route on destination.
466 */
467 if CLNPSRCRT_TERM(oidx, options) {
468 dst.isoa_len = final_dst->isoa_len;
469 bcopy((caddr_t)final_dst, (caddr_t)&dst, dst.isoa_len);
470 } else {
471 /*
472 * setup dst based on src rt specified
473 */
474 dst.isoa_len = CLNPSRCRT_CLEN(oidx, options);
475 bcopy(CLNPSRCRT_CADDR(oidx, options), (caddr_t)&dst, dst.isoa_len);
476 }
477
478 /*
479 * try to route it
480 */
481 error = clnp_route(&dst, route, 0, first_hop, ifp);
482 if (error != 0)
483 return error;
484
485 /*
486 * If complete src rt, first hop must be equal to dst
487 */
488 if ((CLNPSRCRT_TYPE(oidx, options) == CLNPOVAL_COMPRT) &&
489 (!iso_addrmatch1(&(*(struct sockaddr_iso **)first_hop)->siso_addr,&dst))){
490 IFDEBUG(D_OPTIONS)
491 printf("clnp_srcroute: complete src route failed\n");
492 ENDDEBUG
493 return EHOSTUNREACH; /* RAH? would like ESRCRTFAILED */
494 }
495
496 return error;
497}
498
499/*
500 * FUNCTION: clnp_srcaddr
501 *
502 * PURPOSE: Build the correct source address for a datagram based on the
503 * outgoing interface and firsthop. The firsthop information
504 * is needed inorder to decide which addr to use if
505 * >1 ISO addr is present for an ifp.
506 *
507 * RETURNS: a ptr to a static copy of the source address.
508 * or NULL
509 *
510 * SIDE EFFECTS:
511 *
512 * NOTES: The ifp must be valid, or we will return NULL
513 */
514static struct iso_addr mysrc;
515struct iso_addr *
516clnp_srcaddr(ifp, firsthop)
517struct ifnet *ifp; /* ptr to interface to send packet on */
518struct iso_addr *firsthop; /* ptr to first hop for packet */
519{
520 register struct iso_ifaddr *ia; /* scan through interface addresses */
521 struct iso_addr *maybe = NULL;
522
523 for (ia = iso_ifaddr; ia; ia = ia->ia_next) {
524 if (ia->ia_ifp == ifp) {
525 struct iso_addr *isoa = &IA_SIS(ia)->siso_addr;
526
527 IFDEBUG(D_ROUTE)
528 printf("clnp_srcaddr: isoa is %s\n", clnp_iso_addrp(isoa));
529 ENDDEBUG
530
531 if (iso_eqtype(isoa, firsthop)) {
532 mysrc.isoa_len = isoa->isoa_len;
533 bcopy((caddr_t)isoa, (caddr_t)&mysrc, mysrc.isoa_len);
534 return(&mysrc);
535 } else
536 maybe = isoa;
537 }
538 }
539
540 if (maybe != NULL) {
541 mysrc.isoa_len = maybe->isoa_len;
542 bcopy((caddr_t)maybe, (caddr_t)&mysrc, mysrc.isoa_len);
543 return(&mysrc);
544 } else {
545 /*
546 * This will only happen if there are routes involving
547 * an interface that has just had all iso addresses deleted
548 * from it. This will happen if esisd has added a default
549 * route to an interface, and then the interface was
550 * marked down. As soon as esisd tries to send a pdu on that
551 * interface, it will discover it is down, and remove the
552 * route. Nonetheless, there is a window for this discrepancy,
553 * so we will return null here rather than panicing.
554 */
555 return(NULL);
556 }
557}
558
559/*
560 * FUNCTION: clnp_ypocb - backwards bcopy
561 *
562 * PURPOSE: bcopy starting at end of src rather than beginning.
563 *
564 * RETURNS: none
565 *
566 * SIDE EFFECTS:
567 *
568 * NOTES: No attempt has been made to make this efficient
569 */
570clnp_ypocb(from, to, len)
571caddr_t from; /* src buffer */
572caddr_t to; /* dst buffer */
573u_int len; /* number of bytes */
574{
575 while (len--)
576 *(to + len) = *(from + len);
577}
578
579/*
580 * FUNCTION: clnp_hdrsize
581 *
582 * PURPOSE: Return the size of a typical clnp hdr.
583 *
584 * RETURNS: Size of hdr in bytes.
585 *
586 * SIDE EFFECTS:
587 *
588 * NOTES: Assumes segmenting subset. If addrlen is
589 * zero, default to largest nsap address size.
590 */
591clnp_hdrsize(addrlen)
592u_char addrlen; /* length of nsap address */
593{
594 if (addrlen == 0)
595 addrlen = 20;
596
597 addrlen++; /* length of address byte */
598 addrlen *= 2; /* src and dst addresses */
599 addrlen += sizeof(struct clnp_fixed) + sizeof(struct clnp_segment);
600
601 return(addrlen);
602}
603#endif ISO