1/*-
2 * Copyright (c) 2003-2012 Broadcom Corporation
3 * All Rights Reserved
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in
13 *    the documentation and/or other materials provided with the
14 *    distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD$");
31
32#include <sys/param.h>
33#include <sys/types.h>
34#include <sys/systm.h>
35#include <sys/kernel.h>
36#include <sys/module.h>
37#include <sys/malloc.h>
38#include <sys/mbuf.h>
39#include <sys/lock.h>
40#include <sys/mutex.h>
41#include <sys/bus.h>
42#include <sys/uio.h>
43#include <machine/bus.h>
44#include <machine/md_var.h>
45#include <machine/cpuregs.h>
46
47#include <vm/vm.h>
48#include <vm/pmap.h>
49
50#include <opencrypto/cryptodev.h>
51
52#include <mips/nlm/hal/haldefs.h>
53#include <mips/nlm/hal/cop2.h>
54#include <mips/nlm/hal/fmn.h>
55#include <mips/nlm/hal/mips-extns.h>
56#include <mips/nlm/hal/nlmsaelib.h>
57#include <mips/nlm/dev/sec/nlmseclib.h>
58
59static int
60nlm_crypto_complete_sec_request(struct xlp_sec_softc *sc,
61    struct xlp_sec_command *cmd)
62{
63	unsigned int fbvc;
64	struct nlm_fmn_msg m;
65	int ret;
66
67	fbvc = nlm_cpuid() / CMS_MAX_VCPU_VC;
68	m.msg[0] = m.msg[1] = m.msg[2] = m.msg[3] = 0;
69
70	m.msg[0] = nlm_crypto_form_pkt_fmn_entry0(fbvc, 0, 0,
71	    cmd->ctrlp->cipherkeylen, vtophys(cmd->ctrlp));
72
73	m.msg[1] = nlm_crypto_form_pkt_fmn_entry1(0, cmd->ctrlp->hashkeylen,
74	    NLM_CRYPTO_PKT_DESC_SIZE(cmd->nsegs), vtophys(cmd->paramp));
75
76	/* Software scratch pad */
77	m.msg[2] = (uintptr_t)cmd;
78	sc->sec_msgsz = 3;
79
80	/* Send the message to sec/rsa engine vc */
81	ret = nlm_fmn_msgsend(sc->sec_vc_start, sc->sec_msgsz,
82	    FMN_SWCODE_CRYPTO, &m);
83	if (ret != 0) {
84#ifdef NLM_SEC_DEBUG
85		printf("%s: msgsnd failed (%x)\n", __func__, ret);
86#endif
87		return (ERESTART);
88	}
89	return (0);
90}
91
92int
93nlm_crypto_form_srcdst_segs(struct xlp_sec_command *cmd)
94{
95	unsigned int srcseg = 0, dstseg = 0;
96	struct cryptodesc *cipdesc = NULL;
97	struct cryptop *crp = NULL;
98
99	crp = cmd->crp;
100	cipdesc = cmd->enccrd;
101
102	if (cipdesc != NULL) {
103		/* IV is given as ONE segment to avoid copy */
104		if (cipdesc->crd_flags & CRD_F_IV_EXPLICIT) {
105			srcseg = nlm_crypto_fill_src_seg(cmd->paramp, srcseg,
106			    cmd->iv, cmd->ivlen);
107			dstseg = nlm_crypto_fill_dst_seg(cmd->paramp, dstseg,
108			    cmd->iv, cmd->ivlen);
109		}
110	}
111
112	if (crp->crp_flags & CRYPTO_F_IMBUF) {
113		struct mbuf *m = NULL;
114
115		m  = (struct mbuf *)crp->crp_buf;
116		while (m != NULL) {
117			srcseg = nlm_crypto_fill_src_seg(cmd->paramp, srcseg,
118			    mtod(m,caddr_t), m->m_len);
119			if (cipdesc != NULL) {
120				dstseg = nlm_crypto_fill_dst_seg(cmd->paramp,
121				    dstseg, mtod(m,caddr_t), m->m_len);
122			}
123			m = m->m_next;
124		}
125	} else if (crp->crp_flags & CRYPTO_F_IOV) {
126		struct uio *uio = NULL;
127		struct iovec *iov = NULL;
128	        int iol = 0;
129
130		uio = (struct uio *)crp->crp_buf;
131		iov = (struct iovec *)uio->uio_iov;
132		iol = uio->uio_iovcnt;
133
134		while (iol > 0) {
135			srcseg = nlm_crypto_fill_src_seg(cmd->paramp, srcseg,
136			    (caddr_t)iov->iov_base, iov->iov_len);
137			if (cipdesc != NULL) {
138				dstseg = nlm_crypto_fill_dst_seg(cmd->paramp,
139				    dstseg, (caddr_t)iov->iov_base,
140				    iov->iov_len);
141			}
142			iov++;
143			iol--;
144		}
145	} else {
146		srcseg = nlm_crypto_fill_src_seg(cmd->paramp, srcseg,
147		    ((caddr_t)crp->crp_buf), crp->crp_ilen);
148		if (cipdesc != NULL) {
149			dstseg = nlm_crypto_fill_dst_seg(cmd->paramp, dstseg,
150			    ((caddr_t)crp->crp_buf), crp->crp_ilen);
151		}
152	}
153	return (0);
154}
155
156int
157nlm_crypto_do_cipher(struct xlp_sec_softc *sc, struct xlp_sec_command *cmd)
158{
159	struct cryptodesc *cipdesc = NULL;
160	unsigned char *cipkey = NULL;
161	int ret = 0;
162
163	cipdesc = cmd->enccrd;
164	cipkey = (unsigned char *)cipdesc->crd_key;
165	if (cmd->cipheralg == NLM_CIPHER_3DES) {
166		if (!(cipdesc->crd_flags & CRD_F_ENCRYPT)) {
167                        uint64_t *k, *tkey;
168			k = (uint64_t *)cipdesc->crd_key;
169			tkey = (uint64_t *)cmd->des3key;
170			tkey[2] = k[0];
171			tkey[1] = k[1];
172			tkey[0] = k[2];
173			cipkey = (unsigned char *)tkey;
174		}
175	}
176	nlm_crypto_fill_pkt_ctrl(cmd->ctrlp, 0, NLM_HASH_BYPASS, 0,
177	    cmd->cipheralg, cmd->ciphermode, cipkey,
178	    (cipdesc->crd_klen >> 3), NULL, 0);
179
180	nlm_crypto_fill_cipher_pkt_param(cmd->ctrlp, cmd->paramp,
181	    (cipdesc->crd_flags & CRD_F_ENCRYPT) ? 1 : 0, cmd->ivoff,
182	    cmd->ivlen, cmd->cipheroff, cmd->cipherlen);
183	nlm_crypto_form_srcdst_segs(cmd);
184
185	ret = nlm_crypto_complete_sec_request(sc, cmd);
186	return (ret);
187}
188
189int
190nlm_crypto_do_digest(struct xlp_sec_softc *sc, struct xlp_sec_command *cmd)
191{
192	struct cryptodesc *digdesc = NULL;
193	int ret=0;
194
195	digdesc = cmd->maccrd;
196
197	nlm_crypto_fill_pkt_ctrl(cmd->ctrlp, (digdesc->crd_klen) ? 1 : 0,
198	    cmd->hashalg, cmd->hashmode, NLM_CIPHER_BYPASS, 0,
199	    NULL, 0, digdesc->crd_key, digdesc->crd_klen >> 3);
200
201	nlm_crypto_fill_auth_pkt_param(cmd->ctrlp, cmd->paramp,
202	    cmd->hashoff, cmd->hashlen, cmd->hmacpad,
203	    (unsigned char *)cmd->hashdest);
204
205	nlm_crypto_form_srcdst_segs(cmd);
206
207	ret = nlm_crypto_complete_sec_request(sc, cmd);
208
209	return (ret);
210}
211
212int
213nlm_crypto_do_cipher_digest(struct xlp_sec_softc *sc,
214    struct xlp_sec_command *cmd)
215{
216	struct cryptodesc *cipdesc=NULL, *digdesc=NULL;
217	unsigned char *cipkey = NULL;
218	int ret=0;
219
220	cipdesc = cmd->enccrd;
221	digdesc = cmd->maccrd;
222
223	cipkey = (unsigned char *)cipdesc->crd_key;
224	if (cmd->cipheralg == NLM_CIPHER_3DES) {
225		if (!(cipdesc->crd_flags & CRD_F_ENCRYPT)) {
226			uint64_t *k, *tkey;
227			k = (uint64_t *)cipdesc->crd_key;
228			tkey = (uint64_t *)cmd->des3key;
229			tkey[2] = k[0];
230			tkey[1] = k[1];
231			tkey[0] = k[2];
232			cipkey = (unsigned char *)tkey;
233		}
234	}
235	nlm_crypto_fill_pkt_ctrl(cmd->ctrlp, (digdesc->crd_klen) ? 1 : 0,
236	    cmd->hashalg, cmd->hashmode, cmd->cipheralg, cmd->ciphermode,
237	    cipkey, (cipdesc->crd_klen >> 3),
238	    digdesc->crd_key, (digdesc->crd_klen >> 3));
239
240	nlm_crypto_fill_cipher_auth_pkt_param(cmd->ctrlp, cmd->paramp,
241	    (cipdesc->crd_flags & CRD_F_ENCRYPT) ? 1 : 0, cmd->hashsrc,
242	    cmd->ivoff, cmd->ivlen, cmd->hashoff, cmd->hashlen,
243	    cmd->hmacpad, cmd->cipheroff, cmd->cipherlen,
244	    (unsigned char *)cmd->hashdest);
245
246	nlm_crypto_form_srcdst_segs(cmd);
247
248	ret = nlm_crypto_complete_sec_request(sc, cmd);
249	return (ret);
250}
251
252int
253nlm_get_digest_param(struct xlp_sec_command *cmd)
254{
255	switch(cmd->maccrd->crd_alg) {
256	case CRYPTO_MD5:
257		cmd->hashalg  = NLM_HASH_MD5;
258		cmd->hashmode = NLM_HASH_MODE_SHA1;
259		break;
260	case CRYPTO_SHA1:
261		cmd->hashalg  = NLM_HASH_SHA;
262		cmd->hashmode = NLM_HASH_MODE_SHA1;
263		break;
264	case CRYPTO_MD5_HMAC:
265		cmd->hashalg  = NLM_HASH_MD5;
266		cmd->hashmode = NLM_HASH_MODE_SHA1;
267		break;
268	case CRYPTO_SHA1_HMAC:
269		cmd->hashalg  = NLM_HASH_SHA;
270		cmd->hashmode = NLM_HASH_MODE_SHA1;
271		break;
272	default:
273		/* Not supported */
274		return (-1);
275	}
276	return (0);
277}
278int
279nlm_get_cipher_param(struct xlp_sec_command *cmd)
280{
281	switch(cmd->enccrd->crd_alg) {
282	case CRYPTO_DES_CBC:
283		cmd->cipheralg  = NLM_CIPHER_DES;
284		cmd->ciphermode = NLM_CIPHER_MODE_CBC;
285		cmd->ivlen	= XLP_SEC_DES_IV_LENGTH;
286		break;
287	case CRYPTO_3DES_CBC:
288		cmd->cipheralg  = NLM_CIPHER_3DES;
289		cmd->ciphermode = NLM_CIPHER_MODE_CBC;
290		cmd->ivlen	= XLP_SEC_DES_IV_LENGTH;
291		break;
292	case CRYPTO_AES_CBC:
293		cmd->cipheralg  = NLM_CIPHER_AES128;
294		cmd->ciphermode = NLM_CIPHER_MODE_CBC;
295		cmd->ivlen	= XLP_SEC_AES_IV_LENGTH;
296		break;
297	case CRYPTO_ARC4:
298		cmd->cipheralg  = NLM_CIPHER_ARC4;
299		cmd->ciphermode = NLM_CIPHER_MODE_ECB;
300		cmd->ivlen	= XLP_SEC_ARC4_IV_LENGTH;
301		break;
302	default:
303		/* Not supported */
304		return (-1);
305	}
306	return (0);
307}
308