[BACK]Return to awi_wep.c CVS log [TXT][DIR] Up to [local] / sys / dev / ic

Annotation of sys/dev/ic/awi_wep.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: awi_wep.c,v 1.13 2005/02/21 11:16:00 dlg Exp $        */
        !             2: /*     $NetBSD: awi_wep.c,v 1.2 2000/07/04 14:47:58 onoe Exp $ */
        !             3:
        !             4: /*
        !             5:  * Copyright (c) 2000 The NetBSD Foundation, Inc.
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * This code is derived from software contributed to The NetBSD Foundation
        !             9:  * by Atsushi Onoe.
        !            10:  *
        !            11:  * Redistribution and use in source and binary forms, with or without
        !            12:  * modification, are permitted provided that the following conditions
        !            13:  * are met:
        !            14:  * 1. Redistributions of source code must retain the above copyright
        !            15:  *    notice, this list of conditions and the following disclaimer.
        !            16:  * 2. Redistributions in binary form must reproduce the above copyright
        !            17:  *    notice, this list of conditions and the following disclaimer in the
        !            18:  *    documentation and/or other materials provided with the distribution.
        !            19:  * 3. All advertising materials mentioning features or use of this software
        !            20:  *    must display the following acknowledgement:
        !            21:  *     This product includes software developed by the NetBSD
        !            22:  *     Foundation, Inc. and its contributors.
        !            23:  * 4. Neither the name of The NetBSD Foundation nor the names of its
        !            24:  *    contributors may be used to endorse or promote products derived
        !            25:  *    from this software without specific prior written permission.
        !            26:  *
        !            27:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
        !            28:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
        !            29:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
        !            30:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
        !            31:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
        !            32:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
        !            33:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
        !            34:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
        !            35:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
        !            36:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            37:  * POSSIBILITY OF SUCH DAMAGE.
        !            38:  */
        !            39:
        !            40: /*
        !            41:  * WEP support framework for the awi driver.
        !            42:  *
        !            43:  * No actual encryption capability is provided here, but any can be added
        !            44:  * to awi_wep_algo table below.
        !            45:  *
        !            46:  * Note that IEEE802.11 specification states WEP uses RC4 with 40bit key,
        !            47:  * which is a proprietary encryption algorithm available under license
        !            48:  * from RSA Data Security Inc.  Using another algorithm, includes null
        !            49:  * encryption provided here, the awi driver cannot be able to communicate
        !            50:  * with other stations.
        !            51:  */
        !            52:
        !            53: #include <sys/param.h>
        !            54: #include <sys/systm.h>
        !            55: #include <sys/kernel.h>
        !            56: #include <sys/mbuf.h>
        !            57: #include <sys/malloc.h>
        !            58: #include <sys/proc.h>
        !            59: #include <sys/socket.h>
        !            60: #include <sys/errno.h>
        !            61: #include <sys/sockio.h>
        !            62: #if defined(__FreeBSD__) && __FreeBSD__ >= 4
        !            63: #include <sys/bus.h>
        !            64: #else
        !            65: #include <sys/device.h>
        !            66: #endif
        !            67:
        !            68: #include <net/if.h>
        !            69: #include <net/if_dl.h>
        !            70: #ifdef __FreeBSD__
        !            71: #include <net/ethernet.h>
        !            72: #include <net/if_arp.h>
        !            73: #elif defined(__OpenBSD__)
        !            74: #include <netinet/in.h>
        !            75: #include <netinet/if_ether.h>
        !            76: #else
        !            77: #include <net/if_ether.h>
        !            78: #endif
        !            79: #include <net/if_media.h>
        !            80: #include <net80211/ieee80211.h>
        !            81: #include <net80211/ieee80211_ioctl.h>
        !            82:
        !            83: #include <machine/cpu.h>
        !            84: #include <machine/bus.h>
        !            85: #ifdef __FreeBSD__
        !            86: #include <machine/clock.h>
        !            87: #endif
        !            88:
        !            89: #if defined(__NetBSD__) || defined(__OpenBSD__)
        !            90: #include <dev/ic/am79c930reg.h>
        !            91: #include <dev/ic/am79c930var.h>
        !            92: #include <dev/ic/awireg.h>
        !            93: #include <dev/ic/awivar.h>
        !            94: #include <dev/rndvar.h>
        !            95: #endif
        !            96:
        !            97: #ifdef __OpenBSD__
        !            98: #include <dev/rndvar.h>
        !            99: #endif
        !           100:
        !           101: #ifdef __OpenBSD__
        !           102: #include <dev/rndvar.h>
        !           103: #endif
        !           104:
        !           105: #ifdef __NetBSD__
        !           106: #include <crypto/arc4/arc4.h>
        !           107: #endif
        !           108:
        !           109: #ifdef __FreeBSD__
        !           110: #include <dev/awi/am79c930reg.h>
        !           111: #include <dev/awi/am79c930var.h>
        !           112: #include <dev/awi/awireg.h>
        !           113: #include <dev/awi/awivar.h>
        !           114:
        !           115: #include <crypto/rc4/rc4.h>
        !           116: static __inline int
        !           117: arc4_ctxlen(void)
        !           118: {
        !           119:         return sizeof(struct rc4_state);
        !           120: }
        !           121:
        !           122: static __inline void
        !           123: arc4_setkey(void *ctx, u_int8_t *key, int keylen)
        !           124: {
        !           125:        rc4_init(ctx, key, keylen);
        !           126: }
        !           127:
        !           128: static __inline void
        !           129: arc4_encrypt(void *ctx, u_int8_t *dst, u_int8_t *src, int len)
        !           130: {
        !           131:        rc4_crypt(ctx, dst, src, len);
        !           132: }
        !           133: #endif
        !           134:
        !           135: static void awi_crc_init(void);
        !           136: static u_int32_t awi_crc_update(u_int32_t crc, u_int8_t *buf, int len);
        !           137:
        !           138: static int awi_null_ctxlen(void);
        !           139: static void awi_null_setkey(void *ctx, u_int8_t *key, int keylen);
        !           140: static void awi_null_copy(void *ctx, u_int8_t *dst, u_int8_t *src, int len);
        !           141:
        !           142: /* XXX: the order should be known to wiconfig/user */
        !           143:
        !           144: static struct awi_wep_algo awi_wep_algo[] = {
        !           145: /* 0: no wep */
        !           146:        { "no" },       /* dummy for no wep */
        !           147:
        !           148: #if 0
        !           149: /* 1: normal wep (arc4) */
        !           150:        { "arc4", arc4_ctxlen, arc4_setkey,
        !           151:            arc4_encrypt, arc4_encrypt },
        !           152: #endif
        !           153: /* 2: debug wep (null) */
        !           154:        { "null", awi_null_ctxlen, awi_null_setkey,
        !           155:            awi_null_copy, awi_null_copy },
        !           156:                        /* dummy for wep without encryption */
        !           157: };
        !           158:
        !           159: int
        !           160: awi_wep_setnwkey(sc, nwkey)
        !           161:        struct awi_softc *sc;
        !           162:        struct ieee80211_nwkey *nwkey;
        !           163: {
        !           164:        int i, len, error;
        !           165:        u_int8_t keybuf[AWI_MAX_KEYLEN];
        !           166:
        !           167:        if (nwkey->i_defkid <= 0 ||
        !           168:            nwkey->i_defkid > IEEE80211_WEP_NKID)
        !           169:                return EINVAL;
        !           170:        error = 0;
        !           171:        for (i = 0; i < IEEE80211_WEP_NKID; i++) {
        !           172:                if (nwkey->i_key[i].i_keydat == NULL)
        !           173:                        continue;
        !           174:                len = nwkey->i_key[i].i_keylen;
        !           175:                if (len > sizeof(keybuf)) {
        !           176:                        error = EINVAL;
        !           177:                        break;
        !           178:                }
        !           179:                error = copyin(nwkey->i_key[i].i_keydat, keybuf, len);
        !           180:                if (error)
        !           181:                        break;
        !           182:                error = awi_wep_setkey(sc, i, keybuf, len);
        !           183:                if (error)
        !           184:                        break;
        !           185:        }
        !           186:        if (error == 0) {
        !           187:                sc->sc_wep_defkid = nwkey->i_defkid - 1;
        !           188:                error = awi_wep_setalgo(sc, nwkey->i_wepon);
        !           189:                if (error == 0 && sc->sc_enabled) {
        !           190:                        awi_stop(sc);
        !           191:                        error = awi_init(sc);
        !           192:                }
        !           193:        }
        !           194:        return error;
        !           195: }
        !           196:
        !           197: int
        !           198: awi_wep_getnwkey(sc, nwkey)
        !           199:        struct awi_softc *sc;
        !           200:        struct ieee80211_nwkey *nwkey;
        !           201: {
        !           202:        int i, len, error, suerr;
        !           203:        u_int8_t keybuf[AWI_MAX_KEYLEN];
        !           204:
        !           205:        nwkey->i_wepon = awi_wep_getalgo(sc);
        !           206:        nwkey->i_defkid = sc->sc_wep_defkid + 1;
        !           207:        /* do not show any keys to non-root user */
        !           208: #ifdef __FreeBSD__
        !           209:        suerr = suser(curproc);
        !           210: #else
        !           211: #ifdef __OpenBSD__
        !           212:        suerr = suser(curproc, 0);
        !           213: #else
        !           214:        suerr = suser(curproc->p_ucred, &curproc->p_acflag);
        !           215: #endif
        !           216: #endif
        !           217:        error = 0;
        !           218:        for (i = 0; i < IEEE80211_WEP_NKID; i++) {
        !           219:                if (nwkey->i_key[i].i_keydat == NULL)
        !           220:                        continue;
        !           221:                if (suerr) {
        !           222:                        error = suerr;
        !           223:                        break;
        !           224:                }
        !           225:                len = sizeof(keybuf);
        !           226:                error = awi_wep_getkey(sc, i, keybuf, &len);
        !           227:                if (error)
        !           228:                        break;
        !           229:                if (nwkey->i_key[i].i_keylen < len) {
        !           230:                        error = ENOSPC;
        !           231:                        break;
        !           232:                }
        !           233:                nwkey->i_key[i].i_keylen = len;
        !           234:                error = copyout(keybuf, nwkey->i_key[i].i_keydat, len);
        !           235:                if (error)
        !           236:                        break;
        !           237:        }
        !           238:        return error;
        !           239: }
        !           240:
        !           241: int
        !           242: awi_wep_getalgo(sc)
        !           243:        struct awi_softc *sc;
        !           244: {
        !           245:
        !           246:        if (sc->sc_wep_algo == NULL)
        !           247:                return 0;
        !           248:        return sc->sc_wep_algo - awi_wep_algo;
        !           249: }
        !           250:
        !           251: int
        !           252: awi_wep_setalgo(sc, algo)
        !           253:        struct awi_softc *sc;
        !           254:        int algo;
        !           255: {
        !           256:        struct awi_wep_algo *awa;
        !           257:        int ctxlen;
        !           258:
        !           259:        awi_crc_init(); /* XXX: not belongs here */
        !           260:        if (algo < 0 || algo >= sizeof(awi_wep_algo)/sizeof(awi_wep_algo[0]))
        !           261:                return EINVAL;
        !           262:        awa = &awi_wep_algo[algo];
        !           263:        if (awa->awa_name == NULL)
        !           264:                return EINVAL;
        !           265:        if (awa->awa_ctxlen == NULL) {
        !           266:                awa = NULL;
        !           267:                ctxlen = 0;
        !           268:        } else
        !           269:                ctxlen = awa->awa_ctxlen();
        !           270:        if (sc->sc_wep_ctx != NULL) {
        !           271:                free(sc->sc_wep_ctx, M_DEVBUF);
        !           272:                sc->sc_wep_ctx = NULL;
        !           273:        }
        !           274:        if (ctxlen) {
        !           275:                sc->sc_wep_ctx = malloc(ctxlen, M_DEVBUF, M_NOWAIT);
        !           276:                if (sc->sc_wep_ctx == NULL)
        !           277:                        return ENOMEM;
        !           278:        }
        !           279:        sc->sc_wep_algo = awa;
        !           280:        return 0;
        !           281: }
        !           282:
        !           283: int
        !           284: awi_wep_setkey(sc, kid, key, keylen)
        !           285:        struct awi_softc *sc;
        !           286:        int kid;
        !           287:        unsigned char *key;
        !           288:        int keylen;
        !           289: {
        !           290:
        !           291:        if (kid < 0 || kid >= IEEE80211_WEP_NKID)
        !           292:                return EINVAL;
        !           293:        if (keylen < 0 || keylen + IEEE80211_WEP_IVLEN > AWI_MAX_KEYLEN)
        !           294:                return EINVAL;
        !           295:        sc->sc_wep_keylen[kid] = keylen;
        !           296:        if (keylen > 0)
        !           297:                memcpy(sc->sc_wep_key[kid] + IEEE80211_WEP_IVLEN, key, keylen);
        !           298:        return 0;
        !           299: }
        !           300:
        !           301: int
        !           302: awi_wep_getkey(sc, kid, key, keylen)
        !           303:        struct awi_softc *sc;
        !           304:        int kid;
        !           305:        unsigned char *key;
        !           306:        int *keylen;
        !           307: {
        !           308:
        !           309:        if (kid < 0 || kid >= IEEE80211_WEP_NKID)
        !           310:                return EINVAL;
        !           311:        if (*keylen < sc->sc_wep_keylen[kid])
        !           312:                return ENOSPC;
        !           313:        *keylen = sc->sc_wep_keylen[kid];
        !           314:        if (*keylen > 0)
        !           315:                memcpy(key, sc->sc_wep_key[kid] + IEEE80211_WEP_IVLEN, *keylen);
        !           316:        return 0;
        !           317: }
        !           318:
        !           319: struct mbuf *
        !           320: awi_wep_encrypt(sc, m0, txflag)
        !           321:        struct awi_softc *sc;
        !           322:        struct mbuf *m0;
        !           323:        int txflag;
        !           324: {
        !           325:        struct mbuf *m, *n, *n0;
        !           326:        struct ieee80211_frame *wh;
        !           327:        struct awi_wep_algo *awa;
        !           328:        int left, len, moff, noff, keylen, kid;
        !           329:        u_int32_t iv, crc;
        !           330:        u_int8_t *key, *ivp;
        !           331:        void *ctx;
        !           332:        u_int8_t crcbuf[IEEE80211_WEP_CRCLEN];
        !           333:
        !           334:        n0 = NULL;
        !           335:        awa = sc->sc_wep_algo;
        !           336:        if (awa == NULL)
        !           337:                goto fail;
        !           338:        ctx = sc->sc_wep_ctx;
        !           339:        m = m0;
        !           340:        left = m->m_pkthdr.len;
        !           341:        MGET(n, M_DONTWAIT, m->m_type);
        !           342:        n0 = n;
        !           343:        if (n == NULL)
        !           344:                goto fail;
        !           345:        M_DUP_PKTHDR(n, m);
        !           346:        len = IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
        !           347:              IEEE80211_WEP_CRCLEN;
        !           348:        if (txflag) {
        !           349:                n->m_pkthdr.len += len;
        !           350:        } else {
        !           351:                wh = mtod(n, struct ieee80211_frame *);
        !           352:                n->m_pkthdr.len -= len;
        !           353:                left -= len;
        !           354:        }
        !           355:        n->m_len = MHLEN;
        !           356:        if (n->m_pkthdr.len >= MINCLSIZE) {
        !           357:                MCLGET(n, M_DONTWAIT);
        !           358:                if (n->m_flags & M_EXT)
        !           359:                        n->m_len = n->m_ext.ext_size;
        !           360:        }
        !           361:        len = sizeof(struct ieee80211_frame);
        !           362:        memcpy(mtod(n, caddr_t), mtod(m, caddr_t), len);
        !           363:        left -= len;
        !           364:        moff = len;
        !           365:        noff = len;
        !           366:        if (txflag) {
        !           367:                kid = sc->sc_wep_defkid;
        !           368:                wh = mtod(n, struct ieee80211_frame *);
        !           369:                wh->i_fc[1] |= IEEE80211_FC1_WEP;
        !           370:                iv = arc4random();
        !           371:                /*
        !           372:                 * store IV, byte order is not the matter since it's random.
        !           373:                 * assuming IEEE80211_WEP_IVLEN is 3
        !           374:                 */
        !           375:                ivp = mtod(n, u_int8_t *) + noff;
        !           376:                ivp[0] = (iv >> 16) & 0xff;
        !           377:                ivp[1] = (iv >> 8) & 0xff;
        !           378:                ivp[2] = iv & 0xff;
        !           379:                ivp[3] = kid & 0x03;    /* clear pad and keyid */
        !           380:                noff += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN;
        !           381:        } else {
        !           382:                ivp = mtod(m, u_int8_t *) + moff;
        !           383:                moff += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN;
        !           384:                kid = ivp[IEEE80211_WEP_IVLEN] & 0x03;
        !           385:        }
        !           386:        key = sc->sc_wep_key[kid];
        !           387:        keylen = sc->sc_wep_keylen[kid];
        !           388:        /* assuming IEEE80211_WEP_IVLEN is 3 */
        !           389:        key[0] = ivp[0];
        !           390:        key[1] = ivp[1];
        !           391:        key[2] = ivp[2];
        !           392:        awa->awa_setkey(ctx, key, IEEE80211_WEP_IVLEN + keylen);
        !           393:
        !           394:        /* encrypt with calculating CRC */
        !           395:        crc = ~0;
        !           396:        while (left > 0) {
        !           397:                len = m->m_len - moff;
        !           398:                if (len == 0) {
        !           399:                        m = m->m_next;
        !           400:                        moff = 0;
        !           401:                        continue;
        !           402:                }
        !           403:                if (len > n->m_len - noff) {
        !           404:                        len = n->m_len - noff;
        !           405:                        if (len == 0) {
        !           406:                                MGET(n->m_next, M_DONTWAIT, n->m_type);
        !           407:                                if (n->m_next == NULL)
        !           408:                                        goto fail;
        !           409:                                n = n->m_next;
        !           410:                                n->m_len = MLEN;
        !           411:                                if (left >= MINCLSIZE) {
        !           412:                                        MCLGET(n, M_DONTWAIT);
        !           413:                                        if (n->m_flags & M_EXT)
        !           414:                                                n->m_len = n->m_ext.ext_size;
        !           415:                                }
        !           416:                                noff = 0;
        !           417:                                continue;
        !           418:                        }
        !           419:                }
        !           420:                if (len > left)
        !           421:                        len = left;
        !           422:                if (txflag) {
        !           423:                        awa->awa_encrypt(ctx, mtod(n, caddr_t) + noff,
        !           424:                            mtod(m, caddr_t) + moff, len);
        !           425:                        crc = awi_crc_update(crc, mtod(m, caddr_t) + moff, len);
        !           426:                } else {
        !           427:                        awa->awa_decrypt(ctx, mtod(n, caddr_t) + noff,
        !           428:                            mtod(m, caddr_t) + moff, len);
        !           429:                        crc = awi_crc_update(crc, mtod(n, caddr_t) + noff, len);
        !           430:                }
        !           431:                left -= len;
        !           432:                moff += len;
        !           433:                noff += len;
        !           434:        }
        !           435:        crc = ~crc;
        !           436:        if (txflag) {
        !           437:                LE_WRITE_4(crcbuf, crc);
        !           438:                if (n->m_len >= noff + sizeof(crcbuf))
        !           439:                        n->m_len = noff + sizeof(crcbuf);
        !           440:                else {
        !           441:                        n->m_len = noff;
        !           442:                        MGET(n->m_next, M_DONTWAIT, n->m_type);
        !           443:                        if (n->m_next == NULL)
        !           444:                                goto fail;
        !           445:                        n = n->m_next;
        !           446:                        n->m_len = sizeof(crcbuf);
        !           447:                        noff = 0;
        !           448:                }
        !           449:                awa->awa_encrypt(ctx, mtod(n, caddr_t) + noff, crcbuf,
        !           450:                    sizeof(crcbuf));
        !           451:        } else {
        !           452:                n->m_len = noff;
        !           453:                noff = 0;
        !           454:                for (; noff < sizeof(crcbuf); noff += len, m = m->m_next) {
        !           455:                        if (m->m_len < moff + len)
        !           456:                                len = m->m_len - moff;
        !           457:                        if (len == 0)
        !           458:                                continue;
        !           459:                        awa->awa_decrypt(ctx, crcbuf + noff,
        !           460:                            mtod(m, caddr_t) + moff, len);
        !           461:                }
        !           462:                if (crc != LE_READ_4(crcbuf))
        !           463:                        goto fail;
        !           464:        }
        !           465:        m_freem(m0);
        !           466:        return n0;
        !           467:
        !           468:   fail:
        !           469:        m_freem(m0);
        !           470:        m_freem(n0);
        !           471:        return NULL;
        !           472: }
        !           473:
        !           474: /*
        !           475:  * CRC 32 -- routine from RFC 2083
        !           476:  */
        !           477:
        !           478: /* Table of CRCs of all 8-bit messages */
        !           479: static u_int32_t awi_crc_table[256];
        !           480: static int awi_crc_table_computed = 0;
        !           481:
        !           482: /* Make the table for a fast CRC. */
        !           483: static void
        !           484: awi_crc_init()
        !           485: {
        !           486:        u_int32_t c;
        !           487:        int n, k;
        !           488:
        !           489:        if (awi_crc_table_computed)
        !           490:                return;
        !           491:        for (n = 0; n < 256; n++) {
        !           492:                c = (u_int32_t)n;
        !           493:                for (k = 0; k < 8; k++) {
        !           494:                        if (c & 1)
        !           495:                                c = 0xedb88320UL ^ (c >> 1);
        !           496:                        else
        !           497:                                c = c >> 1;
        !           498:                }
        !           499:                awi_crc_table[n] = c;
        !           500:        }
        !           501:        awi_crc_table_computed = 1;
        !           502: }
        !           503:
        !           504: /*
        !           505:  * Update a running CRC with the bytes buf[0..len-1]--the CRC
        !           506:  * should be initialized to all 1's, and the transmitted value
        !           507:  * is the 1's complement of the final running CRC
        !           508:  */
        !           509:
        !           510: static u_int32_t
        !           511: awi_crc_update(crc, buf, len)
        !           512:        u_int32_t crc;
        !           513:        u_int8_t *buf;
        !           514:        int len;
        !           515: {
        !           516:        u_int8_t *endbuf;
        !           517:
        !           518:        for (endbuf = buf + len; buf < endbuf; buf++)
        !           519:                crc = awi_crc_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
        !           520:        return crc;
        !           521: }
        !           522:
        !           523: /*
        !           524:  * Null -- do nothing but copy.
        !           525:  */
        !           526:
        !           527: static int
        !           528: awi_null_ctxlen()
        !           529: {
        !           530:
        !           531:        return 0;
        !           532: }
        !           533:
        !           534: static void
        !           535: awi_null_setkey(ctx, key, keylen)
        !           536:        void *ctx;
        !           537:        u_char *key;
        !           538:        int keylen;
        !           539: {
        !           540: }
        !           541:
        !           542: static void
        !           543: awi_null_copy(ctx, dst, src, len)
        !           544:        void *ctx;
        !           545:        u_char *dst;
        !           546:        u_char *src;
        !           547:        int len;
        !           548: {
        !           549:
        !           550:        memcpy(dst, src, len);
        !           551: }

CVSweb