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