The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/mips/cavium/cryptocteon/cryptocteon.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Octeon Crypto for OCF
    3  *
    4  * Written by David McCullough <david_mccullough@securecomputing.com>
    5  * Copyright (C) 2009 David McCullough
    6  *
    7  * LICENSE TERMS
    8  *
    9  * The free distribution and use of this software in both source and binary
   10  * form is allowed (with or without changes) provided that:
   11  *
   12  *   1. distributions of this source code include the above copyright
   13  *      notice, this list of conditions and the following disclaimer;
   14  *
   15  *   2. distributions in binary form include the above copyright
   16  *      notice, this list of conditions and the following disclaimer
   17  *      in the documentation and/or other associated materials;
   18  *
   19  *   3. the copyright holder's name is not used to endorse products
   20  *      built using this software without specific written permission.
   21  *
   22  * DISCLAIMER
   23  *
   24  * This software is provided 'as is' with no explicit or implied warranties
   25  * in respect of its properties, including, but not limited to, correctness
   26  * and/or fitness for purpose.
   27  * ---------------------------------------------------------------------------
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD: releng/11.0/sys/mips/cavium/cryptocteon/cryptocteon.c 210312 2010-07-20 19:32:25Z jmallett $");
   32 
   33 #include <sys/param.h>
   34 #include <sys/systm.h>
   35 #include <sys/bus.h>
   36 #include <sys/kernel.h>
   37 #include <sys/module.h>
   38 #include <sys/malloc.h>
   39 #include <sys/mbuf.h>
   40 #include <sys/uio.h>
   41 
   42 #include <opencrypto/cryptodev.h>
   43 
   44 #include <contrib/octeon-sdk/cvmx.h>
   45 
   46 #include <mips/cavium/cryptocteon/cryptocteonvar.h>
   47 
   48 #include "cryptodev_if.h"
   49 
   50 struct cryptocteon_softc {
   51         int32_t                 sc_cid;         /* opencrypto id */
   52         struct octo_sess        **sc_sessions;
   53         uint32_t                sc_sesnum;
   54 };
   55 
   56 int cryptocteon_debug = 0;
   57 TUNABLE_INT("hw.cryptocteon.debug", &cryptocteon_debug);
   58 
   59 static void cryptocteon_identify(driver_t *, device_t);
   60 static int cryptocteon_probe(device_t);
   61 static int cryptocteon_attach(device_t);
   62 
   63 static int cryptocteon_process(device_t, struct cryptop *, int);
   64 static int cryptocteon_newsession(device_t, u_int32_t *, struct cryptoini *);
   65 static int cryptocteon_freesession(device_t, u_int64_t);
   66 
   67 static void
   68 cryptocteon_identify(driver_t *drv, device_t parent)
   69 {
   70         if (octeon_has_feature(OCTEON_FEATURE_CRYPTO))
   71                 BUS_ADD_CHILD(parent, 0, "cryptocteon", 0);
   72 }
   73 
   74 static int
   75 cryptocteon_probe(device_t dev)
   76 {
   77         device_set_desc(dev, "Octeon Secure Coprocessor");
   78         return (0);
   79 }
   80 
   81 static int
   82 cryptocteon_attach(device_t dev)
   83 {
   84         struct cryptocteon_softc *sc;
   85 
   86         sc = device_get_softc(dev);
   87 
   88         sc->sc_cid = crypto_get_driverid(dev, CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SYNC);
   89         if (sc->sc_cid < 0) {
   90                 device_printf(dev, "crypto_get_driverid ret %d\n", sc->sc_cid);
   91                 return (ENXIO);
   92         }
   93 
   94         crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0);
   95         crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0);
   96         crypto_register(sc->sc_cid, CRYPTO_DES_CBC, 0, 0);
   97         crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0);
   98         crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0);
   99 
  100         return (0);
  101 }
  102 
  103 /*
  104  * Generate a new octo session.  We artifically limit it to a single
  105  * hash/cipher or hash-cipher combo just to make it easier, most callers
  106  * do not expect more than this anyway.
  107  */
  108 static int
  109 cryptocteon_newsession(device_t dev, u_int32_t *sid, struct cryptoini *cri)
  110 {
  111         struct cryptoini *c, *encini = NULL, *macini = NULL;
  112         struct cryptocteon_softc *sc;
  113         struct octo_sess **ocd;
  114         int i;
  115 
  116         sc = device_get_softc(dev);
  117 
  118         if (sid == NULL || cri == NULL || sc == NULL)
  119                 return (EINVAL);
  120 
  121         /*
  122          * To keep it simple, we only handle hash, cipher or hash/cipher in a
  123          * session,  you cannot currently do multiple ciphers/hashes in one
  124          * session even though it would be possibel to code this driver to
  125          * handle it.
  126          */
  127         for (i = 0, c = cri; c && i < 2; i++) {
  128                 if (c->cri_alg == CRYPTO_MD5_HMAC ||
  129                     c->cri_alg == CRYPTO_SHA1_HMAC ||
  130                     c->cri_alg == CRYPTO_NULL_HMAC) {
  131                         if (macini) {
  132                                 break;
  133                         }
  134                         macini = c;
  135                 }
  136                 if (c->cri_alg == CRYPTO_DES_CBC ||
  137                     c->cri_alg == CRYPTO_3DES_CBC ||
  138                     c->cri_alg == CRYPTO_AES_CBC ||
  139                     c->cri_alg == CRYPTO_NULL_CBC) {
  140                         if (encini) {
  141                                 break;
  142                         }
  143                         encini = c;
  144                 }
  145                 c = c->cri_next;
  146         }
  147         if (!macini && !encini) {
  148                 dprintf("%s,%d - EINVAL bad cipher/hash or combination\n",
  149                                 __FILE__, __LINE__);
  150                 return EINVAL;
  151         }
  152         if (c) {
  153                 dprintf("%s,%d - EINVAL cannot handle chained cipher/hash combos\n",
  154                                 __FILE__, __LINE__);
  155                 return EINVAL;
  156         }
  157 
  158         /*
  159          * So we have something we can do, lets setup the session
  160          */
  161 
  162         if (sc->sc_sessions) {
  163                 for (i = 1; i < sc->sc_sesnum; i++)
  164                         if (sc->sc_sessions[i] == NULL)
  165                                 break;
  166         } else
  167                 i = 1;          /* NB: to silence compiler warning */
  168 
  169         if (sc->sc_sessions == NULL || i == sc->sc_sesnum) {
  170                 if (sc->sc_sessions == NULL) {
  171                         i = 1; /* We leave sc->sc_sessions[0] empty */
  172                         sc->sc_sesnum = CRYPTO_SW_SESSIONS;
  173                 } else
  174                         sc->sc_sesnum *= 2;
  175 
  176                 ocd = malloc(sc->sc_sesnum * sizeof(struct octo_sess *),
  177                              M_DEVBUF, M_NOWAIT | M_ZERO);
  178                 if (ocd == NULL) {
  179                         /* Reset session number */
  180                         if (sc->sc_sesnum == CRYPTO_SW_SESSIONS)
  181                                 sc->sc_sesnum = 0;
  182                         else
  183                                 sc->sc_sesnum /= 2;
  184                         dprintf("%s,%d: ENOBUFS\n", __FILE__, __LINE__);
  185                         return ENOBUFS;
  186                 }
  187 
  188                 /* Copy existing sessions */
  189                 if (sc->sc_sessions) {
  190                         memcpy(ocd, sc->sc_sessions,
  191                             (sc->sc_sesnum / 2) * sizeof(struct octo_sess *));
  192                         free(sc->sc_sessions, M_DEVBUF);
  193                 }
  194 
  195                 sc->sc_sessions = ocd;
  196         }
  197 
  198         ocd = &sc->sc_sessions[i];
  199         *sid = i;
  200 
  201         *ocd = malloc(sizeof(struct octo_sess), M_DEVBUF, M_NOWAIT | M_ZERO);
  202         if (*ocd == NULL) {
  203                 cryptocteon_freesession(NULL, i);
  204                 dprintf("%s,%d: ENOBUFS\n", __FILE__, __LINE__);
  205                 return ENOBUFS;
  206         }
  207 
  208         if (encini && encini->cri_key) {
  209                 (*ocd)->octo_encklen = (encini->cri_klen + 7) / 8;
  210                 memcpy((*ocd)->octo_enckey, encini->cri_key, (*ocd)->octo_encklen);
  211         }
  212 
  213         if (macini && macini->cri_key) {
  214                 (*ocd)->octo_macklen = (macini->cri_klen + 7) / 8;
  215                 memcpy((*ocd)->octo_mackey, macini->cri_key, (*ocd)->octo_macklen);
  216         }
  217 
  218         (*ocd)->octo_mlen = 0;
  219         if (encini && encini->cri_mlen)
  220                 (*ocd)->octo_mlen = encini->cri_mlen;
  221         else if (macini && macini->cri_mlen)
  222                 (*ocd)->octo_mlen = macini->cri_mlen;
  223         else
  224                 (*ocd)->octo_mlen = 12;
  225 
  226         /*
  227          * point c at the enc if it exists, otherwise the mac
  228          */
  229         c = encini ? encini : macini;
  230 
  231         switch (c->cri_alg) {
  232         case CRYPTO_DES_CBC:
  233         case CRYPTO_3DES_CBC:
  234                 (*ocd)->octo_ivsize  = 8;
  235                 switch (macini ? macini->cri_alg : -1) {
  236                 case CRYPTO_MD5_HMAC:
  237                         (*ocd)->octo_encrypt = octo_des_cbc_md5_encrypt;
  238                         (*ocd)->octo_decrypt = octo_des_cbc_md5_decrypt;
  239                         octo_calc_hash(0, macini->cri_key, (*ocd)->octo_hminner,
  240                                         (*ocd)->octo_hmouter);
  241                         break;
  242                 case CRYPTO_SHA1_HMAC:
  243                         (*ocd)->octo_encrypt = octo_des_cbc_sha1_encrypt;
  244                         (*ocd)->octo_decrypt = octo_des_cbc_sha1_encrypt;
  245                         octo_calc_hash(1, macini->cri_key, (*ocd)->octo_hminner,
  246                                         (*ocd)->octo_hmouter);
  247                         break;
  248                 case -1:
  249                         (*ocd)->octo_encrypt = octo_des_cbc_encrypt;
  250                         (*ocd)->octo_decrypt = octo_des_cbc_decrypt;
  251                         break;
  252                 default:
  253                         cryptocteon_freesession(NULL, i);
  254                         dprintf("%s,%d: EINVALn", __FILE__, __LINE__);
  255                         return EINVAL;
  256                 }
  257                 break;
  258         case CRYPTO_AES_CBC:
  259                 (*ocd)->octo_ivsize  = 16;
  260                 switch (macini ? macini->cri_alg : -1) {
  261                 case CRYPTO_MD5_HMAC:
  262                         (*ocd)->octo_encrypt = octo_aes_cbc_md5_encrypt;
  263                         (*ocd)->octo_decrypt = octo_aes_cbc_md5_decrypt;
  264                         octo_calc_hash(0, macini->cri_key, (*ocd)->octo_hminner,
  265                                         (*ocd)->octo_hmouter);
  266                         break;
  267                 case CRYPTO_SHA1_HMAC:
  268                         (*ocd)->octo_encrypt = octo_aes_cbc_sha1_encrypt;
  269                         (*ocd)->octo_decrypt = octo_aes_cbc_sha1_decrypt;
  270                         octo_calc_hash(1, macini->cri_key, (*ocd)->octo_hminner,
  271                                         (*ocd)->octo_hmouter);
  272                         break;
  273                 case -1:
  274                         (*ocd)->octo_encrypt = octo_aes_cbc_encrypt;
  275                         (*ocd)->octo_decrypt = octo_aes_cbc_decrypt;
  276                         break;
  277                 default:
  278                         cryptocteon_freesession(NULL, i);
  279                         dprintf("%s,%d: EINVALn", __FILE__, __LINE__);
  280                         return EINVAL;
  281                 }
  282                 break;
  283         case CRYPTO_MD5_HMAC:
  284                 (*ocd)->octo_encrypt = octo_null_md5_encrypt;
  285                 (*ocd)->octo_decrypt = octo_null_md5_encrypt;
  286                 octo_calc_hash(0, macini->cri_key, (*ocd)->octo_hminner,
  287                                 (*ocd)->octo_hmouter);
  288                 break;
  289         case CRYPTO_SHA1_HMAC:
  290                 (*ocd)->octo_encrypt = octo_null_sha1_encrypt;
  291                 (*ocd)->octo_decrypt = octo_null_sha1_encrypt;
  292                 octo_calc_hash(1, macini->cri_key, (*ocd)->octo_hminner,
  293                                 (*ocd)->octo_hmouter);
  294                 break;
  295         default:
  296                 cryptocteon_freesession(NULL, i);
  297                 dprintf("%s,%d: EINVALn", __FILE__, __LINE__);
  298                 return EINVAL;
  299         }
  300 
  301         (*ocd)->octo_encalg = encini ? encini->cri_alg : -1;
  302         (*ocd)->octo_macalg = macini ? macini->cri_alg : -1;
  303 
  304         return 0;
  305 }
  306 
  307 /*
  308  * Free a session.
  309  */
  310 static int
  311 cryptocteon_freesession(device_t dev, u_int64_t tid)
  312 {
  313         struct cryptocteon_softc *sc;
  314         u_int32_t sid = CRYPTO_SESID2LID(tid);
  315 
  316         sc = device_get_softc(dev);
  317 
  318         if (sc == NULL)
  319                 return (EINVAL);
  320 
  321         if (sid > sc->sc_sesnum || sc->sc_sessions == NULL ||
  322             sc->sc_sessions[sid] == NULL)
  323                 return (EINVAL);
  324 
  325         /* Silently accept and return */
  326         if (sid == 0)
  327                 return(0);
  328 
  329         if (sc->sc_sessions[sid])
  330                 free(sc->sc_sessions[sid], M_DEVBUF);
  331         sc->sc_sessions[sid] = NULL;
  332         return 0;
  333 }
  334 
  335 /*
  336  * Process a request.
  337  */
  338 static int
  339 cryptocteon_process(device_t dev, struct cryptop *crp, int hint)
  340 {
  341         struct cryptodesc *crd;
  342         struct octo_sess *od;
  343         u_int32_t lid;
  344         size_t iovcnt, iovlen;
  345         struct mbuf *m = NULL;
  346         struct uio *uiop = NULL;
  347         struct cryptodesc *enccrd = NULL, *maccrd = NULL;
  348         unsigned char *ivp = NULL;
  349         unsigned char iv_data[HASH_MAX_LEN];
  350         int auth_off = 0, auth_len = 0, crypt_off = 0, crypt_len = 0, icv_off = 0;
  351         struct cryptocteon_softc *sc;
  352 
  353         sc = device_get_softc(dev);
  354 
  355         if (sc == NULL || crp == NULL)
  356                 return EINVAL;
  357 
  358         crp->crp_etype = 0;
  359 
  360         if (crp->crp_desc == NULL || crp->crp_buf == NULL) {
  361                 dprintf("%s,%d: EINVAL\n", __FILE__, __LINE__);
  362                 crp->crp_etype = EINVAL;
  363                 goto done;
  364         }
  365 
  366         lid = crp->crp_sid & 0xffffffff;
  367         if (lid >= sc->sc_sesnum || lid == 0 || sc->sc_sessions == NULL ||
  368             sc->sc_sessions[lid] == NULL) {
  369                 crp->crp_etype = ENOENT;
  370                 dprintf("%s,%d: ENOENT\n", __FILE__, __LINE__);
  371                 goto done;
  372         }
  373         od = sc->sc_sessions[lid];
  374 
  375         /*
  376          * do some error checking outside of the loop for m and IOV processing
  377          * this leaves us with valid m or uiop pointers for later
  378          */
  379         if (crp->crp_flags & CRYPTO_F_IMBUF) {
  380                 unsigned frags;
  381 
  382                 m = (struct mbuf *) crp->crp_buf;
  383                 for (frags = 0; m != NULL; frags++)
  384                         m = m->m_next;
  385 
  386                 if (frags >= UIO_MAXIOV) {
  387                         printf("%s,%d: %d frags > UIO_MAXIOV", __FILE__, __LINE__, frags);
  388                         goto done;
  389                 }
  390 
  391                 m = (struct mbuf *) crp->crp_buf;
  392         } else if (crp->crp_flags & CRYPTO_F_IOV) {
  393                 uiop = (struct uio *) crp->crp_buf;
  394                 if (uiop->uio_iovcnt > UIO_MAXIOV) {
  395                         printf("%s,%d: %d uio_iovcnt > UIO_MAXIOV", __FILE__, __LINE__,
  396                                uiop->uio_iovcnt);
  397                         goto done;
  398                 }
  399         }
  400 
  401         /* point our enccrd and maccrd appropriately */
  402         crd = crp->crp_desc;
  403         if (crd->crd_alg == od->octo_encalg) enccrd = crd;
  404         if (crd->crd_alg == od->octo_macalg) maccrd = crd;
  405         crd = crd->crd_next;
  406         if (crd) {
  407                 if (crd->crd_alg == od->octo_encalg) enccrd = crd;
  408                 if (crd->crd_alg == od->octo_macalg) maccrd = crd;
  409                 crd = crd->crd_next;
  410         }
  411         if (crd) {
  412                 crp->crp_etype = EINVAL;
  413                 dprintf("%s,%d: ENOENT - descriptors do not match session\n",
  414                                 __FILE__, __LINE__);
  415                 goto done;
  416         }
  417 
  418         if (enccrd) {
  419                 if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) {
  420                         ivp = enccrd->crd_iv;
  421                 } else {
  422                         ivp = iv_data;
  423                         crypto_copydata(crp->crp_flags, crp->crp_buf,
  424                                         enccrd->crd_inject, od->octo_ivsize, (caddr_t) ivp);
  425                 }
  426 
  427                 if (maccrd) {
  428                         auth_off = maccrd->crd_skip;
  429                         auth_len = maccrd->crd_len;
  430                         icv_off  = maccrd->crd_inject;
  431                 }
  432 
  433                 crypt_off = enccrd->crd_skip;
  434                 crypt_len = enccrd->crd_len;
  435         } else { /* if (maccrd) */
  436                 auth_off = maccrd->crd_skip;
  437                 auth_len = maccrd->crd_len;
  438                 icv_off  = maccrd->crd_inject;
  439         }
  440 
  441         /*
  442          * setup the I/O vector to cover the buffer
  443          */
  444         if (crp->crp_flags & CRYPTO_F_IMBUF) {
  445                 iovcnt = 0;
  446                 iovlen = 0;
  447 
  448                 while (m != NULL) {
  449                         od->octo_iov[iovcnt].iov_base = mtod(m, void *);
  450                         od->octo_iov[iovcnt].iov_len = m->m_len;
  451 
  452                         m = m->m_next;
  453                         iovlen += od->octo_iov[iovcnt++].iov_len;
  454                 }
  455         } else if (crp->crp_flags & CRYPTO_F_IOV) {
  456                 iovlen = 0;
  457                 for (iovcnt = 0; iovcnt < uiop->uio_iovcnt; iovcnt++) {
  458                         od->octo_iov[iovcnt].iov_base = uiop->uio_iov[iovcnt].iov_base;
  459                         od->octo_iov[iovcnt].iov_len = uiop->uio_iov[iovcnt].iov_len;
  460 
  461                         iovlen += od->octo_iov[iovcnt].iov_len;
  462                 }
  463         } else {
  464                 iovlen = crp->crp_ilen;
  465                 od->octo_iov[0].iov_base = crp->crp_buf;
  466                 od->octo_iov[0].iov_len = crp->crp_ilen;
  467                 iovcnt = 1;
  468         }
  469 
  470 
  471         /*
  472          * setup a new explicit key
  473          */
  474         if (enccrd) {
  475                 if (enccrd->crd_flags & CRD_F_KEY_EXPLICIT) {
  476                         od->octo_encklen = (enccrd->crd_klen + 7) / 8;
  477                         memcpy(od->octo_enckey, enccrd->crd_key, od->octo_encklen);
  478                 }
  479         }
  480         if (maccrd) {
  481                 if (maccrd->crd_flags & CRD_F_KEY_EXPLICIT) {
  482                         od->octo_macklen = (maccrd->crd_klen + 7) / 8;
  483                         memcpy(od->octo_mackey, maccrd->crd_key, od->octo_macklen);
  484                         od->octo_mackey_set = 0;
  485                 }
  486                 if (!od->octo_mackey_set) {
  487                         octo_calc_hash(maccrd->crd_alg == CRYPTO_MD5_HMAC ? 0 : 1,
  488                                 maccrd->crd_key, od->octo_hminner, od->octo_hmouter);
  489                         od->octo_mackey_set = 1;
  490                 }
  491         }
  492 
  493 
  494         if (!enccrd || (enccrd->crd_flags & CRD_F_ENCRYPT))
  495                 (*od->octo_encrypt)(od, od->octo_iov, iovcnt, iovlen,
  496                                 auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp);
  497         else
  498                 (*od->octo_decrypt)(od, od->octo_iov, iovcnt, iovlen,
  499                                 auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp);
  500 
  501 done:
  502         crypto_done(crp);
  503         return 0;
  504 }
  505 
  506 static device_method_t cryptocteon_methods[] = {
  507         /* device methods */
  508         DEVMETHOD(device_identify,      cryptocteon_identify),
  509         DEVMETHOD(device_probe,         cryptocteon_probe),
  510         DEVMETHOD(device_attach,        cryptocteon_attach),
  511 
  512         /* crypto device methods */
  513         DEVMETHOD(cryptodev_newsession, cryptocteon_newsession),
  514         DEVMETHOD(cryptodev_freesession,cryptocteon_freesession),
  515         DEVMETHOD(cryptodev_process,    cryptocteon_process),
  516 
  517         { 0, 0 }
  518 };
  519 
  520 static driver_t cryptocteon_driver = {
  521         "cryptocteon",
  522         cryptocteon_methods,
  523         sizeof (struct cryptocteon_softc),
  524 };
  525 static devclass_t cryptocteon_devclass;
  526 DRIVER_MODULE(cryptocteon, nexus, cryptocteon_driver, cryptocteon_devclass, 0, 0);

Cache object: ab5c7e3bb8f090e289ec81f8a8ae772e


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.