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