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