summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordim <dim@FreeBSD.org>2015-12-31 22:55:02 +0000
committerdim <dim@FreeBSD.org>2015-12-31 22:55:02 +0000
commitbc8f4c6766d9b42a3b5bc686c68cd43e8044462c (patch)
tree34b4a25c4bc3b0ad56cf20133da5eec165babec9
parent5e96169da3835c4e7ba0d43cbe01f0d7b36f67b3 (diff)
parent64f2c44ad84c0333d3cdc811e04bf59d76f1ef26 (diff)
downloadFreeBSD-src-bc8f4c6766d9b42a3b5bc686c68cd43e8044462c.zip
FreeBSD-src-bc8f4c6766d9b42a3b5bc686c68cd43e8044462c.tar.gz
Merge ^/head r292951 through r293015.
-rw-r--r--COPYRIGHT2
-rw-r--r--bin/sh/expand.c703
-rw-r--r--bin/sh/expand.h5
-rw-r--r--contrib/binutils/bfd/elf32-arm.c26
-rw-r--r--lib/libmd/mdXhl.c13
-rw-r--r--lib/libstand/Makefile6
-rw-r--r--share/man/man4/Makefile2
-rw-r--r--share/man/man4/rtwn.4165
-rw-r--r--share/man/man4/rtwnfw.474
-rw-r--r--sys/arm64/arm64/identcpu.c507
-rw-r--r--sys/arm64/arm64/mp_machdep.c10
-rw-r--r--sys/arm64/include/armreg.h152
-rw-r--r--sys/arm64/include/cpu.h1
-rw-r--r--sys/boot/forth/loader.conf1
-rw-r--r--sys/boot/forth/menu-commands.4th64
-rw-r--r--sys/boot/forth/menu.rc53
-rw-r--r--sys/boot/forth/support.4th31
-rw-r--r--sys/boot/i386/loader/main.c57
-rw-r--r--sys/boot/zfs/libzfs.h3
-rw-r--r--sys/boot/zfs/zfs.c166
-rw-r--r--sys/boot/zfs/zfsimpl.c62
-rw-r--r--sys/compat/linuxkpi/common/include/linux/cdev.h36
-rw-r--r--sys/compat/linuxkpi/common/include/linux/device.h115
-rw-r--r--sys/compat/linuxkpi/common/include/linux/file.h7
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kobject.h16
-rw-r--r--sys/compat/linuxkpi/common/include/linux/miscdevice.h8
-rw-r--r--sys/compat/linuxkpi/common/src/linux_compat.c193
-rw-r--r--sys/compat/linuxkpi/common/src/linux_pci.c6
-rw-r--r--sys/conf/newvers.sh5
-rw-r--r--sys/contrib/dev/rtwn/LICENSE39
-rw-r--r--sys/contrib/dev/rtwn/rtwn-rtl8192cfwU.fw.uu333
-rw-r--r--sys/contrib/dev/rtwn/rtwn-rtl8192cfwU_B.fw.uu366
-rw-r--r--sys/crypto/sha1.h2
-rw-r--r--sys/dev/cxgb/ulp/tom/cxgb_l2t.c2
-rw-r--r--sys/dev/cxgbe/tom/t4_tom_l2t.c2
-rw-r--r--sys/dev/rtwn/if_rtwn.c3490
-rw-r--r--sys/dev/rtwn/if_rtwnreg.h2106
-rw-r--r--sys/dev/usb/net/if_axe.c1
-rw-r--r--sys/dev/usb/usbdevs1
-rw-r--r--sys/fs/nullfs/null_vnops.c8
-rw-r--r--sys/modules/Makefile2
-rw-r--r--sys/modules/rtwnfw/Makefile5
-rw-r--r--sys/modules/rtwnfw/Makefile.inc15
-rw-r--r--sys/modules/rtwnfw/rtwnrtl8192cU/Makefile6
-rw-r--r--sys/modules/rtwnfw/rtwnrtl8192cUB/Makefile6
-rw-r--r--sys/net/bpf.c24
-rw-r--r--sys/net/flowtable.c10
-rw-r--r--sys/net/if.c41
-rw-r--r--sys/net/if_ethersubr.c289
-rw-r--r--sys/net/if_gif.c2
-rw-r--r--sys/net/if_gre.c22
-rw-r--r--sys/net/if_llatbl.c102
-rw-r--r--sys/net/if_llatbl.h20
-rw-r--r--sys/net/if_var.h44
-rw-r--r--sys/net/route.h13
-rw-r--r--sys/netinet/if_ether.c178
-rw-r--r--sys/netinet/if_ether.h2
-rw-r--r--sys/netinet/in.c12
-rw-r--r--sys/netinet/ip_output.c2
-rw-r--r--sys/netinet/toecore.c2
-rw-r--r--sys/netinet6/icmp6.c2
-rw-r--r--sys/netinet6/in6.c14
-rw-r--r--sys/netinet6/in6.h6
-rw-r--r--sys/netinet6/ip6_output.c1
-rw-r--r--sys/netinet6/nd6.c92
-rw-r--r--sys/netinet6/nd6.h2
-rw-r--r--sys/netinet6/nd6_nbr.c22
-rw-r--r--sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c8
-rw-r--r--sys/opencrypto/skipjack.h5
-rw-r--r--sys/opencrypto/xform.c910
-rw-r--r--sys/opencrypto/xform.h80
-rw-r--r--sys/opencrypto/xform_aes_icm.c152
-rw-r--r--sys/opencrypto/xform_aes_xts.c164
-rw-r--r--sys/opencrypto/xform_auth.h89
-rw-r--r--sys/opencrypto/xform_blf.c127
-rw-r--r--sys/opencrypto/xform_cast5.c107
-rw-r--r--sys/opencrypto/xform_cml.c113
-rw-r--r--sys/opencrypto/xform_comp.h52
-rw-r--r--sys/opencrypto/xform_deflate.c86
-rw-r--r--sys/opencrypto/xform_des1.c116
-rw-r--r--sys/opencrypto/xform_des3.c119
-rw-r--r--sys/opencrypto/xform_enc.h92
-rw-r--r--sys/opencrypto/xform_gmac.c99
-rw-r--r--sys/opencrypto/xform_md5.c81
-rw-r--r--sys/opencrypto/xform_null.c136
-rw-r--r--sys/opencrypto/xform_rijndael.c113
-rw-r--r--sys/opencrypto/xform_rmd160.c75
-rw-r--r--sys/opencrypto/xform_sha1.c93
-rw-r--r--sys/opencrypto/xform_sha2.c109
-rw-r--r--sys/opencrypto/xform_skipjack.c117
-rw-r--r--sys/opencrypto/xform_userland.h48
-rw-r--r--sys/sparc64/include/ktr.h2
-rw-r--r--sys/sys/copyright.h4
-rw-r--r--sys/sys/param.h2
-rw-r--r--sys/xen/xenbus/xenbusb.c2
-rw-r--r--tests/sys/kern/unix_passfd_test.c22
-rw-r--r--usr.sbin/bhyve/bhyverun.c9
-rw-r--r--usr.sbin/bhyve/pci_emul.c3
-rw-r--r--usr.sbin/camdd/camdd.c5
99 files changed, 11041 insertions, 1874 deletions
diff --git a/COPYRIGHT b/COPYRIGHT
index 1d7198f..94046dd 100644
--- a/COPYRIGHT
+++ b/COPYRIGHT
@@ -4,7 +4,7 @@
The compilation of software known as FreeBSD is distributed under the
following terms:
-Copyright (c) 1992-2015 The FreeBSD Project. All rights reserved.
+Copyright (c) 1992-2016 The FreeBSD Project. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
diff --git a/bin/sh/expand.c b/bin/sh/expand.c
index c876abb..59ba549 100644
--- a/bin/sh/expand.c
+++ b/bin/sh/expand.c
@@ -3,6 +3,8 @@
* The Regents of the University of California. All rights reserved.
* Copyright (c) 1997-2005
* Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ * Copyright (c) 2010-2015
+ * Jilles Tjoelker <jilles@stack.nl>. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Kenneth Almquist.
@@ -79,42 +81,32 @@ __FBSDID("$FreeBSD$");
#include "show.h"
#include "builtins.h"
-/*
- * Structure specifying which parts of the string should be searched
- * for IFS characters.
- */
+enum wordstate { WORD_IDLE, WORD_WS_DELIMITED, WORD_QUOTEMARK };
-struct ifsregion {
- struct ifsregion *next; /* next region in list */
- int begoff; /* offset of start of region */
- int endoff; /* offset of end of region */
- int inquotes; /* search for nul bytes only */
+struct worddest {
+ struct arglist *list;
+ enum wordstate state;
};
-
static char *expdest; /* output of current string */
static struct nodelist *argbackq; /* list of back quote expressions */
-static struct ifsregion ifsfirst; /* first struct in list of ifs regions */
-static struct ifsregion *ifslastp; /* last struct in list */
-static char *argstr(char *, int);
+static char *argstr(char *, int, struct worddest *);
static char *exptilde(char *, int);
-static char *expari(char *);
-static void expbackq(union node *, int, int);
-static int subevalvar_trim(char *, int, int, int, int);
+static char *expari(char *, int, struct worddest *);
+static void expbackq(union node *, int, int, struct worddest *);
+static void subevalvar_trim(char *, int, int, int);
static int subevalvar_misc(char *, const char *, int, int, int);
-static char *evalvar(char *, int);
+static char *evalvar(char *, int, struct worddest *);
static int varisset(const char *, int);
-static void strtodest(const char *, int, int, int);
-static void varvalue(const char *, int, int, int);
-static void recordregion(int, int, int);
-static void removerecordregions(int);
-static void ifsbreakup(char *, struct arglist *);
-static void expandmeta(struct arglist *, struct arglist *);
+static void strtodest(const char *, int, int, int, struct worddest *);
+static void reprocess(int, int, int, int, struct worddest *);
+static void varvalue(const char *, int, int, int, struct worddest *);
+static void expandmeta(char *, struct arglist *);
static void expmeta(char *, char *, struct arglist *);
static int expsortcmp(const void *, const void *);
-static int patmatch(const char *, const char *, int);
-static char *cvtnum(int, char *);
+static int patmatch(const char *, const char *);
+static void cvtnum(int, char *);
static int collate_range_cmp(wchar_t, wchar_t);
void
@@ -169,6 +161,53 @@ stputs_quotes(const char *data, const char *syntax, char *p)
}
#define STPUTS_QUOTES(data, syntax, p) p = stputs_quotes((data), syntax, p)
+static char *
+nextword(char c, int flag, char *p, struct worddest *dst)
+{
+ int is_ws;
+
+ is_ws = c == '\t' || c == '\n' || c == ' ';
+ if (p != stackblock() || (is_ws ? dst->state == WORD_QUOTEMARK :
+ dst->state != WORD_WS_DELIMITED) || c == '\0') {
+ STPUTC('\0', p);
+ if (flag & EXP_GLOB)
+ expandmeta(grabstackstr(p), dst->list);
+ else
+ appendarglist(dst->list, grabstackstr(p));
+ dst->state = is_ws ? WORD_WS_DELIMITED : WORD_IDLE;
+ } else if (!is_ws && dst->state == WORD_WS_DELIMITED)
+ dst->state = WORD_IDLE;
+ /* Reserve space while the stack string is empty. */
+ appendarglist(dst->list, NULL);
+ dst->list->count--;
+ STARTSTACKSTR(p);
+ return p;
+}
+#define NEXTWORD(c, flag, p, dstlist) p = nextword(c, flag, p, dstlist)
+
+static char *
+stputs_split(const char *data, const char *syntax, int flag, char *p,
+ struct worddest *dst)
+{
+ const char *ifs;
+ char c;
+
+ ifs = ifsset() ? ifsval() : " \t\n";
+ while (*data) {
+ CHECKSTRSPACE(2, p);
+ c = *data++;
+ if (strchr(ifs, c) != NULL) {
+ NEXTWORD(c, flag, p, dst);
+ continue;
+ }
+ if (flag & EXP_GLOB && syntax[(int)c] == CCTL)
+ USTPUTC(CTLESC, p);
+ USTPUTC(c, p);
+ }
+ return (p);
+}
+#define STPUTS_SPLIT(data, syntax, flag, p, dst) p = stputs_split((data), syntax, flag, p, dst)
+
/*
* Perform expansions on an argument, placing the resulting list of arguments
* in arglist. Parameter expansion, command substitution and arithmetic
@@ -184,34 +223,31 @@ stputs_quotes(const char *data, const char *syntax, char *p)
void
expandarg(union node *arg, struct arglist *arglist, int flag)
{
- struct arglist exparg;
- char *p;
+ struct worddest exparg;
+ if (fflag)
+ flag &= ~EXP_GLOB;
argbackq = arg->narg.backquote;
+ exparg.list = arglist;
+ exparg.state = WORD_IDLE;
STARTSTACKSTR(expdest);
- ifsfirst.next = NULL;
- ifslastp = NULL;
- argstr(arg->narg.text, flag);
+ argstr(arg->narg.text, flag, &exparg);
if (arglist == NULL) {
STACKSTRNUL(expdest);
return; /* here document expanded */
}
- STPUTC('\0', expdest);
- p = grabstackstr(expdest);
- emptyarglist(&exparg);
- if (flag & EXP_FULL) {
- ifsbreakup(p, &exparg);
- expandmeta(&exparg, arglist);
- } else
- appendarglist(arglist, p);
- while (ifsfirst.next != NULL) {
- struct ifsregion *ifsp;
- INTOFF;
- ifsp = ifsfirst.next->next;
- ckfree(ifsfirst.next);
- ifsfirst.next = ifsp;
- INTON;
+ if ((flag & EXP_SPLIT) == 0 || expdest != stackblock() ||
+ exparg.state == WORD_QUOTEMARK) {
+ STPUTC('\0', expdest);
+ if (flag & EXP_SPLIT) {
+ if (flag & EXP_GLOB)
+ expandmeta(grabstackstr(expdest), exparg.list);
+ else
+ appendarglist(exparg.list, grabstackstr(expdest));
+ }
}
+ if ((flag & EXP_SPLIT) == 0)
+ appendarglist(arglist, grabstackstr(expdest));
}
@@ -221,15 +257,16 @@ expandarg(union node *arg, struct arglist *arglist, int flag)
* expansion, and tilde expansion if requested via EXP_TILDE/EXP_VARTILDE.
* Processing ends at a CTLENDVAR or CTLENDARI character as well as '\0'.
* This is used to expand word in ${var+word} etc.
- * If EXP_FULL or EXP_CASE are set, keep and/or generate CTLESC
+ * If EXP_GLOB or EXP_CASE are set, keep and/or generate CTLESC
* characters to allow for further processing.
- * If EXP_FULL is set, also preserve CTLQUOTEMARK characters.
+ *
+ * If EXP_SPLIT is set, dst receives any complete words produced.
*/
static char *
-argstr(char *p, int flag)
+argstr(char *p, int flag, struct worddest *dst)
{
char c;
- int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
+ int quotes = flag & (EXP_GLOB | EXP_CASE); /* do CTLESC */
int firsteq = 1;
int split_lit;
int lit_quoted;
@@ -253,32 +290,33 @@ argstr(char *p, int flag)
if (p[0] == CTLVAR && (p[1] & VSQUOTE) != 0 &&
p[2] == '@' && p[3] == '=')
break;
- if ((flag & EXP_FULL) != 0)
- USTPUTC(c, expdest);
+ if ((flag & EXP_SPLIT) != 0 && expdest == stackblock())
+ dst->state = WORD_QUOTEMARK;
break;
case CTLQUOTEEND:
lit_quoted = 0;
break;
case CTLESC:
- if (quotes)
- USTPUTC(c, expdest);
c = *p++;
+ if (split_lit && !lit_quoted &&
+ strchr(ifsset() ? ifsval() : " \t\n", c) != NULL) {
+ NEXTWORD(c, flag, expdest, dst);
+ break;
+ }
+ if (quotes)
+ USTPUTC(CTLESC, expdest);
USTPUTC(c, expdest);
- if (split_lit && !lit_quoted)
- recordregion(expdest - stackblock() -
- (quotes ? 2 : 1),
- expdest - stackblock(), 0);
break;
case CTLVAR:
- p = evalvar(p, flag);
+ p = evalvar(p, flag, dst);
break;
case CTLBACKQ:
case CTLBACKQ|CTLQUOTE:
- expbackq(argbackq->n, c & CTLQUOTE, flag);
+ expbackq(argbackq->n, c & CTLQUOTE, flag, dst);
argbackq = argbackq->next;
break;
case CTLARI:
- p = expari(p);
+ p = expari(p, flag, dst);
break;
case ':':
case '=':
@@ -286,10 +324,12 @@ argstr(char *p, int flag)
* sort of a hack - expand tildes in variable
* assignments (after the first '=' and after ':'s).
*/
+ if (split_lit && !lit_quoted &&
+ strchr(ifsset() ? ifsval() : " \t\n", c) != NULL) {
+ NEXTWORD(c, flag, expdest, dst);
+ break;
+ }
USTPUTC(c, expdest);
- if (split_lit && !lit_quoted)
- recordregion(expdest - stackblock() - 1,
- expdest - stackblock(), 0);
if (flag & EXP_VARTILDE && *p == '~' &&
(c != '=' || firsteq)) {
if (c == '=')
@@ -298,10 +338,12 @@ argstr(char *p, int flag)
}
break;
default:
+ if (split_lit && !lit_quoted &&
+ strchr(ifsset() ? ifsval() : " \t\n", c) != NULL) {
+ NEXTWORD(c, flag, expdest, dst);
+ break;
+ }
USTPUTC(c, expdest);
- if (split_lit && !lit_quoted)
- recordregion(expdest - stackblock() - 1,
- expdest - stackblock(), 0);
}
}
}
@@ -345,7 +387,7 @@ exptilde(char *p, int flag)
*p = c;
if (home == NULL || *home == '\0')
return (startp);
- strtodest(home, flag, VSNORMAL, 1);
+ strtodest(home, flag, VSNORMAL, 1, NULL);
return (p);
}
p++;
@@ -353,51 +395,11 @@ exptilde(char *p, int flag)
}
-static void
-removerecordregions(int endoff)
-{
- if (ifslastp == NULL)
- return;
-
- if (ifsfirst.endoff > endoff) {
- while (ifsfirst.next != NULL) {
- struct ifsregion *ifsp;
- INTOFF;
- ifsp = ifsfirst.next->next;
- ckfree(ifsfirst.next);
- ifsfirst.next = ifsp;
- INTON;
- }
- if (ifsfirst.begoff > endoff)
- ifslastp = NULL;
- else {
- ifslastp = &ifsfirst;
- ifsfirst.endoff = endoff;
- }
- return;
- }
-
- ifslastp = &ifsfirst;
- while (ifslastp->next && ifslastp->next->begoff < endoff)
- ifslastp=ifslastp->next;
- while (ifslastp->next != NULL) {
- struct ifsregion *ifsp;
- INTOFF;
- ifsp = ifslastp->next->next;
- ckfree(ifslastp->next);
- ifslastp->next = ifsp;
- INTON;
- }
- if (ifslastp->endoff > endoff)
- ifslastp->endoff = endoff;
-}
-
/*
* Expand arithmetic expression.
- * Note that flag is not required as digits never require CTLESC characters.
*/
static char *
-expari(char *p)
+expari(char *p, int flag, struct worddest *dst)
{
char *q, *start;
arith_t result;
@@ -407,8 +409,7 @@ expari(char *p)
quoted = *p++ == '"';
begoff = expdest - stackblock();
- p = argstr(p, 0);
- removerecordregions(begoff);
+ p = argstr(p, 0, NULL);
STPUTC('\0', expdest);
start = stackblock() + begoff;
@@ -425,7 +426,7 @@ expari(char *p)
adj = strlen(expdest);
STADJUST(adj, expdest);
if (!quoted)
- recordregion(begoff, expdest - stackblock(), 0);
+ reprocess(expdest - adj - stackblock(), flag, VSNORMAL, 0, dst);
return p;
}
@@ -434,35 +435,34 @@ expari(char *p)
* Perform command substitution.
*/
static void
-expbackq(union node *cmd, int quoted, int flag)
+expbackq(union node *cmd, int quoted, int flag, struct worddest *dst)
{
struct backcmd in;
int i;
char buf[128];
char *p;
char *dest = expdest;
- struct ifsregion saveifs, *savelastp;
struct nodelist *saveargbackq;
char lastc;
- int startloc = dest - stackblock();
char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
- int quotes = flag & (EXP_FULL | EXP_CASE);
+ int quotes = flag & (EXP_GLOB | EXP_CASE);
size_t nnl;
+ const char *ifs;
INTOFF;
- saveifs = ifsfirst;
- savelastp = ifslastp;
saveargbackq = argbackq;
p = grabstackstr(dest);
evalbackcmd(cmd, &in);
ungrabstackstr(p, dest);
- ifsfirst = saveifs;
- ifslastp = savelastp;
argbackq = saveargbackq;
p = in.buf;
lastc = '\0';
nnl = 0;
+ if (!quoted && flag & EXP_SPLIT)
+ ifs = ifsset() ? ifsval() : " \t\n";
+ else
+ ifs = "";
/* Don't copy trailing newlines */
for (;;) {
if (--in.nleft < 0) {
@@ -476,15 +476,27 @@ expbackq(union node *cmd, int quoted, int flag)
in.nleft = i - 1;
}
lastc = *p++;
- if (lastc != '\0') {
- if (lastc == '\n') {
- nnl++;
- } else {
- CHECKSTRSPACE(nnl + 2, dest);
- while (nnl > 0) {
- nnl--;
- USTPUTC('\n', dest);
+ if (lastc == '\0')
+ continue;
+ if (lastc == '\n') {
+ nnl++;
+ } else {
+ if (nnl > 0) {
+ if (strchr(ifs, '\n') != NULL) {
+ NEXTWORD('\n', flag, dest, dst);
+ nnl = 0;
+ } else {
+ CHECKSTRSPACE(nnl + 2, dest);
+ while (nnl > 0) {
+ nnl--;
+ USTPUTC('\n', dest);
+ }
}
+ }
+ if (strchr(ifs, lastc) != NULL)
+ NEXTWORD(lastc, flag, dest, dst);
+ else {
+ CHECKSTRSPACE(2, dest);
if (quotes && syntax[(int)lastc] == CCTL)
USTPUTC(CTLESC, dest);
USTPUTC(lastc, dest);
@@ -498,8 +510,6 @@ expbackq(union node *cmd, int quoted, int flag)
ckfree(in.buf);
if (in.jp)
exitstatus = waitforjob(in.jp, (int *)NULL);
- if (quoted == 0)
- recordregion(startloc, dest - stackblock(), 0);
TRACE(("expbackq: size=%td: \"%.*s\"\n",
((dest - stackblock()) - startloc),
(int)((dest - stackblock()) - startloc),
@@ -521,18 +531,17 @@ recordleft(const char *str, const char *loc, char *startp)
*startp++ = *loc++;
}
-static int
-subevalvar_trim(char *p, int strloc, int subtype, int startloc, int quotes)
+static void
+subevalvar_trim(char *p, int strloc, int subtype, int startloc)
{
char *startp;
char *loc = NULL;
- char *q;
char *str;
int c = 0;
struct nodelist *saveargbackq = argbackq;
int amount;
- argstr(p, EXP_CASE | EXP_TILDE);
+ argstr(p, EXP_CASE | EXP_TILDE, NULL);
STACKSTRNUL(expdest);
argbackq = saveargbackq;
startp = stackblock() + startloc;
@@ -543,72 +552,56 @@ subevalvar_trim(char *p, int strloc, int subtype, int startloc, int quotes)
for (loc = startp; loc < str; loc++) {
c = *loc;
*loc = '\0';
- if (patmatch(str, startp, quotes)) {
+ if (patmatch(str, startp)) {
*loc = c;
recordleft(str, loc, startp);
- return 1;
+ return;
}
*loc = c;
- if (quotes && *loc == CTLESC)
- loc++;
}
- return 0;
+ break;
case VSTRIMLEFTMAX:
for (loc = str - 1; loc >= startp;) {
c = *loc;
*loc = '\0';
- if (patmatch(str, startp, quotes)) {
+ if (patmatch(str, startp)) {
*loc = c;
recordleft(str, loc, startp);
- return 1;
+ return;
}
*loc = c;
loc--;
- if (quotes && loc > startp && *(loc - 1) == CTLESC) {
- for (q = startp; q < loc; q++)
- if (*q == CTLESC)
- q++;
- if (q > loc)
- loc--;
- }
}
- return 0;
+ break;
case VSTRIMRIGHT:
for (loc = str - 1; loc >= startp;) {
- if (patmatch(str, loc, quotes)) {
+ if (patmatch(str, loc)) {
amount = loc - expdest;
STADJUST(amount, expdest);
- return 1;
+ return;
}
loc--;
- if (quotes && loc > startp && *(loc - 1) == CTLESC) {
- for (q = startp; q < loc; q++)
- if (*q == CTLESC)
- q++;
- if (q > loc)
- loc--;
- }
}
- return 0;
+ break;
case VSTRIMRIGHTMAX:
for (loc = startp; loc < str - 1; loc++) {
- if (patmatch(str, loc, quotes)) {
+ if (patmatch(str, loc)) {
amount = loc - expdest;
STADJUST(amount, expdest);
- return 1;
+ return;
}
- if (quotes && *loc == CTLESC)
- loc++;
}
- return 0;
+ break;
default:
abort();
}
+ amount = (expdest - stackblock() - strloc) + 1;
+ STADJUST(-amount, expdest);
}
@@ -620,7 +613,7 @@ subevalvar_misc(char *p, const char *var, int subtype, int startloc,
struct nodelist *saveargbackq = argbackq;
int amount;
- argstr(p, EXP_TILDE);
+ argstr(p, EXP_TILDE, NULL);
STACKSTRNUL(expdest);
argbackq = saveargbackq;
startp = stackblock() + startloc;
@@ -653,7 +646,7 @@ subevalvar_misc(char *p, const char *var, int subtype, int startloc,
*/
static char *
-evalvar(char *p, int flag)
+evalvar(char *p, int flag, struct worddest *dst)
{
int subtype;
int varflags;
@@ -666,9 +659,7 @@ evalvar(char *p, int flag)
int startloc;
int varlen;
int varlenb;
- int easy;
- int quotes = flag & (EXP_FULL | EXP_CASE);
- int record = 0;
+ char buf[21];
varflags = (unsigned char)*p++;
subtype = varflags & VSTYPE;
@@ -710,10 +701,16 @@ again: /* jump here after setting a variable with ${var=text} */
if (set && subtype != VSPLUS) {
/* insert the value of the variable */
if (special) {
- if (varflags & VSLINENO)
- STPUTBIN(var, p - var - 1, expdest);
- else
- varvalue(var, varflags & VSQUOTE, subtype, flag);
+ if (varflags & VSLINENO) {
+ if (p - var > (ptrdiff_t)sizeof(buf))
+ abort();
+ memcpy(buf, var, p - var - 1);
+ buf[p - var - 1] = '\0';
+ strtodest(buf, flag, subtype,
+ varflags & VSQUOTE, dst);
+ } else
+ varvalue(var, varflags & VSQUOTE, subtype, flag,
+ dst);
if (subtype == VSLENGTH) {
varlenb = expdest - stackblock() - startloc;
varlen = varlenb;
@@ -734,35 +731,29 @@ again: /* jump here after setting a variable with ${var=text} */
}
else
strtodest(val, flag, subtype,
- varflags & VSQUOTE);
+ varflags & VSQUOTE, dst);
}
}
if (subtype == VSPLUS)
set = ! set;
- easy = ((varflags & VSQUOTE) == 0 ||
- (*var == '@' && shellparam.nparam != 1));
-
-
switch (subtype) {
case VSLENGTH:
- expdest = cvtnum(varlen, expdest);
- record = 1;
+ cvtnum(varlen, buf);
+ strtodest(buf, flag, VSNORMAL, varflags & VSQUOTE, dst);
break;
case VSNORMAL:
- record = easy;
break;
case VSPLUS:
case VSMINUS:
if (!set) {
- argstr(p, flag | (flag & EXP_FULL ? EXP_SPLIT_LIT : 0) |
- (varflags & VSQUOTE ? EXP_LIT_QUOTED : 0));
+ argstr(p, flag | (flag & EXP_SPLIT ? EXP_SPLIT_LIT : 0) |
+ (varflags & VSQUOTE ? EXP_LIT_QUOTED : 0), dst);
break;
}
- record = easy;
break;
case VSTRIMLEFT:
@@ -777,14 +768,10 @@ again: /* jump here after setting a variable with ${var=text} */
*/
STPUTC('\0', expdest);
patloc = expdest - stackblock();
- if (subevalvar_trim(p, patloc, subtype,
- startloc, quotes) == 0) {
- int amount = (expdest - stackblock() - patloc) + 1;
- STADJUST(-amount, expdest);
- }
- /* Remove any recorded regions beyond start of variable */
- removerecordregions(startloc);
- record = 1;
+ subevalvar_trim(p, patloc, subtype, startloc);
+ reprocess(startloc, flag, VSNORMAL, varflags & VSQUOTE, dst);
+ if (flag & EXP_SPLIT && *var == '@' && varflags & VSQUOTE)
+ dst->state = WORD_QUOTEMARK;
break;
case VSASSIGN:
@@ -793,16 +780,10 @@ again: /* jump here after setting a variable with ${var=text} */
if (subevalvar_misc(p, var, subtype, startloc,
varflags)) {
varflags &= ~VSNUL;
- /*
- * Remove any recorded regions beyond
- * start of variable
- */
- removerecordregions(startloc);
goto again;
}
break;
}
- record = easy;
break;
case VSERROR:
@@ -814,11 +795,6 @@ again: /* jump here after setting a variable with ${var=text} */
abort();
}
- if (record)
- recordregion(startloc, expdest - stackblock(),
- varflags & VSQUOTE || (ifsset() && ifsval()[0] == '\0' &&
- (*var == '@' || *var == '*')));
-
if (subtype != VSNORMAL) { /* skip to end of alternative */
int nesting = 1;
for (;;) {
@@ -884,26 +860,80 @@ varisset(const char *name, int nulok)
}
static void
-strtodest(const char *p, int flag, int subtype, int quoted)
+strtodest(const char *p, int flag, int subtype, int quoted,
+ struct worddest *dst)
{
- if (flag & (EXP_FULL | EXP_CASE) && subtype != VSLENGTH)
+ if (subtype == VSLENGTH || subtype == VSTRIMLEFT ||
+ subtype == VSTRIMLEFTMAX || subtype == VSTRIMRIGHT ||
+ subtype == VSTRIMRIGHTMAX)
+ STPUTS(p, expdest);
+ else if (flag & EXP_SPLIT && !quoted && dst != NULL)
+ STPUTS_SPLIT(p, BASESYNTAX, flag, expdest, dst);
+ else if (flag & (EXP_GLOB | EXP_CASE))
STPUTS_QUOTES(p, quoted ? DQSYNTAX : BASESYNTAX, expdest);
else
STPUTS(p, expdest);
}
+static void
+reprocess(int startloc, int flag, int subtype, int quoted,
+ struct worddest *dst)
+{
+ static char *buf = NULL;
+ static size_t buflen = 0;
+ char *startp;
+ size_t len, zpos, zlen;
+
+ startp = stackblock() + startloc;
+ len = expdest - startp;
+ if (len >= SIZE_MAX / 2)
+ abort();
+ INTOFF;
+ if (len >= buflen) {
+ ckfree(buf);
+ buf = NULL;
+ }
+ if (buflen < 128)
+ buflen = 128;
+ while (len >= buflen)
+ buflen <<= 1;
+ if (buf == NULL)
+ buf = ckmalloc(buflen);
+ INTON;
+ memcpy(buf, startp, len);
+ buf[len] = '\0';
+ STADJUST(-len, expdest);
+ for (zpos = 0;;) {
+ zlen = strlen(buf + zpos);
+ strtodest(buf + zpos, flag, subtype, quoted, dst);
+ zpos += zlen + 1;
+ if (zpos == len + 1)
+ break;
+ if (flag & EXP_SPLIT && (quoted || (zlen > 0 && zpos < len)))
+ NEXTWORD('\0', flag, expdest, dst);
+ }
+}
+
/*
* Add the value of a specialized variable to the stack string.
*/
static void
-varvalue(const char *name, int quoted, int subtype, int flag)
+varvalue(const char *name, int quoted, int subtype, int flag,
+ struct worddest *dst)
{
int num;
char *p;
int i;
+ int splitlater;
char sep[2];
char **ap;
+ char buf[(NSHORTOPTS > 10 ? NSHORTOPTS : 10) + 1];
+
+ if (subtype == VSLENGTH)
+ flag &= ~EXP_FULL;
+ splitlater = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX ||
+ subtype == VSTRIMRIGHT || subtype == VSTRIMRIGHTMAX;
switch (*name) {
case '$':
@@ -919,18 +949,28 @@ varvalue(const char *name, int quoted, int subtype, int flag)
num = backgndpidval();
break;
case '-':
+ p = buf;
for (i = 0 ; i < NSHORTOPTS ; i++) {
if (optlist[i].val)
- STPUTC(optlist[i].letter, expdest);
+ *p++ = optlist[i].letter;
}
+ *p = '\0';
+ strtodest(buf, flag, subtype, quoted, dst);
return;
case '@':
- if (flag & EXP_FULL && quoted) {
+ if (flag & EXP_SPLIT && quoted) {
for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
- strtodest(p, flag, subtype, quoted);
- if (*ap)
- STPUTC('\0', expdest);
+ strtodest(p, flag, subtype, quoted, dst);
+ if (*ap) {
+ if (splitlater)
+ STPUTC('\0', expdest);
+ else
+ NEXTWORD('\0', flag, expdest,
+ dst);
+ }
}
+ if (shellparam.nparam > 0)
+ dst->state = WORD_QUOTEMARK;
return;
}
/* FALLTHROUGH */
@@ -941,13 +981,17 @@ varvalue(const char *name, int quoted, int subtype, int flag)
sep[0] = ' ';
sep[1] = '\0';
for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
- strtodest(p, flag, subtype, quoted);
+ strtodest(p, flag, subtype, quoted, dst);
if (!*ap)
break;
if (sep[0])
- strtodest(sep, flag, subtype, quoted);
- else if (flag & EXP_FULL && !quoted && **ap != '\0')
- STPUTC('\0', expdest);
+ strtodest(sep, flag, subtype, quoted, dst);
+ else if (flag & EXP_SPLIT && !quoted && **ap != '\0') {
+ if (splitlater)
+ STPUTC('\0', expdest);
+ else
+ NEXTWORD('\0', flag, expdest, dst);
+ }
}
return;
default:
@@ -959,192 +1003,53 @@ varvalue(const char *name, int quoted, int subtype, int flag)
p = shellparam.p[num - 1];
else
return;
- strtodest(p, flag, subtype, quoted);
+ strtodest(p, flag, subtype, quoted, dst);
}
return;
}
- expdest = cvtnum(num, expdest);
-}
-
-
-
-/*
- * Record the fact that we have to scan this region of the
- * string for IFS characters.
- */
-
-static void
-recordregion(int start, int end, int inquotes)
-{
- struct ifsregion *ifsp;
-
- INTOFF;
- if (ifslastp == NULL) {
- ifsp = &ifsfirst;
- } else {
- if (ifslastp->endoff == start
- && ifslastp->inquotes == inquotes) {
- /* extend previous area */
- ifslastp->endoff = end;
- INTON;
- return;
- }
- ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
- ifslastp->next = ifsp;
- }
- ifslastp = ifsp;
- ifslastp->next = NULL;
- ifslastp->begoff = start;
- ifslastp->endoff = end;
- ifslastp->inquotes = inquotes;
- INTON;
+ cvtnum(num, buf);
+ strtodest(buf, flag, subtype, quoted, dst);
}
-/*
- * Break the argument string into pieces based upon IFS and add the
- * strings to the argument list. The regions of the string to be
- * searched for IFS characters have been stored by recordregion.
- * CTLESC characters are preserved but have little effect in this pass
- * other than escaping CTL* characters. In particular, they do not escape
- * IFS characters: that should be done with the ifsregion mechanism.
- * CTLQUOTEMARK characters are used to preserve empty quoted strings.
- * This pass treats them as a regular character, making the string non-empty.
- * Later, they are removed along with the other CTL* characters.
- */
-static void
-ifsbreakup(char *string, struct arglist *arglist)
-{
- struct ifsregion *ifsp;
- char *start;
- char *p;
- char *q;
- const char *ifs;
- const char *ifsspc;
- int had_param_ch = 0;
-
- start = string;
-
- if (ifslastp == NULL) {
- /* Return entire argument, IFS doesn't apply to any of it */
- appendarglist(arglist, start);
- return;
- }
-
- ifs = ifsset() ? ifsval() : " \t\n";
-
- for (ifsp = &ifsfirst; ifsp != NULL; ifsp = ifsp->next) {
- p = string + ifsp->begoff;
- while (p < string + ifsp->endoff) {
- q = p;
- if (*p == CTLESC)
- p++;
- if (ifsp->inquotes) {
- /* Only NULs (should be from "$@") end args */
- had_param_ch = 1;
- if (*p != 0) {
- p++;
- continue;
- }
- ifsspc = NULL;
- } else {
- if (!strchr(ifs, *p)) {
- had_param_ch = 1;
- p++;
- continue;
- }
- ifsspc = strchr(" \t\n", *p);
-
- /* Ignore IFS whitespace at start */
- if (q == start && ifsspc != NULL) {
- p++;
- start = p;
- continue;
- }
- had_param_ch = 0;
- }
-
- /* Save this argument... */
- *q = '\0';
- appendarglist(arglist, start);
- p++;
-
- if (ifsspc != NULL) {
- /* Ignore further trailing IFS whitespace */
- for (; p < string + ifsp->endoff; p++) {
- q = p;
- if (*p == CTLESC)
- p++;
- if (strchr(ifs, *p) == NULL) {
- p = q;
- break;
- }
- if (strchr(" \t\n", *p) == NULL) {
- p++;
- break;
- }
- }
- }
- start = p;
- }
- }
-
- /*
- * Save anything left as an argument.
- * Traditionally we have treated 'IFS=':'; set -- x$IFS' as
- * generating 2 arguments, the second of which is empty.
- * Some recent clarification of the Posix spec say that it
- * should only generate one....
- */
- if (had_param_ch || *start != 0)
- appendarglist(arglist, start);
-}
-
-
static char expdir[PATH_MAX];
#define expdir_end (expdir + sizeof(expdir))
/*
* Perform pathname generation and remove control characters.
- * At this point, the only control characters should be CTLESC and CTLQUOTEMARK.
+ * At this point, the only control characters should be CTLESC.
* The results are stored in the list dstlist.
*/
static void
-expandmeta(struct arglist *srclist, struct arglist *dstlist)
+expandmeta(char *pattern, struct arglist *dstlist)
{
char *p;
int firstmatch;
- int i;
char c;
- for (i = 0; i < srclist->count; i++) {
- firstmatch = dstlist->count;
- if (!fflag) {
- p = srclist->args[i];
- for (; (c = *p) != '\0'; p++) {
- /* fast check for meta chars */
- if (c == '*' || c == '?' || c == '[') {
- INTOFF;
- expmeta(expdir, srclist->args[i],
- dstlist);
- INTON;
- break;
- }
- }
- }
- if (dstlist->count == firstmatch) {
- /*
- * no matches
- */
- rmescapes(srclist->args[i]);
- appendarglist(dstlist, srclist->args[i]);
- } else {
- qsort(&dstlist->args[firstmatch],
- dstlist->count - firstmatch,
- sizeof(dstlist->args[0]), expsortcmp);
+ firstmatch = dstlist->count;
+ p = pattern;
+ for (; (c = *p) != '\0'; p++) {
+ /* fast check for meta chars */
+ if (c == '*' || c == '?' || c == '[') {
+ INTOFF;
+ expmeta(expdir, pattern, dstlist);
+ INTON;
+ break;
}
}
+ if (dstlist->count == firstmatch) {
+ /*
+ * no matches
+ */
+ rmescapes(pattern);
+ appendarglist(dstlist, pattern);
+ } else {
+ qsort(&dstlist->args[firstmatch],
+ dstlist->count - firstmatch,
+ sizeof(dstlist->args[0]), expsortcmp);
+ }
}
@@ -1178,8 +1083,6 @@ expmeta(char *enddir, char *name, struct arglist *arglist)
if (*q == '!' || *q == '^')
q++;
for (;;) {
- while (*q == CTLQUOTEMARK)
- q++;
if (*q == CTLESC)
q++;
if (*q == '/' || *q == '\0')
@@ -1191,8 +1094,6 @@ expmeta(char *enddir, char *name, struct arglist *arglist)
}
} else if (*p == '\0')
break;
- else if (*p == CTLQUOTEMARK)
- continue;
else {
if (*p == CTLESC)
esc++;
@@ -1207,8 +1108,6 @@ expmeta(char *enddir, char *name, struct arglist *arglist)
if (enddir != expdir)
metaflag++;
for (p = name ; ; p++) {
- if (*p == CTLQUOTEMARK)
- continue;
if (*p == CTLESC)
p++;
*enddir++ = *p;
@@ -1225,8 +1124,6 @@ expmeta(char *enddir, char *name, struct arglist *arglist)
if (start != name) {
p = name;
while (p < start) {
- while (*p == CTLQUOTEMARK)
- p++;
if (*p == CTLESC)
p++;
*enddir++ = *p++;
@@ -1255,8 +1152,6 @@ expmeta(char *enddir, char *name, struct arglist *arglist)
}
matchdot = 0;
p = start;
- while (*p == CTLQUOTEMARK)
- p++;
if (*p == CTLESC)
p++;
if (*p == '.')
@@ -1264,7 +1159,7 @@ expmeta(char *enddir, char *name, struct arglist *arglist)
while (! int_pending() && (dp = readdir(dirp)) != NULL) {
if (dp->d_name[0] == '.' && ! matchdot)
continue;
- if (patmatch(start, dp->d_name, 0)) {
+ if (patmatch(start, dp->d_name)) {
namlen = dp->d_namlen;
if (enddir + namlen + 1 > expdir_end)
continue;
@@ -1354,7 +1249,7 @@ match_charclass(const char *p, wchar_t chr, const char **end)
*/
static int
-patmatch(const char *pattern, const char *string, int squoted)
+patmatch(const char *pattern, const char *string)
{
const char *p, *q, *end;
const char *bt_p, *bt_q;
@@ -1372,16 +1267,10 @@ patmatch(const char *pattern, const char *string, int squoted)
goto backtrack;
return 1;
case CTLESC:
- if (squoted && *q == CTLESC)
- q++;
if (*q++ != *p++)
goto backtrack;
break;
- case CTLQUOTEMARK:
- continue;
case '?':
- if (squoted && *q == CTLESC)
- q++;
if (*q == '\0')
return 0;
if (localeisutf8) {
@@ -1397,7 +1286,7 @@ patmatch(const char *pattern, const char *string, int squoted)
break;
case '*':
c = *p;
- while (c == CTLQUOTEMARK || c == '*')
+ while (c == '*')
c = *++p;
/*
* If the pattern ends here, we know the string
@@ -1426,8 +1315,6 @@ patmatch(const char *pattern, const char *string, int squoted)
p++;
}
found = 0;
- if (squoted && *q == CTLESC)
- q++;
if (*q == '\0')
return 0;
if (localeisutf8) {
@@ -1443,8 +1330,6 @@ patmatch(const char *pattern, const char *string, int squoted)
c = '[';
goto dft;
}
- if (c == CTLQUOTEMARK)
- continue;
if (c == '[' && *p == ':') {
found |= match_charclass(p, chr, &end);
if (end != NULL)
@@ -1461,8 +1346,6 @@ patmatch(const char *pattern, const char *string, int squoted)
wc = (unsigned char)c;
if (*p == '-' && p[1] != ']') {
p++;
- while (*p == CTLQUOTEMARK)
- p++;
if (*p == CTLESC)
p++;
if (localeisutf8) {
@@ -1485,8 +1368,6 @@ patmatch(const char *pattern, const char *string, int squoted)
break;
}
dft: default:
- if (squoted && *q == CTLESC)
- q++;
if (*q == '\0')
return 0;
if (*q++ == c)
@@ -1499,8 +1380,6 @@ backtrack:
*/
if (bt_p == NULL)
return 0;
- if (squoted && *bt_q == CTLESC)
- bt_q++;
if (*bt_q == '\0')
return 0;
bt_q++;
@@ -1556,11 +1435,10 @@ casematch(union node *pattern, const char *val)
setstackmark(&smark);
argbackq = pattern->narg.backquote;
STARTSTACKSTR(expdest);
- ifslastp = NULL;
- argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
+ argstr(pattern->narg.text, EXP_TILDE | EXP_CASE, NULL);
STPUTC('\0', expdest);
p = grabstackstr(expdest);
- result = patmatch(p, val, 0);
+ result = patmatch(p, val);
popstackmark(&smark);
return result;
}
@@ -1569,7 +1447,7 @@ casematch(union node *pattern, const char *val)
* Our own itoa().
*/
-static char *
+static void
cvtnum(int num, char *buf)
{
char temp[32];
@@ -1585,8 +1463,7 @@ cvtnum(int num, char *buf)
if (neg)
*--p = '-';
- STPUTS(p, buf);
- return buf;
+ memcpy(buf, p, temp + 32 - p);
}
/*
diff --git a/bin/sh/expand.h b/bin/sh/expand.h
index d024e8f..7fa7613 100644
--- a/bin/sh/expand.h
+++ b/bin/sh/expand.h
@@ -43,12 +43,15 @@ struct arglist {
/*
* expandarg() flags
*/
-#define EXP_FULL 0x1 /* perform word splitting & file globbing */
+#define EXP_SPLIT 0x1 /* perform word splitting */
#define EXP_TILDE 0x2 /* do normal tilde expansion */
#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
#define EXP_SPLIT_LIT 0x20 /* IFS split literal text ${v+-a b c} */
#define EXP_LIT_QUOTED 0x40 /* for EXP_SPLIT_LIT, start off quoted */
+#define EXP_GLOB 0x80 /* perform file globbing */
+
+#define EXP_FULL (EXP_SPLIT | EXP_GLOB)
void emptyarglist(struct arglist *);
diff --git a/contrib/binutils/bfd/elf32-arm.c b/contrib/binutils/bfd/elf32-arm.c
index 753cdcc..e20ccca 100644
--- a/contrib/binutils/bfd/elf32-arm.c
+++ b/contrib/binutils/bfd/elf32-arm.c
@@ -7720,12 +7720,26 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
refers to is in a different object. We can't tell for
sure yet, because something later might force the
symbol local. */
- if (r_type != R_ARM_ABS32
- && r_type != R_ARM_REL32
- && r_type != R_ARM_ABS32_NOI
- && r_type != R_ARM_REL32_NOI
- && r_type != R_ARM_ABS12)
- h->needs_plt = 1;
+ switch (r_type)
+ {
+ case R_ARM_ABS12:
+ case R_ARM_ABS32:
+ case R_ARM_ABS32_NOI:
+ case R_ARM_REL32:
+ case R_ARM_REL32_NOI:
+ case R_ARM_MOVW_ABS_NC:
+ case R_ARM_MOVT_ABS:
+ case R_ARM_MOVW_PREL_NC:
+ case R_ARM_MOVT_PREL:
+ case R_ARM_THM_MOVW_ABS_NC:
+ case R_ARM_THM_MOVT_ABS:
+ case R_ARM_THM_MOVW_PREL_NC:
+ case R_ARM_THM_MOVT_PREL:
+ break;
+ default:
+ h->needs_plt = 1;
+ break;
+ }
/* If we create a PLT entry, this relocation will reference
it, even if it's an ABS32 relocation. */
diff --git a/lib/libmd/mdXhl.c b/lib/libmd/mdXhl.c
index f2e918f..378d8ad 100644
--- a/lib/libmd/mdXhl.c
+++ b/lib/libmd/mdXhl.c
@@ -59,14 +59,18 @@ MDXFileChunk(const char *filename, char *buf, off_t ofs, off_t len)
f = open(filename, O_RDONLY);
if (f < 0)
return 0;
- if (fstat(f, &stbuf) < 0)
- return 0;
+ if (fstat(f, &stbuf) < 0) {
+ i = -1;
+ goto error;
+ }
if (ofs > stbuf.st_size)
ofs = stbuf.st_size;
if ((len == 0) || (len > stbuf.st_size - ofs))
len = stbuf.st_size - ofs;
- if (lseek(f, ofs, SEEK_SET) < 0)
- return 0;
+ if (lseek(f, ofs, SEEK_SET) < 0) {
+ i = -1;
+ goto error;
+ }
n = len;
i = 0;
while (n > 0) {
@@ -79,6 +83,7 @@ MDXFileChunk(const char *filename, char *buf, off_t ofs, off_t len)
MDXUpdate(&ctx, buffer, i);
n -= i;
}
+error:
e = errno;
close(f);
errno = e;
diff --git a/lib/libstand/Makefile b/lib/libstand/Makefile
index a69a935..3126c1c 100644
--- a/lib/libstand/Makefile
+++ b/lib/libstand/Makefile
@@ -44,6 +44,12 @@ SRCS+= bcmp.c bcopy.c bzero.c ffs.c memccpy.c memchr.c memcmp.c memcpy.c \
.if ${MACHINE_CPUARCH} == "arm"
.PATH: ${LIBC_SRC}/arm/gen
+# Do not generate movt/movw, because the relocation fixup for them does not
+# translate to the -Bsymbolic -pie format required by self_reloc() in loader(8).
+# Also, the fpu is not available in a standalone environment.
+CFLAGS.clang+= -mllvm -arm-use-movt=0
+CFLAGS.clang+= -mfpu=none
+
# Compiler support functions
.PATH: ${LIBSTAND_SRC}/../../contrib/compiler-rt/lib/builtins/
# __clzsi2 and ctzsi2 for various builtin functions
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
index 6cf392a..d5050ac 100644
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -424,6 +424,8 @@ MAN= aac.4 \
rndtest.4 \
route.4 \
rp.4 \
+ rtwn.4 \
+ rtwnfw.4 \
rue.4 \
rum.4 \
run.4 \
diff --git a/share/man/man4/rtwn.4 b/share/man/man4/rtwn.4
new file mode 100644
index 0000000..1025849
--- /dev/null
+++ b/share/man/man4/rtwn.4
@@ -0,0 +1,165 @@
+.\" $OpenBSD: rtwn.4,v 1.2 2015/07/09 11:28:53 stsp Exp $
+.\"
+.\" Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+.\" Copyright (c) 2015 Stefan Sperling <stsp@openbsd.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd October 28, 2015
+.Dt RTWN 4
+.Os
+.Sh NAME
+.Nm rtwn
+.Nd Realtek RTL8188CE PCIe IEEE 802.11b/g/n wireless network device
+.Sh SYNOPSIS
+To compile this driver into the kernel,
+place the following lines in your
+kernel configuration file:
+.Bd -ragged -offset indent
+.Cd "device rtwn"
+.Cd "device rtwnfw"
+.Cd "device wlan"
+.Cd "device firmware"
+.Ed
+.Pp
+Alternatively, to load the driver as a
+module at boot time, place the following line in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+if_rtwn_load="YES"
+.Ed
+.Pp
+After you have read the license in
+.Pa /usr/share/doc/legal/realtek.LICENSE
+you will want to add the following lines to
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+legal.realtek.license_ack=1
+rtwn-rtl8192cfwU_load="YES"
+rtwn-rtl8192cfwU_B_load="YES"
+.Ed
+.Sh DESCRIPTION
+The
+.Nm
+driver supports PCIe wireless network devices based on the Realtek
+RTL8188CE chipset.
+.Pp
+The RTL8188CE is a highly integrated 802.11n adapter that combines a MAC,
+a 1T1R capable baseband and an RF in a single chip.
+It operates in the 2GHz spectrum only.
+.Pp
+These are the modes the
+.Nm
+driver can operate in:
+.Bl -tag -width "IBSS-masterXX"
+.It BSS mode
+Also known as
+.Em infrastructure
+mode, this is used when associating with an access point, through
+which all traffic passes.
+This mode is the default.
+.It monitor mode
+In this mode the driver is able to receive packets without
+associating with an access point.
+This disables the internal receive filter and enables the card to
+capture packets from networks which it wouldn't normally have access to,
+or to scan for access points.
+.El
+.Pp
+The
+.Nm
+driver can be configured to use
+Wired Equivalent Privacy (WEP) or
+Wi-Fi Protected Access (WPA-PSK and WPA2-PSK).
+WPA is the current encryption standard for wireless networks.
+It is strongly recommended that WEP
+not be used as the sole mechanism
+to secure wireless communication,
+due to serious weaknesses in it.
+.Pp
+The
+.Nm
+driver can be configured at runtime with
+.Xr ifconfig 8 .
+.Sh FILES
+The driver needs at least version 1.0 of the following firmware files,
+which are loaded when an interface is brought up:
+.Pp
+.Bl -tag -width Ds -offset indent -compact
+.It Pa /boot/kernel/rtwn-rtl8192cfwU.ko
+.It Pa /boot/kernel/rtwn-rtl8192cfwU_B.ko
+.El
+.Sh EXAMPLES
+Join an existing BSS network (i.e., connect to an access point):
+.Bd -literal -offset indent
+ifconfig wlan create wlandev rtwn0 inet 192.168.0.20 \e
+ netmask 0xffffff00
+.Ed
+.Pp
+Join a specific BSS network with network name
+.Dq Li my_net :
+.Pp
+.Dl "ifconfig wlan create wlandev rtwn0 ssid my_net up"
+.Pp
+Join a specific BSS network with 64-bit WEP encryption:
+.Bd -literal -offset indent
+ifconfig wlan create wlandev rtwn0 ssid my_net \e
+ wepmode on wepkey 0x1234567890 weptxkey 1 up
+.Ed
+.Sh DIAGNOSTICS
+.Bl -diag
+.It "could not read firmware %s"
+For some reason, the driver was unable to read the microcode file from the
+filesystem.
+The file might be missing or corrupted.
+.It "device timeout"
+A frame dispatched to the hardware for transmission did not complete in time.
+The driver will reset the hardware.
+This should not happen.
+.El
+.Sh SEE ALSO
+.Xr pci 4 ,
+.Xr rtwnfw 4 ,
+.Xr wlan 4 ,
+.Xr wlan_ccmp 4 ,
+.Xr wlan_tkip 4 ,
+.Xr wlan_wep 4 ,
+.Xr ifconfig 8 ,
+.Xr wpa_supplicant 8
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Ox 5.8 .
+.Sh AUTHORS
+The
+.Nm
+driver was written by
+.An -nosplit
+.An Stefan Sperling Aq Mt stsp@openbsd.org
+and ported by
+.An Kevin Lo Aq Mt kevlo@freebsd.org .
+It was based on the
+.Xr urtwn 4
+driver written by
+.An Damien Bergamini Aq Mt damien.bergamini@free.fr .
+.Sh CAVEATS
+The
+.Nm
+driver does not support any of the 802.11n capabilities offered by the
+adapters.
+Additional work is required in
+.Xr ieee80211 9
+before those features can be supported.
diff --git a/share/man/man4/rtwnfw.4 b/share/man/man4/rtwnfw.4
new file mode 100644
index 0000000..e4ab346
--- /dev/null
+++ b/share/man/man4/rtwnfw.4
@@ -0,0 +1,74 @@
+.\" Copyright (c) 2015 Kevin Lo
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd October 28, 2015
+.Dt RTWNFW 4
+.Os
+.Sh NAME
+.Nm rtwnfw
+.Nd "Firmware Module for Realtek Wireless driver"
+.Sh SYNOPSIS
+To compile this module into the kernel,
+place the following line in your
+kernel configuration file:
+.Bd -ragged -offset indent
+.Cd "device rtwnfw"
+.Ed
+.Pp
+This will include three firmware images inside the kernel.
+If you want to pick only the firmware image for your network adapter choose one
+of the following:
+.Bd -ragged -offset indent
+.Cd "device rtwn-rtl8192cfwU"
+.Cd "device rtwn-rtl8192cfwU_B"
+.Ed
+.Pp
+Alternatively, to load the driver as a
+module at boot time, place the following line in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+rtwn-rtl8192cfwU_load="YES"
+rtwn-rtl8192cfwU_B_load="YES"
+.Ed
+.Sh DESCRIPTION
+This module provides access to firmware sets for the
+Realtek RTL8188CE chip based PCIe adapters.
+It may be
+statically linked into the kernel, or loaded as a module.
+.Pp
+For the loaded firmware to be enabled for use the license at
+.Pa /usr/share/doc/legal/realtek.LICENSE
+must be agreed to by adding the following line to
+.Xr loader.conf 5 :
+.Pp
+.Dl "legal.realtek.license_ack=1"
+.Sh FILES
+.Bl -tag -width ".Pa /usr/share/doc/legal/realtek.LICENSE" -compact
+.It Pa /usr/share/doc/legal/realtek.LICENSE
+.Nm
+firmware license
+.El
+.Sh SEE ALSO
+.Xr rtwn 4 ,
+.Xr firmware 9
diff --git a/sys/arm64/arm64/identcpu.c b/sys/arm64/arm64/identcpu.c
index fb50922..72e2021 100644
--- a/sys/arm64/arm64/identcpu.c
+++ b/sys/arm64/arm64/identcpu.c
@@ -37,9 +37,12 @@ __FBSDID("$FreeBSD$");
#include <sys/sysctl.h>
#include <sys/systm.h>
+#include <machine/atomic.h>
#include <machine/cpu.h>
#include <machine/cpufunc.h>
+static int ident_lock;
+
char machine[] = "arm64";
SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0,
@@ -56,6 +59,7 @@ SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0,
* Aff0 - CPU number in Aff1 cluster
*/
uint64_t __cpu_affinity[MAXCPU];
+static u_int cpu_aff_levels;
struct cpu_desc {
u_int cpu_impl;
@@ -64,9 +68,32 @@ struct cpu_desc {
u_int cpu_revision;
const char *cpu_impl_name;
const char *cpu_part_name;
+
+ uint64_t mpidr;
+ uint64_t id_aa64afr0;
+ uint64_t id_aa64afr1;
+ uint64_t id_aa64dfr0;
+ uint64_t id_aa64dfr1;
+ uint64_t id_aa64isar0;
+ uint64_t id_aa64isar1;
+ uint64_t id_aa64mmfr0;
+ uint64_t id_aa64mmfr1;
+ uint64_t id_aa64pfr0;
+ uint64_t id_aa64pfr1;
};
struct cpu_desc cpu_desc[MAXCPU];
+static u_int cpu_print_regs;
+#define PRINT_ID_AA64_AFR0 0x00000001
+#define PRINT_ID_AA64_AFR1 0x00000002
+#define PRINT_ID_AA64_DFR0 0x00000004
+#define PRINT_ID_AA64_DFR1 0x00000008
+#define PRINT_ID_AA64_ISAR0 0x00000010
+#define PRINT_ID_AA64_ISAR1 0x00000020
+#define PRINT_ID_AA64_MMFR0 0x00000040
+#define PRINT_ID_AA64_MMFR1 0x00000080
+#define PRINT_ID_AA64_PFR0 0x00000100
+#define PRINT_ID_AA64_PFR1 0x00000200
struct cpu_parts {
u_int part_id;
@@ -124,7 +151,398 @@ const struct cpu_implementers cpu_implementers[] = {
CPU_IMPLEMENTER_NONE,
};
-void identify_cpu(void);
+void
+print_cpu_features(u_int cpu)
+{
+ int printed;
+
+ printf("CPU%3d: %s %s r%dp%d", cpu, cpu_desc[cpu].cpu_impl_name,
+ cpu_desc[cpu].cpu_part_name, cpu_desc[cpu].cpu_variant,
+ cpu_desc[cpu].cpu_revision);
+
+ printf(" affinity:");
+ switch(cpu_aff_levels) {
+ default:
+ case 4:
+ printf(" %2d", CPU_AFF3(cpu_desc[cpu].mpidr));
+ /* FALLTHROUGH */
+ case 3:
+ printf(" %2d", CPU_AFF2(cpu_desc[cpu].mpidr));
+ /* FALLTHROUGH */
+ case 2:
+ printf(" %2d", CPU_AFF1(cpu_desc[cpu].mpidr));
+ /* FALLTHROUGH */
+ case 1:
+ case 0: /* On UP this will be zero */
+ printf(" %2d", CPU_AFF0(cpu_desc[cpu].mpidr));
+ break;
+ }
+ printf("\n");
+
+ if (cpu != 0 && cpu_print_regs == 0)
+ return;
+
+#define SEP_STR ((printed++) == 0) ? "" : ","
+
+ /* AArch64 Instruction Set Attribute Register 0 */
+ if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_ISAR0) != 0) {
+ printed = 0;
+ printf(" Instruction Set Attributes 0 = <");
+ switch (ID_AA64ISAR0_AES(cpu_desc[cpu].id_aa64isar0)) {
+ case ID_AA64ISAR0_AES_NONE:
+ break;
+ case ID_AA64ISAR0_AES_BASE:
+ printf("%sAES", SEP_STR);
+ break;
+ case ID_AA64ISAR0_AES_PMULL:
+ printf("%sAES+PMULL", SEP_STR);
+ break;
+ default:
+ printf("%sUnknown AES", SEP_STR);
+ break;
+ }
+
+ switch (ID_AA64ISAR0_SHA1(cpu_desc[cpu].id_aa64isar0)) {
+ case ID_AA64ISAR0_SHA1_NONE:
+ break;
+ case ID_AA64ISAR0_SHA1_BASE:
+ printf("%sSHA1", SEP_STR);
+ break;
+ default:
+ printf("%sUnknown SHA1", SEP_STR);
+ break;
+ }
+
+ switch (ID_AA64ISAR0_SHA2(cpu_desc[cpu].id_aa64isar0)) {
+ case ID_AA64ISAR0_SHA2_NONE:
+ break;
+ case ID_AA64ISAR0_SHA2_BASE:
+ printf("%sSHA2", SEP_STR);
+ break;
+ default:
+ printf("%sUnknown SHA2", SEP_STR);
+ break;
+ }
+
+ switch (ID_AA64ISAR0_CRC32(cpu_desc[cpu].id_aa64isar0)) {
+ case ID_AA64ISAR0_CRC32_NONE:
+ break;
+ case ID_AA64ISAR0_CRC32_BASE:
+ printf("%sCRC32", SEP_STR);
+ break;
+ default:
+ printf("%sUnknown CRC32", SEP_STR);
+ break;
+ }
+
+ if ((cpu_desc[cpu].id_aa64isar0 & ~ID_AA64ISAR0_MASK) != 0)
+ printf("%s%#lx", SEP_STR,
+ cpu_desc[cpu].id_aa64isar0 & ~ID_AA64ISAR0_MASK);
+
+ printf(">\n");
+ }
+
+ /* AArch64 Instruction Set Attribute Register 1 */
+ if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_ISAR1) != 0) {
+ printf(" Instruction Set Attributes 1 = <%#lx>\n",
+ cpu_desc[cpu].id_aa64isar1);
+ }
+
+ /* AArch64 Processor Feature Register 0 */
+ if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_PFR0) != 0) {
+ printed = 0;
+ printf(" Processor Features 0 = <");
+ switch (ID_AA64PFR0_GIC(cpu_desc[cpu].id_aa64pfr0)) {
+ case ID_AA64PFR0_GIC_CPUIF_NONE:
+ break;
+ case ID_AA64PFR0_GIC_CPUIF_EN:
+ printf("%sGIC", SEP_STR);
+ break;
+ default:
+ printf("%sUnknown GIC interface", SEP_STR);
+ break;
+ }
+
+ switch (ID_AA64PFR0_ADV_SIMD(cpu_desc[cpu].id_aa64pfr0)) {
+ case ID_AA64PFR0_ADV_SIMD_NONE:
+ break;
+ case ID_AA64PFR0_ADV_SIMD_IMPL:
+ printf("%sAdvSIMD", SEP_STR);
+ break;
+ default:
+ printf("%sUnknown AdvSIMD", SEP_STR);
+ break;
+ }
+
+ switch (ID_AA64PFR0_FP(cpu_desc[cpu].id_aa64pfr0)) {
+ case ID_AA64PFR0_FP_NONE:
+ break;
+ case ID_AA64PFR0_FP_IMPL:
+ printf("%sFloat", SEP_STR);
+ break;
+ default:
+ printf("%sUnknown Float", SEP_STR);
+ break;
+ }
+
+ switch (ID_AA64PFR0_EL3(cpu_desc[cpu].id_aa64pfr0)) {
+ case ID_AA64PFR0_EL3_NONE:
+ printf("%sNo EL3", SEP_STR);
+ break;
+ case ID_AA64PFR0_EL3_64:
+ printf("%sEL3", SEP_STR);
+ break;
+ case ID_AA64PFR0_EL3_64_32:
+ printf("%sEL3 32", SEP_STR);
+ break;
+ default:
+ printf("%sUnknown EL3", SEP_STR);
+ break;
+ }
+
+ switch (ID_AA64PFR0_EL2(cpu_desc[cpu].id_aa64pfr0)) {
+ case ID_AA64PFR0_EL2_NONE:
+ printf("%sNo EL2", SEP_STR);
+ break;
+ case ID_AA64PFR0_EL2_64:
+ printf("%sEL2", SEP_STR);
+ break;
+ case ID_AA64PFR0_EL2_64_32:
+ printf("%sEL2 32", SEP_STR);
+ break;
+ default:
+ printf("%sUnknown EL2", SEP_STR);
+ break;
+ }
+
+ switch (ID_AA64PFR0_EL1(cpu_desc[cpu].id_aa64pfr0)) {
+ case ID_AA64PFR0_EL1_64:
+ printf("%sEL1", SEP_STR);
+ break;
+ case ID_AA64PFR0_EL1_64_32:
+ printf("%sEL1 32", SEP_STR);
+ break;
+ default:
+ printf("%sUnknown EL1", SEP_STR);
+ break;
+ }
+
+ switch (ID_AA64PFR0_EL0(cpu_desc[cpu].id_aa64pfr0)) {
+ case ID_AA64PFR0_EL0_64:
+ printf("%sEL0", SEP_STR);
+ break;
+ case ID_AA64PFR0_EL0_64_32:
+ printf("%sEL0 32", SEP_STR);
+ break;
+ default:
+ printf("%sUnknown EL0", SEP_STR);
+ break;
+ }
+
+ if ((cpu_desc[cpu].id_aa64pfr0 & ~ID_AA64PFR0_MASK) != 0)
+ printf("%s%#lx", SEP_STR,
+ cpu_desc[cpu].id_aa64pfr0 & ~ID_AA64PFR0_MASK);
+
+ printf(">\n");
+ }
+
+ /* AArch64 Processor Feature Register 1 */
+ if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_PFR1) != 0) {
+ printf(" Processor Features 1 = <%#lx>\n",
+ cpu_desc[cpu].id_aa64pfr1);
+ }
+
+ /* AArch64 Memory Model Feature Register 0 */
+ if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_MMFR0) != 0) {
+ printed = 0;
+ printf(" Memory Model Features 0 = <");
+ switch (ID_AA64MMFR0_TGRAN4(cpu_desc[cpu].id_aa64mmfr0)) {
+ case ID_AA64MMFR0_TGRAN4_NONE:
+ break;
+ case ID_AA64MMFR0_TGRAN4_IMPL:
+ printf("%s4k Granule", SEP_STR);
+ break;
+ default:
+ printf("%sUnknown 4k Granule", SEP_STR);
+ break;
+ }
+
+ switch (ID_AA64MMFR0_TGRAN16(cpu_desc[cpu].id_aa64mmfr0)) {
+ case ID_AA64MMFR0_TGRAN16_NONE:
+ break;
+ case ID_AA64MMFR0_TGRAN16_IMPL:
+ printf("%s16k Granule", SEP_STR);
+ break;
+ default:
+ printf("%sUnknown 16k Granule", SEP_STR);
+ break;
+ }
+
+ switch (ID_AA64MMFR0_TGRAN64(cpu_desc[cpu].id_aa64mmfr0)) {
+ case ID_AA64MMFR0_TGRAN64_NONE:
+ break;
+ case ID_AA64MMFR0_TGRAN64_IMPL:
+ printf("%s64k Granule", SEP_STR);
+ break;
+ default:
+ printf("%sUnknown 64k Granule", SEP_STR);
+ break;
+ }
+
+ switch (ID_AA64MMFR0_BIGEND(cpu_desc[cpu].id_aa64mmfr0)) {
+ case ID_AA64MMFR0_BIGEND_FIXED:
+ break;
+ case ID_AA64MMFR0_BIGEND_MIXED:
+ printf("%sMixedEndian", SEP_STR);
+ break;
+ default:
+ printf("%sUnknown Endian switching", SEP_STR);
+ break;
+ }
+
+ switch (ID_AA64MMFR0_BIGEND_EL0(cpu_desc[cpu].id_aa64mmfr0)) {
+ case ID_AA64MMFR0_BIGEND_EL0_FIXED:
+ break;
+ case ID_AA64MMFR0_BIGEND_EL0_MIXED:
+ printf("%sEL0 MixEndian", SEP_STR);
+ break;
+ default:
+ printf("%sUnknown EL0 Endian switching", SEP_STR);
+ break;
+ }
+
+ switch (ID_AA64MMFR0_S_NS_MEM(cpu_desc[cpu].id_aa64mmfr0)) {
+ case ID_AA64MMFR0_S_NS_MEM_NONE:
+ break;
+ case ID_AA64MMFR0_S_NS_MEM_DISTINCT:
+ printf("%sS/NS Mem", SEP_STR);
+ break;
+ default:
+ printf("%sUnknown S/NS Mem", SEP_STR);
+ break;
+ }
+
+ switch (ID_AA64MMFR0_ASID_BITS(cpu_desc[cpu].id_aa64mmfr0)) {
+ case ID_AA64MMFR0_ASID_BITS_8:
+ printf("%s8bit ASID", SEP_STR);
+ break;
+ case ID_AA64MMFR0_ASID_BITS_16:
+ printf("%s16bit ASID", SEP_STR);
+ break;
+ default:
+ printf("%sUnknown ASID", SEP_STR);
+ break;
+ }
+
+ switch (ID_AA64MMFR0_PA_RANGE(cpu_desc[cpu].id_aa64mmfr0)) {
+ case ID_AA64MMFR0_PA_RANGE_4G:
+ printf("%s4GB PA", SEP_STR);
+ break;
+ case ID_AA64MMFR0_PA_RANGE_64G:
+ printf("%s64GB PA", SEP_STR);
+ break;
+ case ID_AA64MMFR0_PA_RANGE_1T:
+ printf("%s1TB PA", SEP_STR);
+ break;
+ case ID_AA64MMFR0_PA_RANGE_4T:
+ printf("%s4TB PA", SEP_STR);
+ break;
+ case ID_AA64MMFR0_PA_RANGE_16T:
+ printf("%s16TB PA", SEP_STR);
+ break;
+ case ID_AA64MMFR0_PA_RANGE_256T:
+ printf("%s256TB PA", SEP_STR);
+ break;
+ default:
+ printf("%sUnknown PA Range", SEP_STR);
+ break;
+ }
+
+ if ((cpu_desc[cpu].id_aa64mmfr0 & ~ID_AA64MMFR0_MASK) != 0)
+ printf("%s%#lx", SEP_STR,
+ cpu_desc[cpu].id_aa64mmfr0 & ~ID_AA64MMFR0_MASK);
+ printf(">\n");
+ }
+
+ /* AArch64 Memory Model Feature Register 1 */
+ if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_MMFR1) != 0) {
+ printf(" Memory Model Features 1 = <%#lx>\n",
+ cpu_desc[cpu].id_aa64mmfr1);
+ }
+
+ /* AArch64 Debug Feature Register 0 */
+ if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_DFR0) != 0) {
+ printed = 0;
+ printf(" Debug Features 0 = <");
+ printf("%s%lu CTX Breakpoints", SEP_STR,
+ ID_AA64DFR0_CTX_CMPS(cpu_desc[cpu].id_aa64dfr0));
+
+ printf("%s%lu Watchpoints", SEP_STR,
+ ID_AA64DFR0_WRPS(cpu_desc[cpu].id_aa64dfr0));
+
+ printf("%s%lu Breakpoints", SEP_STR,
+ ID_AA64DFR0_BRPS(cpu_desc[cpu].id_aa64dfr0));
+
+ switch (ID_AA64DFR0_PMU_VER(cpu_desc[cpu].id_aa64dfr0)) {
+ case ID_AA64DFR0_PMU_VER_NONE:
+ break;
+ case ID_AA64DFR0_PMU_VER_3:
+ printf("%sPMUv3", SEP_STR);
+ break;
+ case ID_AA64DFR0_PMU_VER_IMPL:
+ printf("%sImplementation defined PMU", SEP_STR);
+ break;
+ default:
+ printf("%sUnknown PMU", SEP_STR);
+ break;
+ }
+
+ switch (ID_AA64DFR0_TRACE_VER(cpu_desc[cpu].id_aa64dfr0)) {
+ case ID_AA64DFR0_TRACE_VER_NONE:
+ break;
+ case ID_AA64DFR0_TRACE_VER_IMPL:
+ printf("%sTrace", SEP_STR);
+ break;
+ default:
+ printf("%sUnknown Trace", SEP_STR);
+ break;
+ }
+
+ switch (ID_AA64DFR0_DEBUG_VER(cpu_desc[cpu].id_aa64dfr0)) {
+ case ID_AA64DFR0_DEBUG_VER_8:
+ printf("%sDebug v8", SEP_STR);
+ break;
+ default:
+ printf("%sUnknown Debug", SEP_STR);
+ break;
+ }
+
+ if (cpu_desc[cpu].id_aa64dfr0 & ~ID_AA64DFR0_MASK)
+ printf("%s%#lx", SEP_STR,
+ cpu_desc[cpu].id_aa64dfr0 & ~ID_AA64DFR0_MASK);
+ printf(">\n");
+ }
+
+ /* AArch64 Memory Model Feature Register 1 */
+ if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_DFR1) != 0) {
+ printf(" Debug Features 1 = <%#lx>\n",
+ cpu_desc[cpu].id_aa64dfr1);
+ }
+
+ /* AArch64 Auxiliary Feature Register 0 */
+ if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_AFR0) != 0) {
+ printf(" Auxiliary Features 0 = <%#lx>\n",
+ cpu_desc[cpu].id_aa64afr0);
+ }
+
+ /* AArch64 Auxiliary Feature Register 1 */
+ if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_AFR1) != 0) {
+ printf(" Auxiliary Features 1 = <%#lx>\n",
+ cpu_desc[cpu].id_aa64afr1);
+ }
+
+#undef SEP_STR
+}
void
identify_cpu(void)
@@ -133,7 +551,6 @@ identify_cpu(void)
u_int impl_id;
u_int part_id;
u_int cpu;
- uint64_t mpidr;
size_t i;
const struct cpu_parts *cpu_partsp = NULL;
@@ -171,19 +588,77 @@ identify_cpu(void)
cpu_desc[cpu].cpu_variant = CPU_VAR(midr);
/* Save affinity for current CPU */
- mpidr = get_mpidr();
- CPU_AFFINITY(cpu) = mpidr & CPU_AFF_MASK;
-
- /* Print details for boot CPU or if we want verbose output */
- if (cpu == 0 || bootverbose) {
- printf("CPU(%d): %s %s r%dp%d\n", cpu,
- cpu_desc[cpu].cpu_impl_name,
- cpu_desc[cpu].cpu_part_name,
- cpu_desc[cpu].cpu_variant,
- cpu_desc[cpu].cpu_revision);
- }
+ cpu_desc[cpu].mpidr = get_mpidr();
+ CPU_AFFINITY(cpu) = cpu_desc[cpu].mpidr & CPU_AFF_MASK;
+
+ cpu_desc[cpu].id_aa64dfr0 = READ_SPECIALREG(id_aa64dfr0_el1);
+ cpu_desc[cpu].id_aa64dfr1 = READ_SPECIALREG(id_aa64dfr1_el1);
+ cpu_desc[cpu].id_aa64isar0 = READ_SPECIALREG(id_aa64isar0_el1);
+ cpu_desc[cpu].id_aa64isar1 = READ_SPECIALREG(id_aa64isar1_el1);
+ cpu_desc[cpu].id_aa64mmfr0 = READ_SPECIALREG(id_aa64mmfr0_el1);
+ cpu_desc[cpu].id_aa64mmfr1 = READ_SPECIALREG(id_aa64mmfr1_el1);
+ cpu_desc[cpu].id_aa64pfr0 = READ_SPECIALREG(id_aa64pfr0_el1);
+ cpu_desc[cpu].id_aa64pfr1 = READ_SPECIALREG(id_aa64pfr1_el1);
- if (bootverbose)
- printf("CPU%u affinity: %u.%u.%u.%u\n", 0, CPU_AFF0(mpidr),
- CPU_AFF1(mpidr), CPU_AFF2(mpidr), CPU_AFF3(mpidr));
+ if (cpu != 0) {
+ /*
+ * This code must run on one cpu at a time, but we are
+ * not scheduling on the current core so implement a
+ * simple spinlock.
+ */
+ while (atomic_cmpset_acq_int(&ident_lock, 0, 1) == 0)
+ __asm __volatile("wfe" ::: "memory");
+
+ switch (cpu_aff_levels) {
+ case 0:
+ if (CPU_AFF0(cpu_desc[cpu].mpidr) !=
+ CPU_AFF0(cpu_desc[0].mpidr))
+ cpu_aff_levels = 1;
+ /* FALLTHROUGH */
+ case 1:
+ if (CPU_AFF1(cpu_desc[cpu].mpidr) !=
+ CPU_AFF1(cpu_desc[0].mpidr))
+ cpu_aff_levels = 2;
+ /* FALLTHROUGH */
+ case 2:
+ if (CPU_AFF2(cpu_desc[cpu].mpidr) !=
+ CPU_AFF2(cpu_desc[0].mpidr))
+ cpu_aff_levels = 3;
+ /* FALLTHROUGH */
+ case 3:
+ if (CPU_AFF3(cpu_desc[cpu].mpidr) !=
+ CPU_AFF3(cpu_desc[0].mpidr))
+ cpu_aff_levels = 4;
+ break;
+ }
+
+ if (cpu_desc[cpu].id_aa64afr0 != cpu_desc[0].id_aa64afr0)
+ cpu_print_regs |= PRINT_ID_AA64_AFR0;
+ if (cpu_desc[cpu].id_aa64afr1 != cpu_desc[0].id_aa64afr1)
+ cpu_print_regs |= PRINT_ID_AA64_AFR1;
+
+ if (cpu_desc[cpu].id_aa64dfr0 != cpu_desc[0].id_aa64dfr0)
+ cpu_print_regs |= PRINT_ID_AA64_DFR0;
+ if (cpu_desc[cpu].id_aa64dfr1 != cpu_desc[0].id_aa64dfr1)
+ cpu_print_regs |= PRINT_ID_AA64_DFR1;
+
+ if (cpu_desc[cpu].id_aa64isar0 != cpu_desc[0].id_aa64isar0)
+ cpu_print_regs |= PRINT_ID_AA64_ISAR0;
+ if (cpu_desc[cpu].id_aa64isar1 != cpu_desc[0].id_aa64isar1)
+ cpu_print_regs |= PRINT_ID_AA64_ISAR1;
+
+ if (cpu_desc[cpu].id_aa64mmfr0 != cpu_desc[0].id_aa64mmfr0)
+ cpu_print_regs |= PRINT_ID_AA64_MMFR0;
+ if (cpu_desc[cpu].id_aa64mmfr1 != cpu_desc[0].id_aa64mmfr1)
+ cpu_print_regs |= PRINT_ID_AA64_MMFR1;
+
+ if (cpu_desc[cpu].id_aa64pfr0 != cpu_desc[0].id_aa64pfr0)
+ cpu_print_regs |= PRINT_ID_AA64_PFR0;
+ if (cpu_desc[cpu].id_aa64pfr1 != cpu_desc[0].id_aa64pfr1)
+ cpu_print_regs |= PRINT_ID_AA64_PFR1;
+
+ /* Wake up the other CPUs */
+ atomic_store_rel_int(&ident_lock, 0);
+ __asm __volatile("sev" ::: "memory");
+ }
}
diff --git a/sys/arm64/arm64/mp_machdep.c b/sys/arm64/arm64/mp_machdep.c
index 73adb76..19cee77 100644
--- a/sys/arm64/arm64/mp_machdep.c
+++ b/sys/arm64/arm64/mp_machdep.c
@@ -175,7 +175,7 @@ arm64_cpu_attach(device_t dev)
static void
release_aps(void *dummy __unused)
{
- int i;
+ int cpu, i;
/* Setup the IPI handler */
for (i = 0; i < COUNT_IPI; i++)
@@ -188,8 +188,14 @@ release_aps(void *dummy __unused)
printf("Release APs\n");
for (i = 0; i < 2000; i++) {
- if (smp_started)
+ if (smp_started) {
+ for (cpu = 0; cpu <= mp_maxid; cpu++) {
+ if (CPU_ABSENT(cpu))
+ continue;
+ print_cpu_features(cpu);
+ }
return;
+ }
DELAY(1000);
}
diff --git a/sys/arm64/include/armreg.h b/sys/arm64/include/armreg.h
index de8ce40..f8d1996 100644
--- a/sys/arm64/include/armreg.h
+++ b/sys/arm64/include/armreg.h
@@ -121,19 +121,147 @@
/* ICC_SRE_EL2 */
#define ICC_SRE_EL2_EN (1U << 3)
+/* ID_AA64DFR0_EL1 */
+#define ID_AA64DFR0_MASK 0xf0f0ffff
+#define ID_AA64DFR0_DEBUG_VER_SHIFT 0
+#define ID_AA64DFR0_DEBUG_VER_MASK (0xf << ID_AA64DFR0_DEBUG_VER_SHIFT)
+#define ID_AA64DFR0_DEBUG_VER(x) ((x) & ID_AA64DFR0_DEBUG_VER_MASK)
+#define ID_AA64DFR0_DEBUG_VER_8 (0x6 << ID_AA64DFR0_DEBUG_VER_SHIFT)
+#define ID_AA64DFR0_TRACE_VER_SHIFT 4
+#define ID_AA64DFR0_TRACE_VER_MASK (0xf << ID_AA64DFR0_TRACE_VER_SHIFT)
+#define ID_AA64DFR0_TRACE_VER(x) ((x) & ID_AA64DFR0_TRACE_VER_MASK)
+#define ID_AA64DFR0_TRACE_VER_NONE (0x0 << ID_AA64DFR0_TRACE_VER_SHIFT)
+#define ID_AA64DFR0_TRACE_VER_IMPL (0x1 << ID_AA64DFR0_TRACE_VER_SHIFT)
+#define ID_AA64DFR0_PMU_VER_SHIFT 8
+#define ID_AA64DFR0_PMU_VER_MASK (0xf << ID_AA64DFR0_PMU_VER_SHIFT)
+#define ID_AA64DFR0_PMU_VER(x) ((x) & ID_AA64DFR0_PMU_VER_MASK)
+#define ID_AA64DFR0_PMU_VER_NONE (0x0 << ID_AA64DFR0_PMU_VER_SHIFT)
+#define ID_AA64DFR0_PMU_VER_3 (0x1 << ID_AA64DFR0_PMU_VER_SHIFT)
+#define ID_AA64DFR0_PMU_VER_IMPL (0xf << ID_AA64DFR0_PMU_VER_SHIFT)
+#define ID_AA64DFR0_BRPS_SHIFT 12
+#define ID_AA64DFR0_BRPS_MASK (0xf << ID_AA64DFR0_BRPS_SHIFT)
+#define ID_AA64DFR0_BRPS(x) \
+ ((((x) >> ID_AA64DFR0_BRPS_SHIFT) & 0xf) + 1)
+#define ID_AA64DFR0_WRPS_SHIFT 20
+#define ID_AA64DFR0_WRPS_MASK (0xf << ID_AA64DFR0_WRPS_SHIFT)
+#define ID_AA64DFR0_WRPS(x) \
+ ((((x) >> ID_AA64DFR0_WRPS_SHIFT) & 0xf) + 1)
+#define ID_AA64DFR0_CTX_CMPS_SHIFT 28
+#define ID_AA64DFR0_CTX_CMPS_MASK (0xf << ID_AA64DFR0_CTX_CMPS_SHIFT)
+#define ID_AA64DFR0_CTX_CMPS(x) \
+ ((((x) >> ID_AA64DFR0_CTX_CMPS_SHIFT) & 0xf) + 1)
+
+/* ID_AA64ISAR0_EL1 */
+#define ID_AA64ISAR0_MASK 0x000ffff0
+#define ID_AA64ISAR0_AES_SHIFT 4
+#define ID_AA64ISAR0_AES_MASK (0xf << ID_AA64ISAR0_AES_SHIFT)
+#define ID_AA64ISAR0_AES(x) ((x) & ID_AA64ISAR0_AES_MASK)
+#define ID_AA64ISAR0_AES_NONE (0x0 << ID_AA64ISAR0_AES_SHIFT)
+#define ID_AA64ISAR0_AES_BASE (0x1 << ID_AA64ISAR0_AES_SHIFT)
+#define ID_AA64ISAR0_AES_PMULL (0x2 << ID_AA64ISAR0_AES_SHIFT)
+#define ID_AA64ISAR0_SHA1_SHIFT 8
+#define ID_AA64ISAR0_SHA1_MASK (0xf << ID_AA64ISAR0_SHA1_SHIFT)
+#define ID_AA64ISAR0_SHA1(x) ((x) & ID_AA64ISAR0_SHA1_MASK)
+#define ID_AA64ISAR0_SHA1_NONE (0x0 << ID_AA64ISAR0_SHA1_SHIFT)
+#define ID_AA64ISAR0_SHA1_BASE (0x1 << ID_AA64ISAR0_SHA1_SHIFT)
+#define ID_AA64ISAR0_SHA2_SHIFT 12
+#define ID_AA64ISAR0_SHA2_MASK (0xf << ID_AA64ISAR0_SHA2_SHIFT)
+#define ID_AA64ISAR0_SHA2(x) ((x) & ID_AA64ISAR0_SHA2_MASK)
+#define ID_AA64ISAR0_SHA2_NONE (0x0 << ID_AA64ISAR0_SHA2_SHIFT)
+#define ID_AA64ISAR0_SHA2_BASE (0x1 << ID_AA64ISAR0_SHA2_SHIFT)
+#define ID_AA64ISAR0_CRC32_SHIFT 16
+#define ID_AA64ISAR0_CRC32_MASK (0xf << ID_AA64ISAR0_CRC32_SHIFT)
+#define ID_AA64ISAR0_CRC32(x) ((x) & ID_AA64ISAR0_CRC32_MASK)
+#define ID_AA64ISAR0_CRC32_NONE (0x0 << ID_AA64ISAR0_CRC32_SHIFT)
+#define ID_AA64ISAR0_CRC32_BASE (0x1 << ID_AA64ISAR0_CRC32_SHIFT)
+
+/* ID_AA64MMFR0_EL1 */
+#define ID_AA64MMFR0_MASK 0xffffffff
+#define ID_AA64MMFR0_PA_RANGE_SHIFT 0
+#define ID_AA64MMFR0_PA_RANGE_MASK (0xf << ID_AA64MMFR0_PA_RANGE_SHIFT)
+#define ID_AA64MMFR0_PA_RANGE(x) ((x) & ID_AA64MMFR0_PA_RANGE_MASK)
+#define ID_AA64MMFR0_PA_RANGE_4G (0x0 << ID_AA64MMFR0_PA_RANGE_SHIFT)
+#define ID_AA64MMFR0_PA_RANGE_64G (0x1 << ID_AA64MMFR0_PA_RANGE_SHIFT)
+#define ID_AA64MMFR0_PA_RANGE_1T (0x2 << ID_AA64MMFR0_PA_RANGE_SHIFT)
+#define ID_AA64MMFR0_PA_RANGE_4T (0x3 << ID_AA64MMFR0_PA_RANGE_SHIFT)
+#define ID_AA64MMFR0_PA_RANGE_16T (0x4 << ID_AA64MMFR0_PA_RANGE_SHIFT)
+#define ID_AA64MMFR0_PA_RANGE_256T (0x5 << ID_AA64MMFR0_PA_RANGE_SHIFT)
+#define ID_AA64MMFR0_ASID_BITS_SHIFT 4
+#define ID_AA64MMFR0_ASID_BITS_MASK (0xf << ID_AA64MMFR0_ASID_BITS_SHIFT)
+#define ID_AA64MMFR0_ASID_BITS(x) ((x) & ID_AA64MMFR0_ASID_BITS_MASK)
+#define ID_AA64MMFR0_ASID_BITS_8 (0x0 << ID_AA64MMFR0_ASID_BITS_SHIFT)
+#define ID_AA64MMFR0_ASID_BITS_16 (0x2 << ID_AA64MMFR0_ASID_BITS_SHIFT)
+#define ID_AA64MMFR0_BIGEND_SHIFT 8
+#define ID_AA64MMFR0_BIGEND_MASK (0xf << ID_AA64MMFR0_BIGEND_SHIFT)
+#define ID_AA64MMFR0_BIGEND(x) ((x) & ID_AA64MMFR0_BIGEND_MASK)
+#define ID_AA64MMFR0_BIGEND_FIXED (0x0 << ID_AA64MMFR0_BIGEND_SHIFT)
+#define ID_AA64MMFR0_BIGEND_MIXED (0x1 << ID_AA64MMFR0_BIGEND_SHIFT)
+#define ID_AA64MMFR0_S_NS_MEM_SHIFT 12
+#define ID_AA64MMFR0_S_NS_MEM_MASK (0xf << ID_AA64MMFR0_S_NS_MEM_SHIFT)
+#define ID_AA64MMFR0_S_NS_MEM(x) ((x) & ID_AA64MMFR0_S_NS_MEM_MASK)
+#define ID_AA64MMFR0_S_NS_MEM_NONE (0x0 << ID_AA64MMFR0_S_NS_MEM_SHIFT)
+#define ID_AA64MMFR0_S_NS_MEM_DISTINCT (0x1 << ID_AA64MMFR0_S_NS_MEM_SHIFT)
+#define ID_AA64MMFR0_BIGEND_EL0_SHIFT 16
+#define ID_AA64MMFR0_BIGEND_EL0_MASK (0xf << ID_AA64MMFR0_BIGEND_EL0_SHIFT)
+#define ID_AA64MMFR0_BIGEND_EL0(x) ((x) & ID_AA64MMFR0_BIGEND_EL0_MASK)
+#define ID_AA64MMFR0_BIGEND_EL0_FIXED (0x0 << ID_AA64MMFR0_BIGEND_EL0_SHIFT)
+#define ID_AA64MMFR0_BIGEND_EL0_MIXED (0x1 << ID_AA64MMFR0_BIGEND_EL0_SHIFT)
+#define ID_AA64MMFR0_TGRAN16_SHIFT 20
+#define ID_AA64MMFR0_TGRAN16_MASK (0xf << ID_AA64MMFR0_TGRAN16_SHIFT)
+#define ID_AA64MMFR0_TGRAN16(x) ((x) & ID_AA64MMFR0_TGRAN16_MASK)
+#define ID_AA64MMFR0_TGRAN16_NONE (0x0 << ID_AA64MMFR0_TGRAN16_SHIFT)
+#define ID_AA64MMFR0_TGRAN16_IMPL (0x1 << ID_AA64MMFR0_TGRAN16_SHIFT)
+#define ID_AA64MMFR0_TGRAN64_SHIFT 24
+#define ID_AA64MMFR0_TGRAN64_MASK (0xf << ID_AA64MMFR0_TGRAN64_SHIFT)
+#define ID_AA64MMFR0_TGRAN64(x) ((x) & ID_AA64MMFR0_TGRAN64_MASK)
+#define ID_AA64MMFR0_TGRAN64_IMPL (0x0 << ID_AA64MMFR0_TGRAN64_SHIFT)
+#define ID_AA64MMFR0_TGRAN64_NONE (0xf << ID_AA64MMFR0_TGRAN64_SHIFT)
+#define ID_AA64MMFR0_TGRAN4_SHIFT 28
+#define ID_AA64MMFR0_TGRAN4_MASK (0xf << ID_AA64MMFR0_TGRAN4_SHIFT)
+#define ID_AA64MMFR0_TGRAN4(x) ((x) & ID_AA64MMFR0_TGRAN4_MASK)
+#define ID_AA64MMFR0_TGRAN4_IMPL (0x0 << ID_AA64MMFR0_TGRAN4_SHIFT)
+#define ID_AA64MMFR0_TGRAN4_NONE (0xf << ID_AA64MMFR0_TGRAN4_SHIFT)
+
/* ID_AA64PFR0_EL1 */
-#define ID_AA64PFR0_EL0_MASK (0xf << 0)
-#define ID_AA64PFR0_EL1_MASK (0xf << 4)
-#define ID_AA64PFR0_EL2_MASK (0xf << 8)
-#define ID_AA64PFR0_EL3_MASK (0xf << 12)
-#define ID_AA64PFR0_FP_MASK (0xf << 16)
-#define ID_AA64PFR0_FP_IMPL (0x0 << 16) /* Floating-point implemented */
-#define ID_AA64PFR0_FP_NONE (0xf << 16) /* Floating-point not implemented */
-#define ID_AA64PFR0_ADV_SIMD_MASK (0xf << 20)
-#define ID_AA64PFR0_GIC_SHIFT (24)
-#define ID_AA64PFR0_GIC_BITS (0x4) /* Number of bits in GIC field */
-#define ID_AA64PFR0_GIC_MASK (0xf << ID_AA64PFR0_GIC_SHIFT)
-#define ID_AA64PFR0_GIC_CPUIF_EN (0x1 << ID_AA64PFR0_GIC_SHIFT)
+#define ID_AA64PFR0_MASK 0x0fffffff
+#define ID_AA64PFR0_EL0_SHIFT 0
+#define ID_AA64PFR0_EL0_MASK (0xf << ID_AA64PFR0_EL0_SHIFT)
+#define ID_AA64PFR0_EL0(x) ((x) & ID_AA64PFR0_EL0_MASK)
+#define ID_AA64PFR0_EL0_64 (1 << ID_AA64PFR0_EL0_SHIFT)
+#define ID_AA64PFR0_EL0_64_32 (2 << ID_AA64PFR0_EL0_SHIFT)
+#define ID_AA64PFR0_EL1_SHIFT 4
+#define ID_AA64PFR0_EL1_MASK (0xf << ID_AA64PFR0_EL1_SHIFT)
+#define ID_AA64PFR0_EL1(x) ((x) & ID_AA64PFR0_EL1_MASK)
+#define ID_AA64PFR0_EL1_64 (1 << ID_AA64PFR0_EL1_SHIFT)
+#define ID_AA64PFR0_EL1_64_32 (2 << ID_AA64PFR0_EL1_SHIFT)
+#define ID_AA64PFR0_EL2_SHIFT 8
+#define ID_AA64PFR0_EL2_MASK (0xf << ID_AA64PFR0_EL2_SHIFT)
+#define ID_AA64PFR0_EL2(x) ((x) & ID_AA64PFR0_EL2_MASK)
+#define ID_AA64PFR0_EL2_NONE (0 << ID_AA64PFR0_EL2_SHIFT)
+#define ID_AA64PFR0_EL2_64 (1 << ID_AA64PFR0_EL2_SHIFT)
+#define ID_AA64PFR0_EL2_64_32 (2 << ID_AA64PFR0_EL2_SHIFT)
+#define ID_AA64PFR0_EL3_SHIFT 12
+#define ID_AA64PFR0_EL3_MASK (0xf << ID_AA64PFR0_EL3_SHIFT)
+#define ID_AA64PFR0_EL3(x) ((x) & ID_AA64PFR0_EL3_MASK)
+#define ID_AA64PFR0_EL3_NONE (0 << ID_AA64PFR0_EL3_SHIFT)
+#define ID_AA64PFR0_EL3_64 (1 << ID_AA64PFR0_EL3_SHIFT)
+#define ID_AA64PFR0_EL3_64_32 (2 << ID_AA64PFR0_EL3_SHIFT)
+#define ID_AA64PFR0_FP_SHIFT 16
+#define ID_AA64PFR0_FP_MASK (0xf << ID_AA64PFR0_FP_SHIFT)
+#define ID_AA64PFR0_FP(x) ((x) & ID_AA64PFR0_FP_MASK)
+#define ID_AA64PFR0_FP_IMPL (0x0 << ID_AA64PFR0_FP_SHIFT)
+#define ID_AA64PFR0_FP_NONE (0xf << ID_AA64PFR0_FP_SHIFT)
+#define ID_AA64PFR0_ADV_SIMD_SHIFT 20
+#define ID_AA64PFR0_ADV_SIMD_MASK (0xf << ID_AA64PFR0_ADV_SIMD_SHIFT)
+#define ID_AA64PFR0_ADV_SIMD(x) ((x) & ID_AA64PFR0_ADV_SIMD_MASK)
+#define ID_AA64PFR0_ADV_SIMD_IMPL (0x0 << ID_AA64PFR0_ADV_SIMD_SHIFT)
+#define ID_AA64PFR0_ADV_SIMD_NONE (0xf << ID_AA64PFR0_ADV_SIMD_SHIFT)
+#define ID_AA64PFR0_GIC_BITS 0x4 /* Number of bits in GIC field */
+#define ID_AA64PFR0_GIC_SHIFT 24
+#define ID_AA64PFR0_GIC_MASK (0xf << ID_AA64PFR0_GIC_SHIFT)
+#define ID_AA64PFR0_GIC(x) ((x) & ID_AA64PFR0_GIC_MASK)
+#define ID_AA64PFR0_GIC_CPUIF_NONE (0x0 << ID_AA64PFR0_GIC_SHIFT)
+#define ID_AA64PFR0_GIC_CPUIF_EN (0x1 << ID_AA64PFR0_GIC_SHIFT)
/* MAIR_EL1 - Memory Attribute Indirection Register */
#define MAIR_ATTR_MASK(idx) (0xff << ((n)* 8))
diff --git a/sys/arm64/include/cpu.h b/sys/arm64/include/cpu.h
index 14bffbc..8f14e82 100644
--- a/sys/arm64/include/cpu.h
+++ b/sys/arm64/include/cpu.h
@@ -145,6 +145,7 @@ void cpu_halt(void) __dead2;
void cpu_reset(void) __dead2;
void fork_trampoline(void);
void identify_cpu(void);
+void print_cpu_features(u_int);
void swi_vm(void *v);
#define CPU_AFFINITY(cpu) __cpu_affinity[(cpu)]
diff --git a/sys/boot/forth/loader.conf b/sys/boot/forth/loader.conf
index e2338ab..c13e90e 100644
--- a/sys/boot/forth/loader.conf
+++ b/sys/boot/forth/loader.conf
@@ -90,6 +90,7 @@ ram_blacklist_type="ram_blacklist" # Required for the kernel to find
#password="" # Prevent changes to boot options
#bootlock_password="" # Prevent booting (see check-password.4th(8))
#geom_eli_passphrase_prompt="NO" # Prompt for geli(8) passphrase to mount root
+bootenv_autolist="YES" # Auto populate the list of ZFS Boot Environments
#beastie_disable="NO" # Turn the beastie boot menu on and off
#kernels="kernel kernel.old" # Kernels to display in the boot menu
#loader_logo="orbbw" # Desired logo: orbbw, orb, fbsdbw, beastiebw, beastie, none
diff --git a/sys/boot/forth/menu-commands.4th b/sys/boot/forth/menu-commands.4th
index 0784676..9adf30a 100644
--- a/sys/boot/forth/menu-commands.4th
+++ b/sys/boot/forth/menu-commands.4th
@@ -351,4 +351,68 @@ also menu-namespace also menu-command-helpers
2 goto_menu
;
+\
+\ Set boot environment defaults
+\
+
+: init_bootenv ( -- )
+ s" set menu_caption[1]=${bemenu_current}${vfs.root.mountfrom}" evaluate
+ s" set ansi_caption[1]=${beansi_current}${vfs.root.mountfrom}" evaluate
+ s" set menu_caption[2]=${bemenu_bootfs}${zfs_be_active}" evaluate
+ s" set ansi_caption[2]=${beansi_bootfs}${zfs_be_active}" evaluate
+ s" set menu_caption[3]=${bemenu_page}${zfs_be_currpage}${bemenu_pageof}${zfs_be_pages}" evaluate
+ s" set ansi_caption[3]=${beansi_page}${zfs_be_currpage}${bemenu_pageof}${zfs_be_pages}" evaluate
+;
+
+\
+\ Redraw the entire screen. A long BE name can corrupt the menu
+\
+
+: be_draw_screen
+ clear \ Clear the screen (in screen.4th)
+ print_version \ print version string (bottom-right; see version.4th)
+ draw-beastie \ Draw FreeBSD logo at right (in beastie.4th)
+ draw-brand \ Draw brand.4th logo at top (in brand.4th)
+ menu-init \ Initialize menu and draw bounding box (in menu.4th)
+;
+
+\
+\ Select a boot environment
+\
+
+: set_bootenv ( N -- N TRUE )
+ dup s" set vfs.root.mountfrom=${bootenv_root[E]}" 38 +c! evaluate
+ s" set currdev=${vfs.root.mountfrom}:" evaluate
+ s" unload" evaluate
+ free-module-options
+ s" /boot/defaults/loader.conf" read-conf
+ s" /boot/loader.conf" read-conf
+ s" /boot/loader.conf.local" read-conf
+ init_bootenv
+ be_draw_screen
+ menu-redraw
+ TRUE
+;
+
+\
+\ Switch to the next page of boot environments
+\
+
+: set_be_page ( N -- N TRUE )
+ s" zfs_be_currpage" getenv dup -1 = if
+ drop s" 1"
+ else
+ 0 s>d 2swap
+ >number ( ud caddr/u -- ud' caddr'/u' ) \ convert string to numbers
+ 2drop \ drop the string
+ 1 um/mod ( ud u1 -- u2 u3 ) \ convert double ud' to single u3' and remainder u2
+ swap drop ( ud2 u3 -- u3 ) \ drop the remainder u2
+ 1+ \ increment the page number
+ s>d <# #s #> \ convert back to a string
+ then
+ s" zfs_be_currpage" setenv
+ s" reloadbe" evaluate
+ 3 goto_menu
+;
+
only forth definitions
diff --git a/sys/boot/forth/menu.rc b/sys/boot/forth/menu.rc
index 7ffeef4..3c7de71 100644
--- a/sys/boot/forth/menu.rc
+++ b/sys/boot/forth/menu.rc
@@ -68,6 +68,13 @@ set mainmenu_command[6]="2 goto_menu"
set mainmenu_keycode[6]=111
set mainansi_caption[6]="Configure Boot ^[1mO^[mptions..."
+s" currdev" getenv dup 0> [if] drop 4 s" zfs:" compare 0= [if]
+ set mainmenu_caption[7]="Select Boot [E]nvironment..."
+ set mainmenu_command[7]="3 goto_menu"
+ set mainmenu_keycode[7]=101
+ set mainansi_caption[7]="Select Boot ^[1mE^[37mnvironment..."
+[then] [else] drop [then]
+
\
\ BOOT OPTIONS MENU
\
@@ -119,6 +126,37 @@ set optionsmenu_keycode[6]=118
set optionsansi_caption[6]="^[1mV^[merbose..... ^[34;1mOff^[m"
set optionstoggled_ansi[6]="^[1mV^[merbose..... ^[32;7mOn^[m"
+\
+\ BOOT ENVIRONMENT MENU
+\
+
+set menuset_name3="bootenv"
+
+set bemenu_current="Active: "
+set beansi_current="^[1m${bemenu_current}^[m"
+set bemenu_bootfs="bootfs: "
+set beansi_bootfs="^[1m${bemenu_bootfs}^[m"
+set bemenu_page="[P]age: "
+set beansi_page="^[1mP^[mage: "
+set bemenu_pageof=" of "
+set beansi_pageof="${bemenu_pageof}"
+set zfs_be_currpage=1
+
+set bootenvmenu_init="init_bootenv"
+
+set bootenvmenu_command[1]="be_draw_screen 1 goto_menu"
+set bootenvmenu_keycode[1]=8
+
+set bootenvmenu_command[2]="set_bootenv"
+set bootenvmenu_keycode[2]=97
+set bootenv_root[2]="${zfs_be_active}"
+
+set bootenvmenu_command[3]="set_be_page"
+set bootenvmenu_keycode[3]=112
+
+set bootenvmenu_options=4
+set bootenvmenu_optionstext="Boot Environments:"
+
\ Enable automatic booting (add ``autoboot_delay=N'' to loader.conf(5) to
\ customize the timeout; default is 10-seconds)
\
@@ -128,6 +166,21 @@ set menu_timeout_command="boot"
\
try-include /boot/menu.rc.local
+\ Initialize boot environment variables
+\
+s" reloadbe" sfind ( xt|0 bool ) [if]
+ s" bootenv_autolist" getenv dup -1 = [if]
+ drop s" execute" evaluate \ Use evaluate to avoid passing
+ \ reloadbe an optional parameter
+ [else]
+ s" YES" compare-insensitive 0= [if]
+ s" execute" evaluate
+ [then]
+ [then]
+[else]
+ drop ( xt=0 )
+[then]
+
\ Display the main menu (see `menu.4th')
set menuset_initial=1
menuset-loadinitial
diff --git a/sys/boot/forth/support.4th b/sys/boot/forth/support.4th
index 9a68872..3a8e1f2 100644
--- a/sys/boot/forth/support.4th
+++ b/sys/boot/forth/support.4th
@@ -684,7 +684,7 @@ only forth also support-functions also file-processing definitions
s" loader_conf_files" getenv conf_files string=
;
-: set_nextboot_conf \ XXX maybe do as set_conf_files ?
+: set_nextboot_conf
value_buffer strget unquote nextboot_conf_file string=
;
@@ -852,7 +852,6 @@ only forth also support-functions definitions
\ Interface to loading conf files
: load_conf ( addr len -- )
- \ ." ----- Trying conf " 2dup type cr \ debugging
0 to end_of_file?
reset_line_reading
O_RDONLY fopen fd !
@@ -931,6 +930,30 @@ only forth definitions also support-functions
repeat
;
+: free-one-module { addr -- addr }
+ addr module.name strfree
+ addr module.loadname strfree
+ addr module.type strfree
+ addr module.args strfree
+ addr module.beforeload strfree
+ addr module.afterload strfree
+ addr module.loaderror strfree
+ addr
+;
+
+: free-module-options
+ module_options @
+ begin
+ ?dup
+ while
+ free-one-module
+ dup module.next @
+ swap free-memory
+ repeat
+ 0 module_options !
+ 0 last_module_option !
+;
+
only forth also support-functions definitions
\ Variables used for processing multiple conf files
@@ -944,7 +967,6 @@ string current_file_name_ref \ used to print the file name
\ loader_conf_files processing support functions
: get_conf_files ( -- addr len ) \ put addr/len on stack, reset var
- \ ." -- starting on <" conf_files strtype ." >" cr \ debugging
conf_files strget 0 0 conf_files strset
;
@@ -971,7 +993,6 @@ string current_file_name_ref \ used to print the file name
pos char+ to pos
repeat
addr len pos addr r@ + pos r> -
- \ 2dup ." get_file_name has " type cr \ debugging
;
: get_next_file ( addr len ptr -- addr len ptr' addr' len' | 0 )
@@ -1022,7 +1043,7 @@ string current_file_name_ref \ used to print the file name
;
: get_nextboot_conf_file ( -- addr len )
- nextboot_conf_file strget strdup
+ nextboot_conf_file strget
;
: rewrite_nextboot_file ( -- )
diff --git a/sys/boot/i386/loader/main.c b/sys/boot/i386/loader/main.c
index 0087338..d4073e7 100644
--- a/sys/boot/i386/loader/main.c
+++ b/sys/boot/i386/loader/main.c
@@ -69,6 +69,7 @@ static int isa_inb(int port);
static void isa_outb(int port, int value);
void exit(int code);
#ifdef LOADER_ZFS_SUPPORT
+static void init_zfs_bootenv(char *currdev);
static void i386_zfs_probe(void);
#endif
@@ -294,12 +295,40 @@ extract_currdev(void)
new_currdev.d_unit = 0;
}
+#ifdef LOADER_ZFS_SUPPORT
+ init_zfs_bootenv(zfs_fmtdev(&new_currdev));
+#endif
+
env_setenv("currdev", EV_VOLATILE, i386_fmtdev(&new_currdev),
i386_setcurrdev, env_nounset);
env_setenv("loaddev", EV_VOLATILE, i386_fmtdev(&new_currdev), env_noset,
env_nounset);
}
+#ifdef LOADER_ZFS_SUPPORT
+static void
+init_zfs_bootenv(char *currdev)
+{
+ char *beroot;
+
+ /* Remove the trailing : */
+ currdev[strlen(currdev) - 1] = '\0';
+ setenv("zfs_be_active", currdev, 1);
+ /* Do not overwrite if already set */
+ setenv("vfs.root.mountfrom", currdev, 0);
+ /* Forward past zfs: */
+ currdev = strchr(currdev, ':');
+ currdev++;
+ /* Remove the last element (current bootenv) */
+ beroot = strrchr(currdev, '/');
+ beroot[0] = '\0';
+
+ beroot = currdev;
+
+ setenv("zfs_be_root", beroot, 1);
+}
+#endif
+
COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot);
static int
@@ -353,6 +382,34 @@ command_lszfs(int argc, char *argv[])
command_errmsg = strerror(err);
return (CMD_ERROR);
}
+
+ return (CMD_OK);
+}
+
+COMMAND_SET(reloadbe, "reloadbe", "refresh the list of ZFS Boot Environments",
+ command_reloadbe);
+
+static int
+command_reloadbe(int argc, char *argv[])
+{
+ int err;
+
+ if (argc > 2) {
+ command_errmsg = "wrong number of arguments";
+ return (CMD_ERROR);
+ }
+
+ if (argc == 2) {
+ err = zfs_bootenv(argv[1]);
+ } else {
+ err = zfs_bootenv(getenv("zfs_be_root"));
+ }
+
+ if (err != 0) {
+ command_errmsg = strerror(err);
+ return (CMD_ERROR);
+ }
+
return (CMD_OK);
}
#endif
diff --git a/sys/boot/zfs/libzfs.h b/sys/boot/zfs/libzfs.h
index 6834f8b..b289849 100644
--- a/sys/boot/zfs/libzfs.h
+++ b/sys/boot/zfs/libzfs.h
@@ -62,6 +62,9 @@ int zfs_parsedev(struct zfs_devdesc *dev, const char *devspec,
char *zfs_fmtdev(void *vdev);
int zfs_probe_dev(const char *devname, uint64_t *pool_guid);
int zfs_list(const char *name);
+int zfs_bootenv(const char *name);
+int zfs_belist_add(const char *name);
+int zfs_set_env(void);
extern struct devsw zfs_dev;
extern struct fs_ops zfs_fsops;
diff --git a/sys/boot/zfs/zfs.c b/sys/boot/zfs/zfs.c
index 64c738d..0e15ac4 100644
--- a/sys/boot/zfs/zfs.c
+++ b/sys/boot/zfs/zfs.c
@@ -48,6 +48,10 @@ __FBSDID("$FreeBSD$");
#include "zfsimpl.c"
+/* Define the range of indexes to be populated with ZFS Boot Environments */
+#define ZFS_BE_FIRST 4
+#define ZFS_BE_LAST 8
+
static int zfs_open(const char *path, struct open_file *f);
static int zfs_write(struct open_file *f, void *buf, size_t size, size_t *resid);
static int zfs_close(struct open_file *f);
@@ -80,6 +84,16 @@ struct file {
zap_leaf_phys_t *f_zap_leaf; /* zap leaf buffer */
};
+static int zfs_env_index;
+static int zfs_env_count;
+
+SLIST_HEAD(zfs_be_list, zfs_be_entry) zfs_be_head = SLIST_HEAD_INITIALIZER(zfs_be_head);
+struct zfs_be_list *zfs_be_headp;
+struct zfs_be_entry {
+ const char *name;
+ SLIST_ENTRY(zfs_be_entry) entries;
+} *zfs_be, *zfs_be_tmp;
+
/*
* Open a file.
*/
@@ -691,6 +705,156 @@ zfs_list(const char *name)
rv = zfs_lookup_dataset(spa, dsname, &objid);
if (rv != 0)
return (rv);
- rv = zfs_list_dataset(spa, objid);
+
+ return (zfs_list_dataset(spa, objid));
+}
+
+int
+zfs_bootenv(const char *name)
+{
+ static char poolname[ZFS_MAXNAMELEN], *dsname;
+ char becount[4];
+ uint64_t objid;
+ spa_t *spa;
+ int len, rv, pages, perpage, currpage;
+
+ if (strcmp(name, getenv("zfs_be_root")) != 0) {
+ if (setenv("zfs_be_root", name, 1) != 0)
+ return (ENOMEM);
+ }
+
+ SLIST_INIT(&zfs_be_head);
+ zfs_env_count = 0;
+ len = strlen(name);
+ dsname = strchr(name, '/');
+ if (dsname != NULL) {
+ len = dsname - name;
+ dsname++;
+ } else
+ dsname = "";
+ memcpy(poolname, name, len);
+ poolname[len] = '\0';
+
+ spa = spa_find_by_name(poolname);
+ if (!spa)
+ return (ENXIO);
+ rv = zfs_lookup_dataset(spa, dsname, &objid);
+ if (rv != 0)
+ return (rv);
+ rv = zfs_callback_dataset(spa, objid, zfs_belist_add);
+
+ /* Calculate and store the number of pages of BEs */
+ perpage = (ZFS_BE_LAST - ZFS_BE_FIRST + 1);
+ pages = (zfs_env_count / perpage) + ((zfs_env_count % perpage) > 0 ? 1 : 0);
+ snprintf(becount, 4, "%d", pages);
+ if (setenv("zfs_be_pages", becount, 1) != 0)
+ return (ENOMEM);
+
+ /* Roll over the page counter if it has exceeded the maximum */
+ currpage = strtol(getenv("zfs_be_currpage"), NULL, 10);
+ if (currpage > pages) {
+ if (setenv("zfs_be_currpage", "1", 1) != 0)
+ return (ENOMEM);
+ }
+
+ /* Populate the menu environment variables */
+ zfs_set_env();
+
+ /* Clean up the SLIST of ZFS BEs */
+ while (!SLIST_EMPTY(&zfs_be_head)) {
+ zfs_be = SLIST_FIRST(&zfs_be_head);
+ SLIST_REMOVE_HEAD(&zfs_be_head, entries);
+ free(zfs_be);
+ }
+
return (rv);
}
+
+int
+zfs_belist_add(const char *name)
+{
+
+ /* Add the boot environment to the head of the SLIST */
+ zfs_be = malloc(sizeof(struct zfs_be_entry));
+ zfs_be->name = name;
+ SLIST_INSERT_HEAD(&zfs_be_head, zfs_be, entries);
+ zfs_env_count++;
+
+ return (0);
+}
+
+int
+zfs_set_env(void)
+{
+ char envname[32], envval[256];
+ char *beroot, *pagenum;
+ int rv, page, ctr;
+
+ beroot = getenv("zfs_be_root");
+ if (beroot == NULL) {
+ return (1);
+ }
+
+ pagenum = getenv("zfs_be_currpage");
+ if (pagenum != NULL) {
+ page = strtol(pagenum, NULL, 10);
+ } else {
+ page = 1;
+ }
+
+ ctr = 1;
+ rv = 0;
+ zfs_env_index = ZFS_BE_FIRST;
+ SLIST_FOREACH_SAFE(zfs_be, &zfs_be_head, entries, zfs_be_tmp) {
+ /* Skip to the requested page number */
+ if (ctr <= ((ZFS_BE_LAST - ZFS_BE_FIRST + 1) * (page - 1))) {
+ ctr++;
+ continue;
+ }
+
+ snprintf(envname, sizeof(envname), "bootenvmenu_caption[%d]", zfs_env_index);
+ snprintf(envval, sizeof(envval), "%s", zfs_be->name);
+ rv = setenv(envname, envval, 1);
+ if (rv != 0) {
+ break;
+ }
+
+ snprintf(envname, sizeof(envname), "bootenvansi_caption[%d]", zfs_env_index);
+ rv = setenv(envname, envval, 1);
+ if (rv != 0){
+ break;
+ }
+
+ snprintf(envname, sizeof(envname), "bootenvmenu_command[%d]", zfs_env_index);
+ rv = setenv(envname, "set_bootenv", 1);
+ if (rv != 0){
+ break;
+ }
+
+ snprintf(envname, sizeof(envname), "bootenv_root[%d]", zfs_env_index);
+ snprintf(envval, sizeof(envval), "zfs:%s/%s", beroot, zfs_be->name);
+ rv = setenv(envname, envval, 1);
+ if (rv != 0){
+ break;
+ }
+
+ zfs_env_index++;
+ if (zfs_env_index > ZFS_BE_LAST) {
+ break;
+ }
+
+ }
+
+ for (; zfs_env_index <= ZFS_BE_LAST; zfs_env_index++) {
+ snprintf(envname, sizeof(envname), "bootenvmenu_caption[%d]", zfs_env_index);
+ (void)unsetenv(envname);
+ snprintf(envname, sizeof(envname), "bootenvansi_caption[%d]", zfs_env_index);
+ (void)unsetenv(envname);
+ snprintf(envname, sizeof(envname), "bootenvmenu_command[%d]", zfs_env_index);
+ (void)unsetenv(envname);
+ snprintf(envname, sizeof(envname), "bootenv_root[%d]", zfs_env_index);
+ (void)unsetenv(envname);
+ }
+
+ return (rv);
+} \ No newline at end of file
diff --git a/sys/boot/zfs/zfsimpl.c b/sys/boot/zfs/zfsimpl.c
index d889047..927fbad 100644
--- a/sys/boot/zfs/zfsimpl.c
+++ b/sys/boot/zfs/zfsimpl.c
@@ -1473,7 +1473,7 @@ zap_lookup(const spa_t *spa, const dnode_phys_t *dnode, const char *name, uint64
* the directory contents.
*/
static int
-mzap_list(const dnode_phys_t *dnode)
+mzap_list(const dnode_phys_t *dnode, int (*callback)(const char *))
{
const mzap_phys_t *mz;
const mzap_ent_phys_t *mze;
@@ -1492,7 +1492,7 @@ mzap_list(const dnode_phys_t *dnode)
mze = &mz->mz_chunk[i];
if (mze->mze_name[0])
//printf("%-32s 0x%jx\n", mze->mze_name, (uintmax_t)mze->mze_value);
- printf("%s\n", mze->mze_name);
+ callback(mze->mze_name);
}
return (0);
@@ -1503,7 +1503,7 @@ mzap_list(const dnode_phys_t *dnode)
* the directory header.
*/
static int
-fzap_list(const spa_t *spa, const dnode_phys_t *dnode)
+fzap_list(const spa_t *spa, const dnode_phys_t *dnode, int (*callback)(const char *))
{
int bsize = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT;
zap_phys_t zh = *(zap_phys_t *) zap_scratch;
@@ -1566,13 +1566,21 @@ fzap_list(const spa_t *spa, const dnode_phys_t *dnode)
value = fzap_leaf_value(&zl, zc);
//printf("%s 0x%jx\n", name, (uintmax_t)value);
- printf("%s\n", name);
+ callback((const char *)name);
}
}
return (0);
}
+static int zfs_printf(const char *name)
+{
+
+ printf("%s\n", name);
+
+ return (0);
+}
+
/*
* List a zap directory.
*/
@@ -1587,9 +1595,9 @@ zap_list(const spa_t *spa, const dnode_phys_t *dnode)
zap_type = *(uint64_t *) zap_scratch;
if (zap_type == ZBT_MICRO)
- return mzap_list(dnode);
+ return mzap_list(dnode, zfs_printf);
else
- return fzap_list(spa, dnode);
+ return fzap_list(spa, dnode, zfs_printf);
}
static int
@@ -1858,6 +1866,48 @@ zfs_list_dataset(const spa_t *spa, uint64_t objnum/*, int pos, char *entry*/)
return (zap_list(spa, &child_dir_zap) != 0);
}
+
+int
+zfs_callback_dataset(const spa_t *spa, uint64_t objnum, int (*callback)(const char *name))
+{
+ uint64_t dir_obj, child_dir_zapobj, zap_type;
+ dnode_phys_t child_dir_zap, dir, dataset;
+ dsl_dataset_phys_t *ds;
+ dsl_dir_phys_t *dd;
+ int err;
+
+ err = objset_get_dnode(spa, &spa->spa_mos, objnum, &dataset);
+ if (err != 0) {
+ printf("ZFS: can't find dataset %ju\n", (uintmax_t)objnum);
+ return (err);
+ }
+ ds = (dsl_dataset_phys_t *) &dataset.dn_bonus;
+ dir_obj = ds->ds_dir_obj;
+
+ err = objset_get_dnode(spa, &spa->spa_mos, dir_obj, &dir);
+ if (err != 0) {
+ printf("ZFS: can't find dirobj %ju\n", (uintmax_t)dir_obj);
+ return (err);
+ }
+ dd = (dsl_dir_phys_t *)&dir.dn_bonus;
+
+ child_dir_zapobj = dd->dd_child_dir_zapobj;
+ err = objset_get_dnode(spa, &spa->spa_mos, child_dir_zapobj, &child_dir_zap);
+ if (err != 0) {
+ printf("ZFS: can't find child zap %ju\n", (uintmax_t)dir_obj);
+ return (err);
+ }
+
+ err = dnode_read(spa, &child_dir_zap, 0, zap_scratch, child_dir_zap.dn_datablkszsec * 512);
+ if (err != 0)
+ return (err);
+
+ zap_type = *(uint64_t *) zap_scratch;
+ if (zap_type == ZBT_MICRO)
+ return mzap_list(&child_dir_zap, callback);
+ else
+ return fzap_list(spa, &child_dir_zap, callback);
+}
#endif
/*
diff --git a/sys/compat/linuxkpi/common/include/linux/cdev.h b/sys/compat/linuxkpi/common/include/linux/cdev.h
index 5d8962f..84b7b70 100644
--- a/sys/compat/linuxkpi/common/include/linux/cdev.h
+++ b/sys/compat/linuxkpi/common/include/linux/cdev.h
@@ -41,6 +41,8 @@ struct inode;
struct module;
extern struct cdevsw linuxcdevsw;
+extern const struct kobj_type linux_cdev_ktype;
+extern const struct kobj_type linux_cdev_static_ktype;
struct linux_cdev {
struct kobject kobj;
@@ -51,39 +53,10 @@ struct linux_cdev {
};
static inline void
-cdev_release(struct kobject *kobj)
-{
- struct linux_cdev *cdev;
-
- cdev = container_of(kobj, struct linux_cdev, kobj);
- if (cdev->cdev)
- destroy_dev(cdev->cdev);
- kfree(cdev);
-}
-
-static inline void
-cdev_static_release(struct kobject *kobj)
-{
- struct linux_cdev *cdev;
-
- cdev = container_of(kobj, struct linux_cdev, kobj);
- if (cdev->cdev)
- destroy_dev(cdev->cdev);
-}
-
-static struct kobj_type cdev_ktype = {
- .release = cdev_release,
-};
-
-static struct kobj_type cdev_static_ktype = {
- .release = cdev_static_release,
-};
-
-static inline void
cdev_init(struct linux_cdev *cdev, const struct file_operations *ops)
{
- kobject_init(&cdev->kobj, &cdev_static_ktype);
+ kobject_init(&cdev->kobj, &linux_cdev_static_ktype);
cdev->ops = ops;
}
@@ -94,7 +67,7 @@ cdev_alloc(void)
cdev = kzalloc(sizeof(struct linux_cdev), M_WAITOK);
if (cdev)
- kobject_init(&cdev->kobj, &cdev_ktype);
+ kobject_init(&cdev->kobj, &linux_cdev_ktype);
return (cdev);
}
@@ -114,6 +87,7 @@ cdev_add(struct linux_cdev *cdev, dev_t dev, unsigned count)
cdev->dev = dev;
cdev->cdev->si_drv1 = cdev;
+ kobject_get(cdev->kobj.parent);
return (0);
}
diff --git a/sys/compat/linuxkpi/common/include/linux/device.h b/sys/compat/linuxkpi/common/include/linux/device.h
index 02b20645..f4b8ec6 100644
--- a/sys/compat/linuxkpi/common/include/linux/device.h
+++ b/sys/compat/linuxkpi/common/include/linux/device.h
@@ -73,8 +73,10 @@ struct device {
unsigned int msix_max;
};
-extern struct device linux_rootdev;
-extern struct kobject class_root;
+extern struct device linux_root_device;
+extern struct kobject linux_class_root;
+extern const struct kobj_type linux_dev_ktype;
+extern const struct kobj_type linux_class_ktype;
struct class_attribute {
struct attribute attr;
@@ -170,62 +172,14 @@ put_device(struct device *dev)
kobject_put(&dev->kobj);
}
-static inline ssize_t
-class_show(struct kobject *kobj, struct attribute *attr, char *buf)
-{
- struct class_attribute *dattr;
- ssize_t error;
-
- dattr = container_of(attr, struct class_attribute, attr);
- error = -EIO;
- if (dattr->show)
- error = dattr->show(container_of(kobj, struct class, kobj),
- dattr, buf);
- return (error);
-}
-
-static inline ssize_t
-class_store(struct kobject *kobj, struct attribute *attr, const char *buf,
- size_t count)
-{
- struct class_attribute *dattr;
- ssize_t error;
-
- dattr = container_of(attr, struct class_attribute, attr);
- error = -EIO;
- if (dattr->store)
- error = dattr->store(container_of(kobj, struct class, kobj),
- dattr, buf, count);
- return (error);
-}
-
-static inline void
-class_release(struct kobject *kobj)
-{
- struct class *class;
-
- class = container_of(kobj, struct class, kobj);
- if (class->class_release)
- class->class_release(class);
-}
-
-static struct sysfs_ops class_sysfs = {
- .show = class_show,
- .store = class_store,
-};
-static struct kobj_type class_ktype = {
- .release = class_release,
- .sysfs_ops = &class_sysfs
-};
-
static inline int
class_register(struct class *class)
{
class->bsdclass = devclass_create(class->name);
- kobject_init(&class->kobj, &class_ktype);
+ kobject_init(&class->kobj, &linux_class_ktype);
kobject_set_name(&class->kobj, class->name);
- kobject_add(&class->kobj, &class_root, class->name);
+ kobject_add(&class->kobj, &linux_class_root, class->name);
return (0);
}
@@ -237,54 +191,6 @@ class_unregister(struct class *class)
kobject_put(&class->kobj);
}
-static inline void
-device_release(struct kobject *kobj)
-{
- struct device *dev;
-
- dev = container_of(kobj, struct device, kobj);
- /* This is the precedence defined by linux. */
- if (dev->release)
- dev->release(dev);
- else if (dev->class && dev->class->dev_release)
- dev->class->dev_release(dev);
-}
-
-static inline ssize_t
-dev_show(struct kobject *kobj, struct attribute *attr, char *buf)
-{
- struct device_attribute *dattr;
- ssize_t error;
-
- dattr = container_of(attr, struct device_attribute, attr);
- error = -EIO;
- if (dattr->show)
- error = dattr->show(container_of(kobj, struct device, kobj),
- dattr, buf);
- return (error);
-}
-
-static inline ssize_t
-dev_store(struct kobject *kobj, struct attribute *attr, const char *buf,
- size_t count)
-{
- struct device_attribute *dattr;
- ssize_t error;
-
- dattr = container_of(attr, struct device_attribute, attr);
- error = -EIO;
- if (dattr->store)
- error = dattr->store(container_of(kobj, struct device, kobj),
- dattr, buf, count);
- return (error);
-}
-
-static struct sysfs_ops dev_sysfs = { .show = dev_show, .store = dev_store, };
-static struct kobj_type dev_ktype = {
- .release = device_release,
- .sysfs_ops = &dev_sysfs
-};
-
/*
* Devices are registered and created for exporting to sysfs. create
* implies register and register assumes the device fields have been
@@ -311,7 +217,7 @@ device_register(struct device *dev)
device_set_softc(bsddev, dev);
}
dev->bsddev = bsddev;
- kobject_init(&dev->kobj, &dev_ktype);
+ kobject_init(&dev->kobj, &linux_dev_ktype);
kobject_add(&dev->kobj, &dev->class->kobj, dev_name(dev));
return (0);
@@ -346,7 +252,7 @@ device_destroy(struct class *class, dev_t devt)
}
static inline void
-class_kfree(struct class *class)
+linux_class_kfree(struct class *class)
{
kfree(class);
@@ -361,7 +267,7 @@ class_create(struct module *owner, const char *name)
class = kzalloc(sizeof(*class), M_WAITOK);
class->owner = owner;
class->name= name;
- class->class_release = class_kfree;
+ class->class_release = linux_class_kfree;
error = class_register(class);
if (error) {
kfree(class);
@@ -414,7 +320,8 @@ class_remove_file(struct class *class, const struct class_attribute *attr)
sysfs_remove_file(&class->kobj, &attr->attr);
}
-static inline int dev_to_node(struct device *dev)
+static inline int
+dev_to_node(struct device *dev)
{
return -1;
}
diff --git a/sys/compat/linuxkpi/common/include/linux/file.h b/sys/compat/linuxkpi/common/include/linux/file.h
index e52afa5..559ac04 100644
--- a/sys/compat/linuxkpi/common/include/linux/file.h
+++ b/sys/compat/linuxkpi/common/include/linux/file.h
@@ -101,10 +101,11 @@ fd_install(unsigned int fd, struct linux_file *filp)
if (fget_unlocked(curthread->td_proc->p_fd, fd,
cap_rights_init(&rights), &file, NULL) != 0) {
- file = NULL;
+ filp->_file = NULL;
+ } else {
+ filp->_file = file;
+ finit(file, filp->f_mode, DTYPE_DEV, filp, &linuxfileops);
}
- filp->_file = file;
- finit(file, filp->f_mode, DTYPE_DEV, filp, &linuxfileops);
/* drop the extra reference */
fput(filp);
diff --git a/sys/compat/linuxkpi/common/include/linux/kobject.h b/sys/compat/linuxkpi/common/include/linux/kobject.h
index 475095e..a000c4e 100644
--- a/sys/compat/linuxkpi/common/include/linux/kobject.h
+++ b/sys/compat/linuxkpi/common/include/linux/kobject.h
@@ -46,13 +46,13 @@ struct kobj_type {
struct attribute **default_attrs;
};
-extern struct kobj_type kfree_type;
+extern const struct kobj_type linux_kfree_type;
struct kobject {
struct kobject *parent;
char *name;
struct kref kref;
- struct kobj_type *ktype;
+ const struct kobj_type *ktype;
struct list_head entry;
struct sysctl_oid *oidp;
};
@@ -74,7 +74,7 @@ struct kobj_attribute {
};
static inline void
-kobject_init(struct kobject *kobj, struct kobj_type *ktype)
+kobject_init(struct kobject *kobj, const struct kobj_type *ktype)
{
kref_init(&kobj->kref);
@@ -83,15 +83,14 @@ kobject_init(struct kobject *kobj, struct kobj_type *ktype)
kobj->oidp = NULL;
}
-static inline void kobject_put(struct kobject *kobj);
-void kobject_release(struct kref *kref);
+void linux_kobject_release(struct kref *kref);
static inline void
kobject_put(struct kobject *kobj)
{
if (kobj)
- kref_put(&kobj->kref, kobject_release);
+ kref_put(&kobj->kref, linux_kobject_release);
}
static inline struct kobject *
@@ -115,7 +114,7 @@ kobject_create(void)
kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
if (kobj == NULL)
return (NULL);
- kobject_init(kobj, &kfree_type);
+ kobject_init(kobj, &linux_kfree_type);
return (kobj);
}
@@ -135,7 +134,6 @@ kobject_create_and_add(const char *name, struct kobject *parent)
return (NULL);
}
-
static inline char *
kobject_name(const struct kobject *kobj)
{
@@ -144,7 +142,7 @@ kobject_name(const struct kobject *kobj)
}
int kobject_set_name(struct kobject *kobj, const char *fmt, ...);
-int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,
+int kobject_init_and_add(struct kobject *kobj, const struct kobj_type *ktype,
struct kobject *parent, const char *fmt, ...);
#endif /* _LINUX_KOBJECT_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/miscdevice.h b/sys/compat/linuxkpi/common/include/linux/miscdevice.h
index 96d8fe7..a873987 100644
--- a/sys/compat/linuxkpi/common/include/linux/miscdevice.h
+++ b/sys/compat/linuxkpi/common/include/linux/miscdevice.h
@@ -46,13 +46,13 @@ struct miscdevice {
umode_t mode;
};
-extern struct class miscclass;
+extern struct class linux_class_misc;
static inline int
misc_register(struct miscdevice *misc)
{
- misc->this_device = device_create(&miscclass, &linux_rootdev, 0, misc,
- misc->name);
+ misc->this_device = device_create(&linux_class_misc,
+ &linux_root_device, 0, misc, misc->name);
misc->cdev = cdev_alloc();
if (misc->cdev == NULL)
return -ENOMEM;
@@ -67,7 +67,7 @@ misc_register(struct miscdevice *misc)
static inline int
misc_deregister(struct miscdevice *misc)
{
- device_destroy(&miscclass, misc->this_device->devt);
+ device_destroy(&linux_class_misc, misc->this_device->devt);
cdev_del(misc->cdev);
return (0);
diff --git a/sys/compat/linuxkpi/common/src/linux_compat.c b/sys/compat/linuxkpi/common/src/linux_compat.c
index 91ec693..4d48519 100644
--- a/sys/compat/linuxkpi/common/src/linux_compat.c
+++ b/sys/compat/linuxkpi/common/src/linux_compat.c
@@ -77,9 +77,9 @@ MALLOC_DEFINE(M_KMALLOC, "linux", "Linux kmalloc compat");
#undef cdev
#define RB_ROOT(head) (head)->rbh_root
-struct kobject class_root;
-struct device linux_rootdev;
-struct class miscclass;
+struct kobject linux_class_root;
+struct device linux_root_device;
+struct class linux_class_misc;
struct list_head pci_drivers;
struct list_head pci_devices;
struct net init_net;
@@ -151,13 +151,13 @@ kobject_set_name(struct kobject *kobj, const char *fmt, ...)
return (error);
}
-static inline int
+static int
kobject_add_complete(struct kobject *kobj, struct kobject *parent)
{
- struct kobj_type *t;
+ const struct kobj_type *t;
int error;
- kobj->parent = kobject_get(parent);
+ kobj->parent = parent;
error = sysfs_create_dir(kobj);
if (error == 0 && kobj->ktype && kobj->ktype->default_attrs) {
struct attribute **attr;
@@ -191,16 +191,13 @@ kobject_add(struct kobject *kobj, struct kobject *parent, const char *fmt, ...)
}
void
-kobject_release(struct kref *kref)
+linux_kobject_release(struct kref *kref)
{
struct kobject *kobj;
char *name;
kobj = container_of(kref, struct kobject, kref);
sysfs_remove_dir(kobj);
- if (kobj->parent)
- kobject_put(kobj->parent);
- kobj->parent = NULL;
name = kobj->name;
if (kobj->ktype && kobj->ktype->release)
kobj->ktype->release(kobj);
@@ -208,28 +205,131 @@ kobject_release(struct kref *kref)
}
static void
-kobject_kfree(struct kobject *kobj)
+linux_kobject_kfree(struct kobject *kobj)
{
kfree(kobj);
}
static void
-kobject_kfree_name(struct kobject *kobj)
+linux_kobject_kfree_name(struct kobject *kobj)
{
if (kobj) {
kfree(kobj->name);
}
}
-struct kobj_type kfree_type = { .release = kobject_kfree };
+const struct kobj_type linux_kfree_type = {
+ .release = linux_kobject_kfree
+};
static void
-dev_release(struct device *dev)
+linux_device_release(struct device *dev)
{
- pr_debug("dev_release: %s\n", dev_name(dev));
+ pr_debug("linux_device_release: %s\n", dev_name(dev));
kfree(dev);
}
+static ssize_t
+linux_class_show(struct kobject *kobj, struct attribute *attr, char *buf)
+{
+ struct class_attribute *dattr;
+ ssize_t error;
+
+ dattr = container_of(attr, struct class_attribute, attr);
+ error = -EIO;
+ if (dattr->show)
+ error = dattr->show(container_of(kobj, struct class, kobj),
+ dattr, buf);
+ return (error);
+}
+
+static ssize_t
+linux_class_store(struct kobject *kobj, struct attribute *attr, const char *buf,
+ size_t count)
+{
+ struct class_attribute *dattr;
+ ssize_t error;
+
+ dattr = container_of(attr, struct class_attribute, attr);
+ error = -EIO;
+ if (dattr->store)
+ error = dattr->store(container_of(kobj, struct class, kobj),
+ dattr, buf, count);
+ return (error);
+}
+
+static void
+linux_class_release(struct kobject *kobj)
+{
+ struct class *class;
+
+ class = container_of(kobj, struct class, kobj);
+ if (class->class_release)
+ class->class_release(class);
+}
+
+static const struct sysfs_ops linux_class_sysfs = {
+ .show = linux_class_show,
+ .store = linux_class_store,
+};
+
+const struct kobj_type linux_class_ktype = {
+ .release = linux_class_release,
+ .sysfs_ops = &linux_class_sysfs
+};
+
+static void
+linux_dev_release(struct kobject *kobj)
+{
+ struct device *dev;
+
+ dev = container_of(kobj, struct device, kobj);
+ /* This is the precedence defined by linux. */
+ if (dev->release)
+ dev->release(dev);
+ else if (dev->class && dev->class->dev_release)
+ dev->class->dev_release(dev);
+}
+
+static ssize_t
+linux_dev_show(struct kobject *kobj, struct attribute *attr, char *buf)
+{
+ struct device_attribute *dattr;
+ ssize_t error;
+
+ dattr = container_of(attr, struct device_attribute, attr);
+ error = -EIO;
+ if (dattr->show)
+ error = dattr->show(container_of(kobj, struct device, kobj),
+ dattr, buf);
+ return (error);
+}
+
+static ssize_t
+linux_dev_store(struct kobject *kobj, struct attribute *attr, const char *buf,
+ size_t count)
+{
+ struct device_attribute *dattr;
+ ssize_t error;
+
+ dattr = container_of(attr, struct device_attribute, attr);
+ error = -EIO;
+ if (dattr->store)
+ error = dattr->store(container_of(kobj, struct device, kobj),
+ dattr, buf, count);
+ return (error);
+}
+
+static const struct sysfs_ops linux_dev_sysfs = {
+ .show = linux_dev_show,
+ .store = linux_dev_store,
+};
+
+const struct kobj_type linux_dev_ktype = {
+ .release = linux_dev_release,
+ .sysfs_ops = &linux_dev_sysfs
+};
+
struct device *
device_create(struct class *class, struct device *parent, dev_t devt,
void *drvdata, const char *fmt, ...)
@@ -242,7 +342,7 @@ device_create(struct class *class, struct device *parent, dev_t devt,
dev->class = class;
dev->devt = devt;
dev->driver_data = drvdata;
- dev->release = dev_release;
+ dev->release = linux_device_release;
va_start(args, fmt);
kobject_set_name_vargs(&dev->kobj, fmt, args);
va_end(args);
@@ -252,7 +352,7 @@ device_create(struct class *class, struct device *parent, dev_t devt,
}
int
-kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,
+kobject_init_and_add(struct kobject *kobj, const struct kobj_type *ktype,
struct kobject *parent, const char *fmt, ...)
{
va_list args;
@@ -1002,6 +1102,41 @@ destroy_workqueue(struct workqueue_struct *wq)
}
static void
+linux_cdev_release(struct kobject *kobj)
+{
+ struct linux_cdev *cdev;
+ struct kobject *parent;
+
+ cdev = container_of(kobj, struct linux_cdev, kobj);
+ parent = kobj->parent;
+ if (cdev->cdev)
+ destroy_dev(cdev->cdev);
+ kfree(cdev);
+ kobject_put(parent);
+}
+
+static void
+linux_cdev_static_release(struct kobject *kobj)
+{
+ struct linux_cdev *cdev;
+ struct kobject *parent;
+
+ cdev = container_of(kobj, struct linux_cdev, kobj);
+ parent = kobj->parent;
+ if (cdev->cdev)
+ destroy_dev(cdev->cdev);
+ kobject_put(parent);
+}
+
+const struct kobj_type linux_cdev_ktype = {
+ .release = linux_cdev_release,
+};
+
+const struct kobj_type linux_cdev_static_ktype = {
+ .release = linux_cdev_static_release,
+};
+
+static void
linux_compat_init(void *arg)
{
struct sysctl_oid *rootoid;
@@ -1009,18 +1144,18 @@ linux_compat_init(void *arg)
rootoid = SYSCTL_ADD_ROOT_NODE(NULL,
OID_AUTO, "sys", CTLFLAG_RD|CTLFLAG_MPSAFE, NULL, "sys");
- kobject_init(&class_root, &class_ktype);
- kobject_set_name(&class_root, "class");
- class_root.oidp = SYSCTL_ADD_NODE(NULL, SYSCTL_CHILDREN(rootoid),
+ kobject_init(&linux_class_root, &linux_class_ktype);
+ kobject_set_name(&linux_class_root, "class");
+ linux_class_root.oidp = SYSCTL_ADD_NODE(NULL, SYSCTL_CHILDREN(rootoid),
OID_AUTO, "class", CTLFLAG_RD|CTLFLAG_MPSAFE, NULL, "class");
- kobject_init(&linux_rootdev.kobj, &dev_ktype);
- kobject_set_name(&linux_rootdev.kobj, "device");
- linux_rootdev.kobj.oidp = SYSCTL_ADD_NODE(NULL,
+ kobject_init(&linux_root_device.kobj, &linux_dev_ktype);
+ kobject_set_name(&linux_root_device.kobj, "device");
+ linux_root_device.kobj.oidp = SYSCTL_ADD_NODE(NULL,
SYSCTL_CHILDREN(rootoid), OID_AUTO, "device", CTLFLAG_RD, NULL,
"device");
- linux_rootdev.bsddev = root_bus;
- miscclass.name = "misc";
- class_register(&miscclass);
+ linux_root_device.bsddev = root_bus;
+ linux_class_misc.name = "misc";
+ class_register(&linux_class_misc);
INIT_LIST_HEAD(&pci_drivers);
INIT_LIST_HEAD(&pci_devices);
spin_lock_init(&pci_lock);
@@ -1033,9 +1168,9 @@ SYSINIT(linux_compat, SI_SUB_DRIVERS, SI_ORDER_SECOND, linux_compat_init, NULL);
static void
linux_compat_uninit(void *arg)
{
- kobject_kfree_name(&class_root);
- kobject_kfree_name(&linux_rootdev.kobj);
- kobject_kfree_name(&miscclass.kobj);
+ linux_kobject_kfree_name(&linux_class_root);
+ linux_kobject_kfree_name(&linux_root_device.kobj);
+ linux_kobject_kfree_name(&linux_class_misc.kobj);
}
SYSUNINIT(linux_compat, SI_SUB_DRIVERS, SI_ORDER_SECOND, linux_compat_uninit, NULL);
diff --git a/sys/compat/linuxkpi/common/src/linux_pci.c b/sys/compat/linuxkpi/common/src/linux_pci.c
index 2d3d03b..7c49a54 100644
--- a/sys/compat/linuxkpi/common/src/linux_pci.c
+++ b/sys/compat/linuxkpi/common/src/linux_pci.c
@@ -119,16 +119,16 @@ linux_pci_attach(device_t dev)
pdrv = linux_pci_find(dev, &id);
pdev = device_get_softc(dev);
- pdev->dev.parent = &linux_rootdev;
+ pdev->dev.parent = &linux_root_device;
pdev->dev.bsddev = dev;
INIT_LIST_HEAD(&pdev->dev.irqents);
pdev->device = id->device;
pdev->vendor = id->vendor;
pdev->dev.dma_mask = &pdev->dma_mask;
pdev->pdrv = pdrv;
- kobject_init(&pdev->dev.kobj, &dev_ktype);
+ kobject_init(&pdev->dev.kobj, &linux_dev_ktype);
kobject_set_name(&pdev->dev.kobj, device_get_nameunit(dev));
- kobject_add(&pdev->dev.kobj, &linux_rootdev.kobj,
+ kobject_add(&pdev->dev.kobj, &linux_root_device.kobj,
kobject_name(&pdev->dev.kobj));
rle = _pci_get_rle(pdev, SYS_RES_IRQ, 0);
if (rle)
diff --git a/sys/conf/newvers.sh b/sys/conf/newvers.sh
index fc812c5..a5d4749 100644
--- a/sys/conf/newvers.sh
+++ b/sys/conf/newvers.sh
@@ -97,7 +97,10 @@ then
fi
touch version
-v=`cat version` u=${USER:-root} d=`pwd` h=${HOSTNAME:-`hostname`}
+v=`cat version`
+u=${USER:-root}
+d=`pwd`
+h=${HOSTNAME:-`hostname`}
if [ -n "$SOURCE_DATE_EPOCH" ]; then
if ! t=`date -r $SOURCE_DATE_EPOCH 2>/dev/null`; then
echo "Invalid SOURCE_DATE_EPOCH" >&2
diff --git a/sys/contrib/dev/rtwn/LICENSE b/sys/contrib/dev/rtwn/LICENSE
new file mode 100644
index 0000000..d70921f
--- /dev/null
+++ b/sys/contrib/dev/rtwn/LICENSE
@@ -0,0 +1,39 @@
+Copyright (c) 2010, Realtek Semiconductor Corporation
+All rights reserved.
+
+Redistribution. Redistribution and use in binary form, without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions must reproduce the above copyright notice and the
+ following disclaimer in the documentation and/or other materials
+ provided with the distribution.
+* Neither the name of Realtek Semiconductor Corporation nor the names of its
+ suppliers may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+* No reverse engineering, decompilation, or disassembly of this software
+ is permitted.
+
+Limited patent license. Realtek Semiconductor Corporation grants a world-wide,
+royalty-free, non-exclusive license under patents it now or hereafter
+owns or controls to make, have made, use, import, offer to sell and
+sell ("Utilize") this software, but solely to the extent that any
+such patent is necessary to Utilize the software alone, or in
+combination with an operating system licensed under an approved Open
+Source license as listed by the Open Source Initiative at
+http://opensource.org/licenses. The patent license shall not apply to
+any other combinations which include this software. No hardware per
+se is licensed hereunder.
+
+DISCLAIMER. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
diff --git a/sys/contrib/dev/rtwn/rtwn-rtl8192cfwU.fw.uu b/sys/contrib/dev/rtwn/rtwn-rtl8192cfwU.fw.uu
new file mode 100644
index 0000000..d542b2e
--- /dev/null
+++ b/sys/contrib/dev/rtwn/rtwn-rtl8192cfwU.fw.uu
@@ -0,0 +1,333 @@
+begin 444 rtwn-rtl8192cfwU.fw.uu
+MP8@"`$@````%$!!3PCD!`(%C`0`````````````````"0[H`````````````
+M`````````E!$````````````````````````````````````````````````
+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
+-29"77>`D_Y*O(@"'%P``
+`
+end
diff --git a/sys/contrib/dev/rtwn/rtwn-rtl8192cfwU_B.fw.uu b/sys/contrib/dev/rtwn/rtwn-rtl8192cfwU_B.fw.uu
new file mode 100644
index 0000000..f104224
--- /dev/null
+++ b/sys/contrib/dev/rtwn/rtwn-rtl8192cfwU_B.fw.uu
@@ -0,0 +1,366 @@
+begin 444 rtwn-rtl8192cfwU_B.fw.uu
+MPH@"`%@``@`'%11$K#\!`,S,S,P````````````````"19L`````````````
+M`````````EE4````````````````````````````````````````````````
+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
+JPY3_4`;@!/#D@!&0DD[@PY3_4`S@!/#DD))-\)"23/"0!/W@1`'P(GP.
+`
+end
diff --git a/sys/crypto/sha1.h b/sys/crypto/sha1.h
index 3686d7d..d32aa8a 100644
--- a/sys/crypto/sha1.h
+++ b/sys/crypto/sha1.h
@@ -53,6 +53,7 @@ struct sha1_ctxt {
} m;
u_int8_t count;
};
+typedef struct sha1_ctxt SHA1_CTX;
#ifdef _KERNEL
extern void sha1_init(struct sha1_ctxt *);
@@ -61,7 +62,6 @@ extern void sha1_loop(struct sha1_ctxt *, const u_int8_t *, size_t);
extern void sha1_result(struct sha1_ctxt *, caddr_t);
/* compatibilty with other SHA1 source codes */
-typedef struct sha1_ctxt SHA1_CTX;
#define SHA1Init(x) sha1_init((x))
#define SHA1Update(x, y, z) sha1_loop((x), (y), (z))
#define SHA1Final(x, y) sha1_result((y), (x))
diff --git a/sys/dev/cxgb/ulp/tom/cxgb_l2t.c b/sys/dev/cxgb/ulp/tom/cxgb_l2t.c
index 4352f33..c2390ae 100644
--- a/sys/dev/cxgb/ulp/tom/cxgb_l2t.c
+++ b/sys/dev/cxgb/ulp/tom/cxgb_l2t.c
@@ -215,7 +215,7 @@ resolve_entry(struct adapter *sc, struct l2t_entry *e)
struct tom_data *td = sc->tom_softc;
struct toedev *tod = &td->tod;
struct sockaddr_in sin = {0};
- uint8_t dmac[ETHER_ADDR_LEN];
+ uint8_t dmac[ETHER_HDR_LEN];
uint16_t vtag = EVL_VLID_MASK;
int rc;
diff --git a/sys/dev/cxgbe/tom/t4_tom_l2t.c b/sys/dev/cxgbe/tom/t4_tom_l2t.c
index 65f7d23..8aadf34 100644
--- a/sys/dev/cxgbe/tom/t4_tom_l2t.c
+++ b/sys/dev/cxgbe/tom/t4_tom_l2t.c
@@ -233,7 +233,7 @@ resolve_entry(struct adapter *sc, struct l2t_entry *e)
struct sockaddr_in sin = {0};
struct sockaddr_in6 sin6 = {0};
struct sockaddr *sa;
- uint8_t dmac[ETHER_ADDR_LEN];
+ uint8_t dmac[ETHER_HDR_LEN];
uint16_t vtag = VLAN_NONE;
int rc;
diff --git a/sys/dev/rtwn/if_rtwn.c b/sys/dev/rtwn/if_rtwn.c
new file mode 100644
index 0000000..6fedf7d
--- /dev/null
+++ b/sys/dev/rtwn/if_rtwn.c
@@ -0,0 +1,3490 @@
+/* $OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $ */
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2015 Stefan Sperling <stsp@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Driver for Realtek RTL8188CE
+ */
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/firmware.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+#include <net/bpf.h>
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+#include <net80211/ieee80211_regdomain.h>
+#include <net80211/ieee80211_ratectl.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h>
+
+#include <dev/rtwn/if_rtwnreg.h>
+
+#define RTWN_DEBUG
+#ifdef RTWN_DEBUG
+#define DPRINTF(x) do { if (sc->sc_debug > 0) printf x; } while (0)
+#define DPRINTFN(n, x) do { if (sc->sc_debug >= (n)) printf x; } while (0)
+#else
+#define DPRINTF(x)
+#define DPRINTFN(n, x)
+#endif
+
+/*
+ * PCI configuration space registers.
+ */
+#define RTWN_PCI_IOBA 0x10 /* i/o mapped base */
+#define RTWN_PCI_MMBA 0x18 /* memory mapped base */
+
+#define RTWN_INT_ENABLE (R92C_IMR_ROK | R92C_IMR_VODOK | R92C_IMR_VIDOK | \
+ R92C_IMR_BEDOK | R92C_IMR_BKDOK | R92C_IMR_MGNTDOK | \
+ R92C_IMR_HIGHDOK | R92C_IMR_BDOK | R92C_IMR_RDU | \
+ R92C_IMR_RXFOVW)
+
+struct rtwn_ident {
+ uint16_t vendor;
+ uint16_t device;
+ const char *name;
+};
+
+
+static const struct rtwn_ident rtwn_ident_table[] = {
+ { 0x10ec, 0x8176, "Realtek RTL8188CE" },
+ { 0, 0, NULL }
+};
+
+
+static void rtwn_dma_map_addr(void *, bus_dma_segment_t *, int, int);
+static void rtwn_setup_rx_desc(struct rtwn_softc *, struct r92c_rx_desc *,
+ bus_addr_t, size_t, int);
+static int rtwn_alloc_rx_list(struct rtwn_softc *);
+static void rtwn_reset_rx_list(struct rtwn_softc *);
+static void rtwn_free_rx_list(struct rtwn_softc *);
+static int rtwn_alloc_tx_list(struct rtwn_softc *, int);
+static void rtwn_reset_tx_list(struct rtwn_softc *, int);
+static void rtwn_free_tx_list(struct rtwn_softc *, int);
+static struct ieee80211vap *rtwn_vap_create(struct ieee80211com *,
+ const char [IFNAMSIZ], int, enum ieee80211_opmode, int,
+ const uint8_t [IEEE80211_ADDR_LEN],
+ const uint8_t [IEEE80211_ADDR_LEN]);
+static void rtwn_vap_delete(struct ieee80211vap *);
+static void rtwn_write_1(struct rtwn_softc *, uint16_t, uint8_t);
+static void rtwn_write_2(struct rtwn_softc *, uint16_t, uint16_t);
+static void rtwn_write_4(struct rtwn_softc *, uint16_t, uint32_t);
+static uint8_t rtwn_read_1(struct rtwn_softc *, uint16_t);
+static uint16_t rtwn_read_2(struct rtwn_softc *, uint16_t);
+static uint32_t rtwn_read_4(struct rtwn_softc *, uint16_t);
+static int rtwn_fw_cmd(struct rtwn_softc *, uint8_t, const void *, int);
+static void rtwn_rf_write(struct rtwn_softc *, int, uint8_t, uint32_t);
+static uint32_t rtwn_rf_read(struct rtwn_softc *, int, uint8_t);
+static int rtwn_llt_write(struct rtwn_softc *, uint32_t, uint32_t);
+static uint8_t rtwn_efuse_read_1(struct rtwn_softc *, uint16_t);
+static void rtwn_efuse_read(struct rtwn_softc *);
+static int rtwn_read_chipid(struct rtwn_softc *);
+static void rtwn_read_rom(struct rtwn_softc *);
+static int rtwn_ra_init(struct rtwn_softc *);
+static void rtwn_tsf_sync_enable(struct rtwn_softc *);
+static void rtwn_set_led(struct rtwn_softc *, int, int);
+static void rtwn_calib_to(void *);
+static int rtwn_newstate(struct ieee80211vap *, enum ieee80211_state, int);
+static int rtwn_updateedca(struct ieee80211com *);
+static void rtwn_update_avgrssi(struct rtwn_softc *, int, int8_t);
+static int8_t rtwn_get_rssi(struct rtwn_softc *, int, void *);
+static void rtwn_rx_frame(struct rtwn_softc *, struct r92c_rx_desc *,
+ struct rtwn_rx_data *, int);
+static int rtwn_tx(struct rtwn_softc *, struct mbuf *,
+ struct ieee80211_node *);
+static void rtwn_tx_done(struct rtwn_softc *, int);
+static int rtwn_raw_xmit(struct ieee80211_node *, struct mbuf *,
+ const struct ieee80211_bpf_params *);
+static int rtwn_transmit(struct ieee80211com *, struct mbuf *);
+static void rtwn_parent(struct ieee80211com *);
+static void rtwn_start(struct rtwn_softc *sc);
+static void rtwn_watchdog(void *);
+static int rtwn_power_on(struct rtwn_softc *);
+static int rtwn_llt_init(struct rtwn_softc *);
+static void rtwn_fw_reset(struct rtwn_softc *);
+static void rtwn_fw_loadpage(struct rtwn_softc *, int, const uint8_t *,
+ int);
+static int rtwn_load_firmware(struct rtwn_softc *);
+static int rtwn_dma_init(struct rtwn_softc *);
+static void rtwn_mac_init(struct rtwn_softc *);
+static void rtwn_bb_init(struct rtwn_softc *);
+static void rtwn_rf_init(struct rtwn_softc *);
+static void rtwn_cam_init(struct rtwn_softc *);
+static void rtwn_pa_bias_init(struct rtwn_softc *);
+static void rtwn_rxfilter_init(struct rtwn_softc *);
+static void rtwn_edca_init(struct rtwn_softc *);
+static void rtwn_write_txpower(struct rtwn_softc *, int, uint16_t[]);
+static void rtwn_get_txpower(struct rtwn_softc *, int,
+ struct ieee80211_channel *, struct ieee80211_channel *,
+ uint16_t[]);
+static void rtwn_set_txpower(struct rtwn_softc *,
+ struct ieee80211_channel *, struct ieee80211_channel *);
+static void rtwn_scan_start(struct ieee80211com *);
+static void rtwn_scan_end(struct ieee80211com *);
+static void rtwn_set_channel(struct ieee80211com *);
+static void rtwn_update_mcast(struct ieee80211com *);
+static void rtwn_set_chan(struct rtwn_softc *,
+ struct ieee80211_channel *, struct ieee80211_channel *);
+static int rtwn_iq_calib_chain(struct rtwn_softc *, int, uint16_t[2],
+ uint16_t[2]);
+static void rtwn_iq_calib_run(struct rtwn_softc *, int, uint16_t[2][2],
+ uint16_t[2][2]);
+static int rtwn_iq_calib_compare_results(uint16_t[2][2], uint16_t[2][2],
+ uint16_t[2][2], uint16_t[2][2], int);
+static void rtwn_iq_calib_write_results(struct rtwn_softc *, uint16_t[2],
+ uint16_t[2], int);
+static void rtwn_iq_calib(struct rtwn_softc *);
+static void rtwn_lc_calib(struct rtwn_softc *);
+static void rtwn_temp_calib(struct rtwn_softc *);
+static void rtwn_init_locked(struct rtwn_softc *);
+static void rtwn_init(struct rtwn_softc *);
+static void rtwn_stop_locked(struct rtwn_softc *);
+static void rtwn_stop(struct rtwn_softc *);
+static void rtwn_intr(void *);
+static void rtwn_hw_reset(void *, int);
+
+/* Aliases. */
+#define rtwn_bb_write rtwn_write_4
+#define rtwn_bb_read rtwn_read_4
+
+static int rtwn_probe(device_t);
+static int rtwn_attach(device_t);
+static int rtwn_detach(device_t);
+static int rtwn_shutdown(device_t);
+static int rtwn_suspend(device_t);
+static int rtwn_resume(device_t);
+
+static device_method_t rtwn_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, rtwn_probe),
+ DEVMETHOD(device_attach, rtwn_attach),
+ DEVMETHOD(device_detach, rtwn_detach),
+ DEVMETHOD(device_shutdown, rtwn_shutdown),
+ DEVMETHOD(device_suspend, rtwn_suspend),
+ DEVMETHOD(device_resume, rtwn_resume),
+
+ DEVMETHOD_END
+};
+
+static driver_t rtwn_driver = {
+ "rtwn",
+ rtwn_methods,
+ sizeof (struct rtwn_softc)
+};
+static devclass_t rtwn_devclass;
+
+DRIVER_MODULE(rtwn, pci, rtwn_driver, rtwn_devclass, NULL, NULL);
+
+MODULE_VERSION(rtwn, 1);
+
+MODULE_DEPEND(rtwn, pci, 1, 1, 1);
+MODULE_DEPEND(rtwn, wlan, 1, 1, 1);
+MODULE_DEPEND(rtwn, firmware, 1, 1, 1);
+
+static int
+rtwn_probe(device_t dev)
+{
+ const struct rtwn_ident *ident;
+
+ for (ident = rtwn_ident_table; ident->name != NULL; ident++) {
+ if (pci_get_vendor(dev) == ident->vendor &&
+ pci_get_device(dev) == ident->device) {
+ device_set_desc(dev, ident->name);
+ return (BUS_PROBE_DEFAULT);
+ }
+ }
+ return (ENXIO);
+}
+
+static int
+rtwn_attach(device_t dev)
+{
+ struct rtwn_softc *sc = device_get_softc(dev);
+ struct ieee80211com *ic = &sc->sc_ic;
+ uint32_t lcsr;
+ uint8_t bands;
+ int i, count, error, rid;
+
+ sc->sc_dev = dev;
+ sc->sc_debug = 0;
+
+ /*
+ * Get the offset of the PCI Express Capability Structure in PCI
+ * Configuration Space.
+ */
+ error = pci_find_cap(dev, PCIY_EXPRESS, &sc->sc_cap_off);
+ if (error != 0) {
+ device_printf(dev, "PCIe capability structure not found!\n");
+ return (error);
+ }
+
+ /* Enable bus-mastering. */
+ pci_enable_busmaster(dev);
+
+ rid = PCIR_BAR(2);
+ sc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (sc->mem == NULL) {
+ device_printf(dev, "can't map mem space\n");
+ return (ENOMEM);
+ }
+ sc->sc_st = rman_get_bustag(sc->mem);
+ sc->sc_sh = rman_get_bushandle(sc->mem);
+
+ /* Install interrupt handler. */
+ count = 1;
+ rid = 0;
+ if (pci_alloc_msi(dev, &count) == 0)
+ rid = 1;
+ sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE |
+ (rid != 0 ? 0 : RF_SHAREABLE));
+ if (sc->irq == NULL) {
+ device_printf(dev, "can't map interrupt\n");
+ return (ENXIO);
+ }
+
+ RTWN_LOCK_INIT(sc);
+ callout_init_mtx(&sc->calib_to, &sc->sc_mtx, 0);
+ callout_init_mtx(&sc->watchdog_to, &sc->sc_mtx, 0);
+ TASK_INIT(&sc->sc_reinit_task, 0, rtwn_hw_reset, sc);
+ mbufq_init(&sc->sc_snd, ifqmaxlen);
+
+ error = rtwn_read_chipid(sc);
+ if (error != 0) {
+ device_printf(dev, "unsupported test chip\n");
+ goto fail;
+ }
+
+ /* Disable PCIe Active State Power Management (ASPM). */
+ lcsr = pci_read_config(sc->sc_dev, sc->sc_cap_off + PCIER_LINK_CTL, 4);
+ lcsr &= ~PCIEM_LINK_CTL_ASPMC;
+ pci_write_config(sc->sc_dev, sc->sc_cap_off + PCIER_LINK_CTL, lcsr, 4);
+
+ /* Allocate Tx/Rx buffers. */
+ error = rtwn_alloc_rx_list(sc);
+ if (error != 0) {
+ device_printf(dev, "could not allocate Rx buffers\n");
+ goto fail;
+ }
+ for (i = 0; i < RTWN_NTXQUEUES; i++) {
+ error = rtwn_alloc_tx_list(sc, i);
+ if (error != 0) {
+ device_printf(dev, "could not allocate Tx buffers\n");
+ goto fail;
+ }
+ }
+
+ /* Determine number of Tx/Rx chains. */
+ if (sc->chip & RTWN_CHIP_92C) {
+ sc->ntxchains = (sc->chip & RTWN_CHIP_92C_1T2R) ? 1 : 2;
+ sc->nrxchains = 2;
+ } else {
+ sc->ntxchains = 1;
+ sc->nrxchains = 1;
+ }
+ rtwn_read_rom(sc);
+
+ device_printf(sc->sc_dev, "MAC/BB RTL%s, RF 6052 %dT%dR\n",
+ (sc->chip & RTWN_CHIP_92C) ? "8192CE" : "8188CE",
+ sc->ntxchains, sc->nrxchains);
+
+ ic->ic_softc = sc;
+ ic->ic_name = device_get_nameunit(dev);
+ ic->ic_opmode = IEEE80211_M_STA;
+ ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */
+
+ /* set device capabilities */
+ ic->ic_caps =
+ IEEE80211_C_STA /* station mode */
+ | IEEE80211_C_MONITOR /* monitor mode */
+ | IEEE80211_C_SHPREAMBLE /* short preamble supported */
+ | IEEE80211_C_SHSLOT /* short slot time supported */
+ | IEEE80211_C_WPA /* capable of WPA1+WPA2 */
+ | IEEE80211_C_BGSCAN /* capable of bg scanning */
+ | IEEE80211_C_WME /* 802.11e */
+ ;
+
+ bands = 0;
+ setbit(&bands, IEEE80211_MODE_11B);
+ setbit(&bands, IEEE80211_MODE_11G);
+ ieee80211_init_channels(ic, NULL, &bands);
+
+ ieee80211_ifattach(ic);
+
+ ic->ic_wme.wme_update = rtwn_updateedca;
+ ic->ic_update_mcast = rtwn_update_mcast;
+ ic->ic_scan_start =rtwn_scan_start;
+ ic->ic_scan_end = rtwn_scan_end;
+ ic->ic_set_channel = rtwn_set_channel;
+ ic->ic_raw_xmit = rtwn_raw_xmit;
+ ic->ic_transmit = rtwn_transmit;
+ ic->ic_parent = rtwn_parent;
+ ic->ic_vap_create = rtwn_vap_create;
+ ic->ic_vap_delete = rtwn_vap_delete;
+
+ ieee80211_radiotap_attach(ic,
+ &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap),
+ RTWN_TX_RADIOTAP_PRESENT,
+ &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap),
+ RTWN_RX_RADIOTAP_PRESENT);
+
+ /*
+ * Hook our interrupt after all initialization is complete.
+ */
+ error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET | INTR_MPSAFE,
+ NULL, rtwn_intr, sc, &sc->sc_ih);
+ if (error != 0) {
+ device_printf(dev, "can't establish interrupt, error %d\n",
+ error);
+ goto fail;
+ }
+
+ if (bootverbose)
+ ieee80211_announce(ic);
+
+ return (0);
+
+fail:
+ rtwn_detach(dev);
+ return (error);
+}
+
+
+static int
+rtwn_detach(device_t dev)
+{
+ struct rtwn_softc *sc = device_get_softc(dev);
+ int i;
+
+ if (sc->sc_ic.ic_softc != NULL) {
+ ieee80211_draintask(&sc->sc_ic, &sc->sc_reinit_task);
+ rtwn_stop(sc);
+
+ callout_drain(&sc->calib_to);
+ callout_drain(&sc->watchdog_to);
+ ieee80211_ifdetach(&sc->sc_ic);
+ mbufq_drain(&sc->sc_snd);
+ }
+
+ /* Uninstall interrupt handler. */
+ if (sc->irq != NULL) {
+ bus_teardown_intr(dev, sc->irq, sc->sc_ih);
+ bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->irq),
+ sc->irq);
+ pci_release_msi(dev);
+ }
+
+ /* Free Tx/Rx buffers. */
+ for (i = 0; i < RTWN_NTXQUEUES; i++)
+ rtwn_free_tx_list(sc, i);
+ rtwn_free_rx_list(sc);
+
+ if (sc->mem != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ rman_get_rid(sc->mem), sc->mem);
+
+ RTWN_LOCK_DESTROY(sc);
+ return (0);
+}
+
+static int
+rtwn_shutdown(device_t dev)
+{
+
+ return (0);
+}
+
+static int
+rtwn_suspend(device_t dev)
+{
+ return (0);
+}
+
+static int
+rtwn_resume(device_t dev)
+{
+
+ return (0);
+}
+
+static void
+rtwn_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
+{
+
+ if (error != 0)
+ return;
+ KASSERT(nsegs == 1, ("too many DMA segments, %d should be 1", nsegs));
+ *(bus_addr_t *)arg = segs[0].ds_addr;
+}
+
+static void
+rtwn_setup_rx_desc(struct rtwn_softc *sc, struct r92c_rx_desc *desc,
+ bus_addr_t addr, size_t len, int idx)
+{
+
+ memset(desc, 0, sizeof(*desc));
+ desc->rxdw0 = htole32(SM(R92C_RXDW0_PKTLEN, len) |
+ ((idx == RTWN_RX_LIST_COUNT - 1) ? R92C_RXDW0_EOR : 0));
+ desc->rxbufaddr = htole32(addr);
+ bus_space_barrier(sc->sc_st, sc->sc_sh, 0, sc->sc_mapsize,
+ BUS_SPACE_BARRIER_WRITE);
+ desc->rxdw0 |= htole32(R92C_RXDW0_OWN);
+}
+
+static int
+rtwn_alloc_rx_list(struct rtwn_softc *sc)
+{
+ struct rtwn_rx_ring *rx_ring = &sc->rx_ring;
+ struct rtwn_rx_data *rx_data;
+ bus_size_t size;
+ int i, error;
+
+ /* Allocate Rx descriptors. */
+ size = sizeof(struct r92c_rx_desc) * RTWN_RX_LIST_COUNT;
+ error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0,
+ BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+ size, 1, size, 0, NULL, NULL, &rx_ring->desc_dmat);
+ if (error != 0) {
+ device_printf(sc->sc_dev, "could not create rx desc DMA tag\n");
+ goto fail;
+ }
+
+ error = bus_dmamem_alloc(rx_ring->desc_dmat, (void **)&rx_ring->desc,
+ BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT,
+ &rx_ring->desc_map);
+ if (error != 0) {
+ device_printf(sc->sc_dev, "could not allocate rx desc\n");
+ goto fail;
+ }
+ error = bus_dmamap_load(rx_ring->desc_dmat, rx_ring->desc_map,
+ rx_ring->desc, size, rtwn_dma_map_addr, &rx_ring->paddr, 0);
+ if (error != 0) {
+ device_printf(sc->sc_dev, "could not load rx desc DMA map\n");
+ goto fail;
+ }
+ bus_dmamap_sync(rx_ring->desc_dmat, rx_ring->desc_map,
+ BUS_DMASYNC_PREWRITE);
+
+ /* Create RX buffer DMA tag. */
+ error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0,
+ BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES,
+ 1, MCLBYTES, 0, NULL, NULL, &rx_ring->data_dmat);
+ if (error != 0) {
+ device_printf(sc->sc_dev, "could not create rx buf DMA tag\n");
+ goto fail;
+ }
+
+ /* Allocate Rx buffers. */
+ for (i = 0; i < RTWN_RX_LIST_COUNT; i++) {
+ rx_data = &rx_ring->rx_data[i];
+ error = bus_dmamap_create(rx_ring->data_dmat, 0, &rx_data->map);
+ if (error != 0) {
+ device_printf(sc->sc_dev,
+ "could not create rx buf DMA map\n");
+ goto fail;
+ }
+
+ rx_data->m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
+ if (rx_data->m == NULL) {
+ device_printf(sc->sc_dev,
+ "could not allocate rx mbuf\n");
+ error = ENOMEM;
+ goto fail;
+ }
+
+ error = bus_dmamap_load(rx_ring->data_dmat, rx_data->map,
+ mtod(rx_data->m, void *), MCLBYTES, rtwn_dma_map_addr,
+ &rx_data->paddr, BUS_DMA_NOWAIT);
+ if (error != 0) {
+ device_printf(sc->sc_dev,
+ "could not load rx buf DMA map");
+ goto fail;
+ }
+
+ rtwn_setup_rx_desc(sc, &rx_ring->desc[i], rx_data->paddr,
+ MCLBYTES, i);
+ }
+ return (0);
+
+fail:
+ rtwn_free_rx_list(sc);
+ return (error);
+}
+
+static void
+rtwn_reset_rx_list(struct rtwn_softc *sc)
+{
+ struct rtwn_rx_ring *rx_ring = &sc->rx_ring;
+ struct rtwn_rx_data *rx_data;
+ int i;
+
+ for (i = 0; i < RTWN_RX_LIST_COUNT; i++) {
+ rx_data = &rx_ring->rx_data[i];
+ rtwn_setup_rx_desc(sc, &rx_ring->desc[i], rx_data->paddr,
+ MCLBYTES, i);
+ }
+}
+
+static void
+rtwn_free_rx_list(struct rtwn_softc *sc)
+{
+ struct rtwn_rx_ring *rx_ring = &sc->rx_ring;
+ struct rtwn_rx_data *rx_data;
+ int i;
+
+ if (rx_ring->desc_dmat != NULL) {
+ if (rx_ring->desc != NULL) {
+ bus_dmamap_unload(rx_ring->desc_dmat,
+ rx_ring->desc_map);
+ bus_dmamem_free(rx_ring->desc_dmat, rx_ring->desc,
+ rx_ring->desc_map);
+ rx_ring->desc = NULL;
+ }
+ bus_dma_tag_destroy(rx_ring->desc_dmat);
+ rx_ring->desc_dmat = NULL;
+ }
+
+ for (i = 0; i < RTWN_RX_LIST_COUNT; i++) {
+ rx_data = &rx_ring->rx_data[i];
+
+ if (rx_data->m != NULL) {
+ bus_dmamap_unload(rx_ring->data_dmat, rx_data->map);
+ m_freem(rx_data->m);
+ rx_data->m = NULL;
+ }
+ bus_dmamap_destroy(rx_ring->data_dmat, rx_data->map);
+ rx_data->map = NULL;
+ }
+ if (rx_ring->data_dmat != NULL) {
+ bus_dma_tag_destroy(rx_ring->data_dmat);
+ rx_ring->data_dmat = NULL;
+ }
+}
+
+static int
+rtwn_alloc_tx_list(struct rtwn_softc *sc, int qid)
+{
+ struct rtwn_tx_ring *tx_ring = &sc->tx_ring[qid];
+ struct rtwn_tx_data *tx_data;
+ bus_size_t size;
+ int i, error;
+
+ size = sizeof(struct r92c_tx_desc) * RTWN_TX_LIST_COUNT;
+ error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), PAGE_SIZE, 0,
+ BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+ size, 1, size, 0, NULL, NULL, &tx_ring->desc_dmat);
+ if (error != 0) {
+ device_printf(sc->sc_dev, "could not create tx ring DMA tag\n");
+ goto fail;
+ }
+
+ error = bus_dmamem_alloc(tx_ring->desc_dmat, (void **)&tx_ring->desc,
+ BUS_DMA_NOWAIT | BUS_DMA_ZERO, &tx_ring->desc_map);
+ if (error != 0) {
+ device_printf(sc->sc_dev, "can't map tx ring DMA memory\n");
+ goto fail;
+ }
+ error = bus_dmamap_load(tx_ring->desc_dmat, tx_ring->desc_map,
+ tx_ring->desc, size, rtwn_dma_map_addr, &tx_ring->paddr,
+ BUS_DMA_NOWAIT);
+ if (error != 0) {
+ device_printf(sc->sc_dev, "could not load desc DMA map\n");
+ goto fail;
+ }
+
+ error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0,
+ BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES,
+ 1, MCLBYTES, 0, NULL, NULL, &tx_ring->data_dmat);
+ if (error != 0) {
+ device_printf(sc->sc_dev, "could not create tx buf DMA tag\n");
+ goto fail;
+ }
+
+ for (i = 0; i < RTWN_TX_LIST_COUNT; i++) {
+ struct r92c_tx_desc *desc = &tx_ring->desc[i];
+
+ /* setup tx desc */
+ desc->nextdescaddr = htole32(tx_ring->paddr +
+ + sizeof(struct r92c_tx_desc)
+ * ((i + 1) % RTWN_TX_LIST_COUNT));
+ tx_data = &tx_ring->tx_data[i];
+ error = bus_dmamap_create(tx_ring->data_dmat, 0, &tx_data->map);
+ if (error != 0) {
+ device_printf(sc->sc_dev,
+ "could not create tx buf DMA map\n");
+ goto fail;
+ }
+ tx_data->m = NULL;
+ tx_data->ni = NULL;
+ }
+ return (0);
+
+fail:
+ rtwn_free_tx_list(sc, qid);
+ return (error);
+}
+
+static void
+rtwn_reset_tx_list(struct rtwn_softc *sc, int qid)
+{
+ struct rtwn_tx_ring *tx_ring = &sc->tx_ring[qid];
+ int i;
+
+ for (i = 0; i < RTWN_TX_LIST_COUNT; i++) {
+ struct r92c_tx_desc *desc = &tx_ring->desc[i];
+ struct rtwn_tx_data *tx_data = &tx_ring->tx_data[i];
+
+ memset(desc, 0, sizeof(*desc) -
+ (sizeof(desc->reserved) + sizeof(desc->nextdescaddr64) +
+ sizeof(desc->nextdescaddr)));
+
+ if (tx_data->m != NULL) {
+ bus_dmamap_unload(tx_ring->data_dmat, tx_data->map);
+ m_freem(tx_data->m);
+ tx_data->m = NULL;
+ }
+ if (tx_data->ni != NULL) {
+ ieee80211_free_node(tx_data->ni);
+ tx_data->ni = NULL;
+ }
+ }
+
+ bus_dmamap_sync(tx_ring->desc_dmat, tx_ring->desc_map,
+ BUS_DMASYNC_POSTWRITE);
+
+ sc->qfullmsk &= ~(1 << qid);
+ tx_ring->queued = 0;
+ tx_ring->cur = 0;
+}
+
+static void
+rtwn_free_tx_list(struct rtwn_softc *sc, int qid)
+{
+ struct rtwn_tx_ring *tx_ring = &sc->tx_ring[qid];
+ struct rtwn_tx_data *tx_data;
+ int i;
+
+ if (tx_ring->desc_dmat != NULL) {
+ if (tx_ring->desc != NULL) {
+ bus_dmamap_unload(tx_ring->desc_dmat,
+ tx_ring->desc_map);
+ bus_dmamem_free(tx_ring->desc_dmat, tx_ring->desc,
+ tx_ring->desc_map);
+ }
+ bus_dma_tag_destroy(tx_ring->desc_dmat);
+ }
+
+ for (i = 0; i < RTWN_TX_LIST_COUNT; i++) {
+ tx_data = &tx_ring->tx_data[i];
+
+ if (tx_data->m != NULL) {
+ bus_dmamap_unload(tx_ring->data_dmat, tx_data->map);
+ m_freem(tx_data->m);
+ tx_data->m = NULL;
+ }
+ }
+ if (tx_ring->data_dmat != NULL) {
+ bus_dma_tag_destroy(tx_ring->data_dmat);
+ tx_ring->data_dmat = NULL;
+ }
+
+ sc->qfullmsk &= ~(1 << qid);
+ tx_ring->queued = 0;
+ tx_ring->cur = 0;
+}
+
+
+static struct ieee80211vap *
+rtwn_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
+ enum ieee80211_opmode opmode, int flags,
+ const uint8_t bssid[IEEE80211_ADDR_LEN],
+ const uint8_t mac[IEEE80211_ADDR_LEN])
+{
+ struct rtwn_vap *rvp;
+ struct ieee80211vap *vap;
+
+ if (!TAILQ_EMPTY(&ic->ic_vaps))
+ return (NULL);
+
+ rvp = malloc(sizeof(struct rtwn_vap), M_80211_VAP, M_WAITOK | M_ZERO);
+ vap = &rvp->vap;
+ if (ieee80211_vap_setup(ic, vap, name, unit, opmode,
+ flags | IEEE80211_CLONE_NOBEACONS, bssid) != 0) {
+ /* out of memory */
+ free(rvp, M_80211_VAP);
+ return (NULL);
+ }
+
+ /* Override state transition machine. */
+ rvp->newstate = vap->iv_newstate;
+ vap->iv_newstate = rtwn_newstate;
+
+ /* Complete setup. */
+ ieee80211_vap_attach(vap, ieee80211_media_change,
+ ieee80211_media_status, mac);
+ ic->ic_opmode = opmode;
+ return (vap);
+}
+
+static void
+rtwn_vap_delete(struct ieee80211vap *vap)
+{
+ struct rtwn_vap *rvp = RTWN_VAP(vap);
+
+ ieee80211_vap_detach(vap);
+ free(rvp, M_80211_VAP);
+}
+
+static void
+rtwn_write_1(struct rtwn_softc *sc, uint16_t addr, uint8_t val)
+{
+
+ bus_space_write_1(sc->sc_st, sc->sc_sh, addr, val);
+}
+
+static void
+rtwn_write_2(struct rtwn_softc *sc, uint16_t addr, uint16_t val)
+{
+
+ val = htole16(val);
+ bus_space_write_2(sc->sc_st, sc->sc_sh, addr, val);
+}
+
+static void
+rtwn_write_4(struct rtwn_softc *sc, uint16_t addr, uint32_t val)
+{
+
+ val = htole32(val);
+ bus_space_write_4(sc->sc_st, sc->sc_sh, addr, val);
+}
+
+static uint8_t
+rtwn_read_1(struct rtwn_softc *sc, uint16_t addr)
+{
+
+ return (bus_space_read_1(sc->sc_st, sc->sc_sh, addr));
+}
+
+static uint16_t
+rtwn_read_2(struct rtwn_softc *sc, uint16_t addr)
+{
+
+ return (bus_space_read_2(sc->sc_st, sc->sc_sh, addr));
+}
+
+static uint32_t
+rtwn_read_4(struct rtwn_softc *sc, uint16_t addr)
+{
+
+ return (bus_space_read_4(sc->sc_st, sc->sc_sh, addr));
+}
+
+static int
+rtwn_fw_cmd(struct rtwn_softc *sc, uint8_t id, const void *buf, int len)
+{
+ struct r92c_fw_cmd cmd;
+ int ntries;
+
+ /* Wait for current FW box to be empty. */
+ for (ntries = 0; ntries < 100; ntries++) {
+ if (!(rtwn_read_1(sc, R92C_HMETFR) & (1 << sc->fwcur)))
+ break;
+ DELAY(1);
+ }
+ if (ntries == 100) {
+ device_printf(sc->sc_dev,
+ "could not send firmware command %d\n", id);
+ return (ETIMEDOUT);
+ }
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.id = id;
+ if (len > 3)
+ cmd.id |= R92C_CMD_FLAG_EXT;
+ KASSERT(len <= sizeof(cmd.msg), ("rtwn_fw_cmd\n"));
+ memcpy(cmd.msg, buf, len);
+
+ /* Write the first word last since that will trigger the FW. */
+ rtwn_write_2(sc, R92C_HMEBOX_EXT(sc->fwcur), *((uint8_t *)&cmd + 4));
+ rtwn_write_4(sc, R92C_HMEBOX(sc->fwcur), *((uint8_t *)&cmd + 0));
+
+ sc->fwcur = (sc->fwcur + 1) % R92C_H2C_NBOX;
+
+ /* Give firmware some time for processing. */
+ DELAY(2000);
+
+ return (0);
+}
+
+static void
+rtwn_rf_write(struct rtwn_softc *sc, int chain, uint8_t addr, uint32_t val)
+{
+ rtwn_bb_write(sc, R92C_LSSI_PARAM(chain),
+ SM(R92C_LSSI_PARAM_ADDR, addr) |
+ SM(R92C_LSSI_PARAM_DATA, val));
+}
+
+static uint32_t
+rtwn_rf_read(struct rtwn_softc *sc, int chain, uint8_t addr)
+{
+ uint32_t reg[R92C_MAX_CHAINS], val;
+
+ reg[0] = rtwn_bb_read(sc, R92C_HSSI_PARAM2(0));
+ if (chain != 0)
+ reg[chain] = rtwn_bb_read(sc, R92C_HSSI_PARAM2(chain));
+
+ rtwn_bb_write(sc, R92C_HSSI_PARAM2(0),
+ reg[0] & ~R92C_HSSI_PARAM2_READ_EDGE);
+ DELAY(1000);
+
+ rtwn_bb_write(sc, R92C_HSSI_PARAM2(chain),
+ RW(reg[chain], R92C_HSSI_PARAM2_READ_ADDR, addr) |
+ R92C_HSSI_PARAM2_READ_EDGE);
+ DELAY(1000);
+
+ rtwn_bb_write(sc, R92C_HSSI_PARAM2(0),
+ reg[0] | R92C_HSSI_PARAM2_READ_EDGE);
+ DELAY(1000);
+
+ if (rtwn_bb_read(sc, R92C_HSSI_PARAM1(chain)) & R92C_HSSI_PARAM1_PI)
+ val = rtwn_bb_read(sc, R92C_HSPI_READBACK(chain));
+ else
+ val = rtwn_bb_read(sc, R92C_LSSI_READBACK(chain));
+ return (MS(val, R92C_LSSI_READBACK_DATA));
+}
+
+static int
+rtwn_llt_write(struct rtwn_softc *sc, uint32_t addr, uint32_t data)
+{
+ int ntries;
+
+ rtwn_write_4(sc, R92C_LLT_INIT,
+ SM(R92C_LLT_INIT_OP, R92C_LLT_INIT_OP_WRITE) |
+ SM(R92C_LLT_INIT_ADDR, addr) |
+ SM(R92C_LLT_INIT_DATA, data));
+ /* Wait for write operation to complete. */
+ for (ntries = 0; ntries < 20; ntries++) {
+ if (MS(rtwn_read_4(sc, R92C_LLT_INIT), R92C_LLT_INIT_OP) ==
+ R92C_LLT_INIT_OP_NO_ACTIVE)
+ return (0);
+ DELAY(5);
+ }
+ return (ETIMEDOUT);
+}
+
+static uint8_t
+rtwn_efuse_read_1(struct rtwn_softc *sc, uint16_t addr)
+{
+ uint32_t reg;
+ int ntries;
+
+ reg = rtwn_read_4(sc, R92C_EFUSE_CTRL);
+ reg = RW(reg, R92C_EFUSE_CTRL_ADDR, addr);
+ reg &= ~R92C_EFUSE_CTRL_VALID;
+ rtwn_write_4(sc, R92C_EFUSE_CTRL, reg);
+ /* Wait for read operation to complete. */
+ for (ntries = 0; ntries < 100; ntries++) {
+ reg = rtwn_read_4(sc, R92C_EFUSE_CTRL);
+ if (reg & R92C_EFUSE_CTRL_VALID)
+ return (MS(reg, R92C_EFUSE_CTRL_DATA));
+ DELAY(5);
+ }
+ device_printf(sc->sc_dev,
+ "could not read efuse byte at address 0x%x\n", addr);
+ return (0xff);
+}
+
+static void
+rtwn_efuse_read(struct rtwn_softc *sc)
+{
+ uint8_t *rom = (uint8_t *)&sc->rom;
+ uint16_t addr = 0;
+ uint32_t reg;
+ uint8_t off, msk;
+ int i;
+
+ reg = rtwn_read_2(sc, R92C_SYS_ISO_CTRL);
+ if (!(reg & R92C_SYS_ISO_CTRL_PWC_EV12V)) {
+ rtwn_write_2(sc, R92C_SYS_ISO_CTRL,
+ reg | R92C_SYS_ISO_CTRL_PWC_EV12V);
+ }
+ reg = rtwn_read_2(sc, R92C_SYS_FUNC_EN);
+ if (!(reg & R92C_SYS_FUNC_EN_ELDR)) {
+ rtwn_write_2(sc, R92C_SYS_FUNC_EN,
+ reg | R92C_SYS_FUNC_EN_ELDR);
+ }
+ reg = rtwn_read_2(sc, R92C_SYS_CLKR);
+ if ((reg & (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) !=
+ (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) {
+ rtwn_write_2(sc, R92C_SYS_CLKR,
+ reg | R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M);
+ }
+ memset(&sc->rom, 0xff, sizeof(sc->rom));
+ while (addr < 512) {
+ reg = rtwn_efuse_read_1(sc, addr);
+ if (reg == 0xff)
+ break;
+ addr++;
+ off = reg >> 4;
+ msk = reg & 0xf;
+ for (i = 0; i < 4; i++) {
+ if (msk & (1 << i))
+ continue;
+ rom[off * 8 + i * 2 + 0] =
+ rtwn_efuse_read_1(sc, addr);
+ addr++;
+ rom[off * 8 + i * 2 + 1] =
+ rtwn_efuse_read_1(sc, addr);
+ addr++;
+ }
+ }
+#ifdef RTWN_DEBUG
+ if (sc->sc_debug >= 2) {
+ /* Dump ROM content. */
+ printf("\n");
+ for (i = 0; i < sizeof(sc->rom); i++)
+ printf("%02x:", rom[i]);
+ printf("\n");
+ }
+#endif
+}
+
+static int
+rtwn_read_chipid(struct rtwn_softc *sc)
+{
+ uint32_t reg;
+
+ reg = rtwn_read_4(sc, R92C_SYS_CFG);
+ if (reg & R92C_SYS_CFG_TRP_VAUX_EN)
+ /* Unsupported test chip. */
+ return (EIO);
+
+ if (reg & R92C_SYS_CFG_TYPE_92C) {
+ sc->chip |= RTWN_CHIP_92C;
+ /* Check if it is a castrated 8192C. */
+ if (MS(rtwn_read_4(sc, R92C_HPON_FSM),
+ R92C_HPON_FSM_CHIP_BONDING_ID) ==
+ R92C_HPON_FSM_CHIP_BONDING_ID_92C_1T2R)
+ sc->chip |= RTWN_CHIP_92C_1T2R;
+ }
+ if (reg & R92C_SYS_CFG_VENDOR_UMC) {
+ sc->chip |= RTWN_CHIP_UMC;
+ if (MS(reg, R92C_SYS_CFG_CHIP_VER_RTL) == 0)
+ sc->chip |= RTWN_CHIP_UMC_A_CUT;
+ }
+ return (0);
+}
+
+static void
+rtwn_read_rom(struct rtwn_softc *sc)
+{
+ struct r92c_rom *rom = &sc->rom;
+
+ /* Read full ROM image. */
+ rtwn_efuse_read(sc);
+
+ if (rom->id != 0x8129)
+ device_printf(sc->sc_dev, "invalid EEPROM ID 0x%x\n", rom->id);
+
+ /* XXX Weird but this is what the vendor driver does. */
+ sc->pa_setting = rtwn_efuse_read_1(sc, 0x1fa);
+ DPRINTF(("PA setting=0x%x\n", sc->pa_setting));
+
+ sc->board_type = MS(rom->rf_opt1, R92C_ROM_RF1_BOARD_TYPE);
+
+ sc->regulatory = MS(rom->rf_opt1, R92C_ROM_RF1_REGULATORY);
+ DPRINTF(("regulatory type=%d\n", sc->regulatory));
+
+ IEEE80211_ADDR_COPY(sc->sc_ic.ic_macaddr, rom->macaddr);
+}
+
+/*
+ * Initialize rate adaptation in firmware.
+ */
+static int
+rtwn_ra_init(struct rtwn_softc *sc)
+{
+ static const uint8_t map[] =
+ { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 };
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
+ struct ieee80211_node *ni = ieee80211_ref_node(vap->iv_bss);
+ struct ieee80211_rateset *rs = &ni->ni_rates;
+ struct r92c_fw_cmd_macid_cfg cmd;
+ uint32_t rates, basicrates;
+ uint8_t mode;
+ int maxrate, maxbasicrate, error, i, j;
+
+ /* Get normal and basic rates mask. */
+ rates = basicrates = 0;
+ maxrate = maxbasicrate = 0;
+ for (i = 0; i < rs->rs_nrates; i++) {
+ /* Convert 802.11 rate to HW rate index. */
+ for (j = 0; j < nitems(map); j++)
+ if ((rs->rs_rates[i] & IEEE80211_RATE_VAL) == map[j])
+ break;
+ if (j == nitems(map)) /* Unknown rate, skip. */
+ continue;
+ rates |= 1 << j;
+ if (j > maxrate)
+ maxrate = j;
+ if (rs->rs_rates[i] & IEEE80211_RATE_BASIC) {
+ basicrates |= 1 << j;
+ if (j > maxbasicrate)
+ maxbasicrate = j;
+ }
+ }
+ if (ic->ic_curmode == IEEE80211_MODE_11B)
+ mode = R92C_RAID_11B;
+ else
+ mode = R92C_RAID_11BG;
+ DPRINTF(("mode=0x%x rates=0x%08x, basicrates=0x%08x\n",
+ mode, rates, basicrates));
+
+ /* Set rates mask for group addressed frames. */
+ cmd.macid = RTWN_MACID_BC | RTWN_MACID_VALID;
+ cmd.mask = htole32(mode << 28 | basicrates);
+ error = rtwn_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd));
+ if (error != 0) {
+ device_printf(sc->sc_dev,
+ "could not add broadcast station\n");
+ return (error);
+ }
+ /* Set initial MRR rate. */
+ DPRINTF(("maxbasicrate=%d\n", maxbasicrate));
+ rtwn_write_1(sc, R92C_INIDATA_RATE_SEL(RTWN_MACID_BC),
+ maxbasicrate);
+
+ /* Set rates mask for unicast frames. */
+ cmd.macid = RTWN_MACID_BSS | RTWN_MACID_VALID;
+ cmd.mask = htole32(mode << 28 | rates);
+ error = rtwn_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd));
+ if (error != 0) {
+ device_printf(sc->sc_dev, "could not add BSS station\n");
+ return (error);
+ }
+ /* Set initial MRR rate. */
+ DPRINTF(("maxrate=%d\n", maxrate));
+ rtwn_write_1(sc, R92C_INIDATA_RATE_SEL(RTWN_MACID_BSS),
+ maxrate);
+
+ /* Configure Automatic Rate Fallback Register. */
+ if (ic->ic_curmode == IEEE80211_MODE_11B) {
+ if (rates & 0x0c)
+ rtwn_write_4(sc, R92C_ARFR(0), htole32(rates & 0x0d));
+ else
+ rtwn_write_4(sc, R92C_ARFR(0), htole32(rates & 0x0f));
+ } else
+ rtwn_write_4(sc, R92C_ARFR(0), htole32(rates & 0x0ff5));
+
+ /* Indicate highest supported rate. */
+ ni->ni_txrate = rs->rs_rates[rs->rs_nrates - 1];
+ return (0);
+}
+
+static void
+rtwn_tsf_sync_enable(struct rtwn_softc *sc)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
+ struct ieee80211_node *ni = vap->iv_bss;
+ uint64_t tsf;
+
+ /* Enable TSF synchronization. */
+ rtwn_write_1(sc, R92C_BCN_CTRL,
+ rtwn_read_1(sc, R92C_BCN_CTRL) & ~R92C_BCN_CTRL_DIS_TSF_UDT0);
+
+ rtwn_write_1(sc, R92C_BCN_CTRL,
+ rtwn_read_1(sc, R92C_BCN_CTRL) & ~R92C_BCN_CTRL_EN_BCN);
+
+ /* Set initial TSF. */
+ memcpy(&tsf, ni->ni_tstamp.data, 8);
+ tsf = le64toh(tsf);
+ tsf = tsf - (tsf % (vap->iv_bss->ni_intval * IEEE80211_DUR_TU));
+ tsf -= IEEE80211_DUR_TU;
+ rtwn_write_4(sc, R92C_TSFTR + 0, tsf);
+ rtwn_write_4(sc, R92C_TSFTR + 4, tsf >> 32);
+
+ rtwn_write_1(sc, R92C_BCN_CTRL,
+ rtwn_read_1(sc, R92C_BCN_CTRL) | R92C_BCN_CTRL_EN_BCN);
+}
+
+static void
+rtwn_set_led(struct rtwn_softc *sc, int led, int on)
+{
+ uint8_t reg;
+
+ if (led == RTWN_LED_LINK) {
+ reg = rtwn_read_1(sc, R92C_LEDCFG2) & 0xf0;
+ if (!on)
+ reg |= R92C_LEDCFG2_DIS;
+ else
+ reg |= R92C_LEDCFG2_EN;
+ rtwn_write_1(sc, R92C_LEDCFG2, reg);
+ sc->ledlink = on; /* Save LED state. */
+ }
+}
+
+static void
+rtwn_calib_to(void *arg)
+{
+ struct rtwn_softc *sc = arg;
+ struct r92c_fw_cmd_rssi cmd;
+
+ if (sc->avg_pwdb != -1) {
+ /* Indicate Rx signal strength to FW for rate adaptation. */
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.macid = 0; /* BSS. */
+ cmd.pwdb = sc->avg_pwdb;
+ DPRINTFN(3, ("sending RSSI command avg=%d\n", sc->avg_pwdb));
+ rtwn_fw_cmd(sc, R92C_CMD_RSSI_SETTING, &cmd, sizeof(cmd));
+ }
+
+ /* Do temperature compensation. */
+ rtwn_temp_calib(sc);
+
+ callout_reset(&sc->calib_to, hz * 2, rtwn_calib_to, sc);
+}
+
+static int
+rtwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
+{
+ struct rtwn_vap *rvp = RTWN_VAP(vap);
+ struct ieee80211com *ic = vap->iv_ic;
+ struct ieee80211_node *ni = vap->iv_bss;
+ struct rtwn_softc *sc = ic->ic_softc;
+ uint32_t reg;
+
+ IEEE80211_UNLOCK(ic);
+ RTWN_LOCK(sc);
+
+ if (vap->iv_state == IEEE80211_S_RUN) {
+ /* Stop calibration. */
+ callout_stop(&sc->calib_to);
+
+ /* Turn link LED off. */
+ rtwn_set_led(sc, RTWN_LED_LINK, 0);
+
+ /* Set media status to 'No Link'. */
+ reg = rtwn_read_4(sc, R92C_CR);
+ reg = RW(reg, R92C_CR_NETTYPE, R92C_CR_NETTYPE_NOLINK);
+ rtwn_write_4(sc, R92C_CR, reg);
+
+ /* Stop Rx of data frames. */
+ rtwn_write_2(sc, R92C_RXFLTMAP2, 0);
+
+ /* Rest TSF. */
+ rtwn_write_1(sc, R92C_DUAL_TSF_RST, 0x03);
+
+ /* Disable TSF synchronization. */
+ rtwn_write_1(sc, R92C_BCN_CTRL,
+ rtwn_read_1(sc, R92C_BCN_CTRL) |
+ R92C_BCN_CTRL_DIS_TSF_UDT0);
+
+ /* Reset EDCA parameters. */
+ rtwn_write_4(sc, R92C_EDCA_VO_PARAM, 0x002f3217);
+ rtwn_write_4(sc, R92C_EDCA_VI_PARAM, 0x005e4317);
+ rtwn_write_4(sc, R92C_EDCA_BE_PARAM, 0x00105320);
+ rtwn_write_4(sc, R92C_EDCA_BK_PARAM, 0x0000a444);
+ }
+ switch (nstate) {
+ case IEEE80211_S_INIT:
+ /* Turn link LED off. */
+ rtwn_set_led(sc, RTWN_LED_LINK, 0);
+ break;
+ case IEEE80211_S_SCAN:
+ if (vap->iv_state != IEEE80211_S_SCAN) {
+ /* Allow Rx from any BSSID. */
+ rtwn_write_4(sc, R92C_RCR,
+ rtwn_read_4(sc, R92C_RCR) &
+ ~(R92C_RCR_CBSSID_DATA | R92C_RCR_CBSSID_BCN));
+
+ /* Set gain for scanning. */
+ reg = rtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(0));
+ reg = RW(reg, R92C_OFDM0_AGCCORE1_GAIN, 0x20);
+ rtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), reg);
+
+ reg = rtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(1));
+ reg = RW(reg, R92C_OFDM0_AGCCORE1_GAIN, 0x20);
+ rtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(1), reg);
+ }
+
+ /* Make link LED blink during scan. */
+ rtwn_set_led(sc, RTWN_LED_LINK, !sc->ledlink);
+
+ /* Pause AC Tx queues. */
+ rtwn_write_1(sc, R92C_TXPAUSE,
+ rtwn_read_1(sc, R92C_TXPAUSE) | 0x0f);
+ break;
+ case IEEE80211_S_AUTH:
+ /* Set initial gain under link. */
+ reg = rtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(0));
+ reg = RW(reg, R92C_OFDM0_AGCCORE1_GAIN, 0x32);
+ rtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), reg);
+
+ reg = rtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(1));
+ reg = RW(reg, R92C_OFDM0_AGCCORE1_GAIN, 0x32);
+ rtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(1), reg);
+ rtwn_set_chan(sc, ic->ic_curchan, NULL);
+ break;
+ case IEEE80211_S_RUN:
+ if (ic->ic_opmode == IEEE80211_M_MONITOR) {
+ /* Enable Rx of data frames. */
+ rtwn_write_2(sc, R92C_RXFLTMAP2, 0xffff);
+
+ /* Turn link LED on. */
+ rtwn_set_led(sc, RTWN_LED_LINK, 1);
+ break;
+ }
+
+ /* Set media status to 'Associated'. */
+ reg = rtwn_read_4(sc, R92C_CR);
+ reg = RW(reg, R92C_CR_NETTYPE, R92C_CR_NETTYPE_INFRA);
+ rtwn_write_4(sc, R92C_CR, reg);
+
+ /* Set BSSID. */
+ rtwn_write_4(sc, R92C_BSSID + 0, LE_READ_4(&ni->ni_bssid[0]));
+ rtwn_write_4(sc, R92C_BSSID + 4, LE_READ_2(&ni->ni_bssid[4]));
+
+ if (ic->ic_curmode == IEEE80211_MODE_11B)
+ rtwn_write_1(sc, R92C_INIRTS_RATE_SEL, 0);
+ else /* 802.11b/g */
+ rtwn_write_1(sc, R92C_INIRTS_RATE_SEL, 3);
+
+ /* Enable Rx of data frames. */
+ rtwn_write_2(sc, R92C_RXFLTMAP2, 0xffff);
+
+ /* Flush all AC queues. */
+ rtwn_write_1(sc, R92C_TXPAUSE, 0);
+
+ /* Set beacon interval. */
+ rtwn_write_2(sc, R92C_BCN_INTERVAL, ni->ni_intval);
+
+ /* Allow Rx from our BSSID only. */
+ rtwn_write_4(sc, R92C_RCR,
+ rtwn_read_4(sc, R92C_RCR) |
+ R92C_RCR_CBSSID_DATA | R92C_RCR_CBSSID_BCN);
+
+ /* Enable TSF synchronization. */
+ rtwn_tsf_sync_enable(sc);
+
+ rtwn_write_1(sc, R92C_SIFS_CCK + 1, 10);
+ rtwn_write_1(sc, R92C_SIFS_OFDM + 1, 10);
+ rtwn_write_1(sc, R92C_SPEC_SIFS + 1, 10);
+ rtwn_write_1(sc, R92C_MAC_SPEC_SIFS + 1, 10);
+ rtwn_write_1(sc, R92C_R2T_SIFS + 1, 10);
+ rtwn_write_1(sc, R92C_T2T_SIFS + 1, 10);
+
+ /* Intialize rate adaptation. */
+ rtwn_ra_init(sc);
+ /* Turn link LED on. */
+ rtwn_set_led(sc, RTWN_LED_LINK, 1);
+
+ sc->avg_pwdb = -1; /* Reset average RSSI. */
+ /* Reset temperature calibration state machine. */
+ sc->thcal_state = 0;
+ sc->thcal_lctemp = 0;
+ /* Start periodic calibration. */
+ callout_reset(&sc->calib_to, hz * 2, rtwn_calib_to, sc);
+ break;
+ default:
+ break;
+ }
+ RTWN_UNLOCK(sc);
+ IEEE80211_LOCK(ic);
+ return (rvp->newstate(vap, nstate, arg));
+}
+
+static int
+rtwn_updateedca(struct ieee80211com *ic)
+{
+ struct rtwn_softc *sc = ic->ic_softc;
+ const uint16_t aci2reg[WME_NUM_AC] = {
+ R92C_EDCA_BE_PARAM,
+ R92C_EDCA_BK_PARAM,
+ R92C_EDCA_VI_PARAM,
+ R92C_EDCA_VO_PARAM
+ };
+ int aci, aifs, slottime;
+
+ IEEE80211_LOCK(ic);
+ slottime = (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20;
+ for (aci = 0; aci < WME_NUM_AC; aci++) {
+ const struct wmeParams *ac =
+ &ic->ic_wme.wme_chanParams.cap_wmeParams[aci];
+ /* AIFS[AC] = AIFSN[AC] * aSlotTime + aSIFSTime. */
+ aifs = ac->wmep_aifsn * slottime + 10;
+ rtwn_write_4(sc, aci2reg[aci],
+ SM(R92C_EDCA_PARAM_TXOP, ac->wmep_txopLimit) |
+ SM(R92C_EDCA_PARAM_ECWMIN, ac->wmep_logcwmin) |
+ SM(R92C_EDCA_PARAM_ECWMAX, ac->wmep_logcwmax) |
+ SM(R92C_EDCA_PARAM_AIFS, aifs));
+ }
+ IEEE80211_UNLOCK(ic);
+ return (0);
+}
+
+static void
+rtwn_update_avgrssi(struct rtwn_softc *sc, int rate, int8_t rssi)
+{
+ int pwdb;
+
+ /* Convert antenna signal to percentage. */
+ if (rssi <= -100 || rssi >= 20)
+ pwdb = 0;
+ else if (rssi >= 0)
+ pwdb = 100;
+ else
+ pwdb = 100 + rssi;
+ if (rate <= 3) {
+ /* CCK gain is smaller than OFDM/MCS gain. */
+ pwdb += 6;
+ if (pwdb > 100)
+ pwdb = 100;
+ if (pwdb <= 14)
+ pwdb -= 4;
+ else if (pwdb <= 26)
+ pwdb -= 8;
+ else if (pwdb <= 34)
+ pwdb -= 6;
+ else if (pwdb <= 42)
+ pwdb -= 2;
+ }
+ if (sc->avg_pwdb == -1) /* Init. */
+ sc->avg_pwdb = pwdb;
+ else if (sc->avg_pwdb < pwdb)
+ sc->avg_pwdb = ((sc->avg_pwdb * 19 + pwdb) / 20) + 1;
+ else
+ sc->avg_pwdb = ((sc->avg_pwdb * 19 + pwdb) / 20);
+ DPRINTFN(4, ("PWDB=%d EMA=%d\n", pwdb, sc->avg_pwdb));
+}
+
+static int8_t
+rtwn_get_rssi(struct rtwn_softc *sc, int rate, void *physt)
+{
+ static const int8_t cckoff[] = { 16, -12, -26, -46 };
+ struct r92c_rx_phystat *phy;
+ struct r92c_rx_cck *cck;
+ uint8_t rpt;
+ int8_t rssi;
+
+ if (rate <= 3) {
+ cck = (struct r92c_rx_cck *)physt;
+ if (sc->sc_flags & RTWN_FLAG_CCK_HIPWR) {
+ rpt = (cck->agc_rpt >> 5) & 0x3;
+ rssi = (cck->agc_rpt & 0x1f) << 1;
+ } else {
+ rpt = (cck->agc_rpt >> 6) & 0x3;
+ rssi = cck->agc_rpt & 0x3e;
+ }
+ rssi = cckoff[rpt] - rssi;
+ } else { /* OFDM/HT. */
+ phy = (struct r92c_rx_phystat *)physt;
+ rssi = ((le32toh(phy->phydw1) >> 1) & 0x7f) - 110;
+ }
+ return (rssi);
+}
+
+static void
+rtwn_rx_frame(struct rtwn_softc *sc, struct r92c_rx_desc *rx_desc,
+ struct rtwn_rx_data *rx_data, int desc_idx)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211_frame *wh;
+ struct ieee80211_node *ni;
+ struct r92c_rx_phystat *phy = NULL;
+ uint32_t rxdw0, rxdw3;
+ struct mbuf *m, *m1;
+ bus_dma_segment_t segs[1];
+ bus_addr_t physaddr;
+ uint8_t rate;
+ int8_t rssi = 0, nf;
+ int infosz, nsegs, pktlen, shift, error;
+
+ rxdw0 = le32toh(rx_desc->rxdw0);
+ rxdw3 = le32toh(rx_desc->rxdw3);
+
+ if (__predict_false(rxdw0 & (R92C_RXDW0_CRCERR | R92C_RXDW0_ICVERR))) {
+ /*
+ * This should not happen since we setup our Rx filter
+ * to not receive these frames.
+ */
+ counter_u64_add(ic->ic_ierrors, 1);
+ return;
+ }
+
+ pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN);
+ if (__predict_false(pktlen < sizeof(*wh) || pktlen > MCLBYTES)) {
+ counter_u64_add(ic->ic_ierrors, 1);
+ return;
+ }
+
+ rate = MS(rxdw3, R92C_RXDW3_RATE);
+ infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8;
+ if (infosz > sizeof(struct r92c_rx_phystat))
+ infosz = sizeof(struct r92c_rx_phystat);
+ shift = MS(rxdw0, R92C_RXDW0_SHIFT);
+
+ /* Get RSSI from PHY status descriptor if present. */
+ if (infosz != 0 && (rxdw0 & R92C_RXDW0_PHYST)) {
+ phy = mtod(rx_data->m, struct r92c_rx_phystat *);
+ rssi = rtwn_get_rssi(sc, rate, phy);
+ /* Update our average RSSI. */
+ rtwn_update_avgrssi(sc, rate, rssi);
+ }
+
+ DPRINTFN(5, ("Rx frame len=%d rate=%d infosz=%d shift=%d rssi=%d\n",
+ pktlen, rate, infosz, shift, rssi));
+
+ m1 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
+ if (m1 == NULL) {
+ counter_u64_add(ic->ic_ierrors, 1);
+ return;
+ }
+ bus_dmamap_unload(sc->rx_ring.data_dmat, rx_data->map);
+
+ error = bus_dmamap_load(sc->rx_ring.data_dmat, rx_data->map,
+ mtod(m1, void *), MCLBYTES, rtwn_dma_map_addr,
+ &physaddr, 0);
+ if (error != 0) {
+ m_freem(m1);
+
+ if (bus_dmamap_load_mbuf_sg(sc->rx_ring.data_dmat,
+ rx_data->map, rx_data->m, segs, &nsegs, 0))
+ panic("%s: could not load old RX mbuf",
+ device_get_name(sc->sc_dev));
+
+ /* Physical address may have changed. */
+ rtwn_setup_rx_desc(sc, rx_desc, physaddr, MCLBYTES, desc_idx);
+ counter_u64_add(ic->ic_ierrors, 1);
+ return;
+ }
+
+ /* Finalize mbuf. */
+ m = rx_data->m;
+ rx_data->m = m1;
+ m->m_pkthdr.len = m->m_len = pktlen + infosz + shift;
+
+ /* Update RX descriptor. */
+ rtwn_setup_rx_desc(sc, rx_desc, physaddr, MCLBYTES, desc_idx);
+
+ /* Get ieee80211 frame header. */
+ if (rxdw0 & R92C_RXDW0_PHYST)
+ m_adj(m, infosz + shift);
+ else
+ m_adj(m, shift);
+
+ nf = -95;
+ if (ieee80211_radiotap_active(ic)) {
+ struct rtwn_rx_radiotap_header *tap = &sc->sc_rxtap;
+
+ tap->wr_flags = 0;
+ if (!(rxdw3 & R92C_RXDW3_HT)) {
+ switch (rate) {
+ /* CCK. */
+ case 0: tap->wr_rate = 2; break;
+ case 1: tap->wr_rate = 4; break;
+ case 2: tap->wr_rate = 11; break;
+ case 3: tap->wr_rate = 22; break;
+ /* OFDM. */
+ case 4: tap->wr_rate = 12; break;
+ case 5: tap->wr_rate = 18; break;
+ case 6: tap->wr_rate = 24; break;
+ case 7: tap->wr_rate = 36; break;
+ case 8: tap->wr_rate = 48; break;
+ case 9: tap->wr_rate = 72; break;
+ case 10: tap->wr_rate = 96; break;
+ case 11: tap->wr_rate = 108; break;
+ }
+ } else if (rate >= 12) { /* MCS0~15. */
+ /* Bit 7 set means HT MCS instead of rate. */
+ tap->wr_rate = 0x80 | (rate - 12);
+ }
+ tap->wr_dbm_antsignal = rssi;
+ tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq);
+ tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags);
+ }
+
+ RTWN_UNLOCK(sc);
+ wh = mtod(m, struct ieee80211_frame *);
+
+ /* Send the frame to the 802.11 layer. */
+ ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh);
+ if (ni != NULL) {
+ (void)ieee80211_input(ni, m, rssi - nf, nf);
+ /* Node is no longer needed. */
+ ieee80211_free_node(ni);
+ } else
+ (void)ieee80211_input_all(ic, m, rssi - nf, nf);
+
+ RTWN_LOCK(sc);
+}
+
+static int
+rtwn_tx(struct rtwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211vap *vap = ni->ni_vap;
+ struct ieee80211_frame *wh;
+ struct ieee80211_key *k = NULL;
+ struct rtwn_tx_ring *tx_ring;
+ struct rtwn_tx_data *data;
+ struct r92c_tx_desc *txd;
+ bus_dma_segment_t segs[1];
+ uint16_t qos;
+ uint8_t raid, type, tid, qid;
+ int nsegs, error;
+
+ wh = mtod(m, struct ieee80211_frame *);
+ type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
+
+ /* Encrypt the frame if need be. */
+ if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
+ k = ieee80211_crypto_encap(ni, m);
+ if (k == NULL) {
+ m_freem(m);
+ return (ENOBUFS);
+ }
+ /* 802.11 header may have moved. */
+ wh = mtod(m, struct ieee80211_frame *);
+ }
+
+ if (IEEE80211_QOS_HAS_SEQ(wh)) {
+ qos = ((const struct ieee80211_qosframe *)wh)->i_qos[0];
+ tid = qos & IEEE80211_QOS_TID;
+ } else {
+ qos = 0;
+ tid = 0;
+ }
+
+ switch (type) {
+ case IEEE80211_FC0_TYPE_CTL:
+ case IEEE80211_FC0_TYPE_MGT:
+ qid = RTWN_VO_QUEUE;
+ break;
+ default:
+ qid = M_WME_GETAC(m);
+ break;
+ }
+
+ /* Grab a Tx buffer from the ring. */
+ tx_ring = &sc->tx_ring[qid];
+ data = &tx_ring->tx_data[tx_ring->cur];
+ if (data->m != NULL) {
+ m_freem(m);
+ return (ENOBUFS);
+ }
+
+ /* Fill Tx descriptor. */
+ txd = &tx_ring->desc[tx_ring->cur];
+ if (htole32(txd->txdw0) & R92C_RXDW0_OWN) {
+ m_freem(m);
+ return (ENOBUFS);
+ }
+ txd->txdw0 = htole32(
+ SM(R92C_TXDW0_PKTLEN, m->m_pkthdr.len) |
+ SM(R92C_TXDW0_OFFSET, sizeof(*txd)) |
+ R92C_TXDW0_FSG | R92C_TXDW0_LSG);
+ if (IEEE80211_IS_MULTICAST(wh->i_addr1))
+ txd->txdw0 |= htole32(R92C_TXDW0_BMCAST);
+
+ txd->txdw1 = 0;
+ txd->txdw4 = 0;
+ txd->txdw5 = 0;
+
+ /* XXX TODO: rate control; implement low-rate for EAPOL */
+ if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
+ type == IEEE80211_FC0_TYPE_DATA) {
+ if (ic->ic_curmode == IEEE80211_MODE_11B)
+ raid = R92C_RAID_11B;
+ else
+ raid = R92C_RAID_11BG;
+ txd->txdw1 |= htole32(
+ SM(R92C_TXDW1_MACID, RTWN_MACID_BSS) |
+ SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_BE) |
+ SM(R92C_TXDW1_RAID, raid) |
+ R92C_TXDW1_AGGBK);
+
+ if (ic->ic_flags & IEEE80211_F_USEPROT) {
+ if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) {
+ txd->txdw4 |= htole32(R92C_TXDW4_CTS2SELF |
+ R92C_TXDW4_HWRTSEN);
+ } else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) {
+ txd->txdw4 |= htole32(R92C_TXDW4_RTSEN |
+ R92C_TXDW4_HWRTSEN);
+ }
+ }
+
+ /* XXX TODO: implement rate control */
+
+ /* Send RTS at OFDM24. */
+ txd->txdw4 |= htole32(SM(R92C_TXDW4_RTSRATE, 8));
+ txd->txdw5 |= htole32(SM(R92C_TXDW5_RTSRATE_FBLIMIT, 0xf));
+ /* Send data at OFDM54. */
+ txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, 11));
+ txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE_FBLIMIT, 0x1f));
+
+ } else {
+ txd->txdw1 |= htole32(
+ SM(R92C_TXDW1_MACID, 0) |
+ SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT) |
+ SM(R92C_TXDW1_RAID, R92C_RAID_11B));
+
+ /* Force CCK1. */
+ txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE);
+ txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, 0));
+ }
+ /* Set sequence number (already little endian). */
+ txd->txdseq = *(uint16_t *)wh->i_seq;
+
+ if (!qos) {
+ /* Use HW sequence numbering for non-QoS frames. */
+ txd->txdw4 |= htole32(R92C_TXDW4_HWSEQ);
+ txd->txdseq |= htole16(0x8000);
+ } else
+ txd->txdw4 |= htole32(R92C_TXDW4_QOS);
+
+ error = bus_dmamap_load_mbuf_sg(tx_ring->data_dmat, data->map, m, segs,
+ &nsegs, BUS_DMA_NOWAIT);
+ if (error != 0 && error != EFBIG) {
+ device_printf(sc->sc_dev, "can't map mbuf (error %d)\n", error);
+ m_freem(m);
+ return (error);
+ }
+ if (error != 0) {
+ struct mbuf *mnew;
+
+ mnew = m_defrag(m, M_NOWAIT);
+ if (mnew == NULL) {
+ device_printf(sc->sc_dev,
+ "can't defragment mbuf\n");
+ m_freem(m);
+ return (ENOBUFS);
+ }
+ m = mnew;
+
+ error = bus_dmamap_load_mbuf_sg(tx_ring->data_dmat, data->map,
+ m, segs, &nsegs, BUS_DMA_NOWAIT);
+ if (error != 0) {
+ device_printf(sc->sc_dev,
+ "can't map mbuf (error %d)\n", error);
+ m_freem(m);
+ return (error);
+ }
+ }
+
+ txd->txbufaddr = htole32(segs[0].ds_addr);
+ txd->txbufsize = htole16(m->m_pkthdr.len);
+ bus_space_barrier(sc->sc_st, sc->sc_sh, 0, sc->sc_mapsize,
+ BUS_SPACE_BARRIER_WRITE);
+ txd->txdw0 |= htole32(R92C_TXDW0_OWN);
+
+ bus_dmamap_sync(tx_ring->desc_dmat, tx_ring->desc_map,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_sync(tx_ring->data_dmat, data->map, BUS_DMASYNC_POSTWRITE);
+
+ data->m = m;
+ data->ni = ni;
+
+ if (ieee80211_radiotap_active_vap(vap)) {
+ struct rtwn_tx_radiotap_header *tap = &sc->sc_txtap;
+
+ tap->wt_flags = 0;
+ tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq);
+ tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags);
+
+ ieee80211_radiotap_tx(vap, m);
+ }
+
+ tx_ring->cur = (tx_ring->cur + 1) % RTWN_TX_LIST_COUNT;
+ tx_ring->queued++;
+
+ if (tx_ring->queued >= (RTWN_TX_LIST_COUNT - 1))
+ sc->qfullmsk |= (1 << qid);
+
+ /* Kick TX. */
+ rtwn_write_2(sc, R92C_PCIE_CTRL_REG, (1 << qid));
+ return (0);
+}
+
+static void
+rtwn_tx_done(struct rtwn_softc *sc, int qid)
+{
+ struct rtwn_tx_ring *tx_ring = &sc->tx_ring[qid];
+ struct rtwn_tx_data *tx_data;
+ struct r92c_tx_desc *tx_desc;
+ int i;
+
+ bus_dmamap_sync(tx_ring->desc_dmat, tx_ring->desc_map,
+ BUS_DMASYNC_POSTREAD);
+
+ for (i = 0; i < RTWN_TX_LIST_COUNT; i++) {
+ tx_data = &tx_ring->tx_data[i];
+ if (tx_data->m == NULL)
+ continue;
+
+ tx_desc = &tx_ring->desc[i];
+ if (le32toh(tx_desc->txdw0) & R92C_TXDW0_OWN)
+ continue;
+
+ bus_dmamap_unload(tx_ring->desc_dmat, tx_ring->desc_map);
+
+ /*
+ * XXX TODO: figure out whether the transmit succeeded or not.
+ * .. and then notify rate control.
+ */
+ ieee80211_tx_complete(tx_data->ni, tx_data->m, 0);
+ tx_data->ni = NULL;
+ tx_data->m = NULL;
+
+ sc->sc_tx_timer = 0;
+ tx_ring->queued--;
+ }
+
+ if (tx_ring->queued < (RTWN_TX_LIST_COUNT - 1))
+ sc->qfullmsk &= ~(1 << qid);
+ rtwn_start(sc);
+}
+
+static int
+rtwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
+ const struct ieee80211_bpf_params *params)
+{
+ struct ieee80211com *ic = ni->ni_ic;
+ struct rtwn_softc *sc = ic->ic_softc;
+
+ RTWN_LOCK(sc);
+
+ /* Prevent management frames from being sent if we're not ready. */
+ if (!(sc->sc_flags & RTWN_RUNNING)) {
+ RTWN_UNLOCK(sc);
+ m_freem(m);
+ return (ENETDOWN);
+ }
+
+ if (rtwn_tx(sc, m, ni) != 0) {
+ m_freem(m);
+ RTWN_UNLOCK(sc);
+ return (EIO);
+ }
+ sc->sc_tx_timer = 5;
+ RTWN_UNLOCK(sc);
+ return (0);
+}
+
+static int
+rtwn_transmit(struct ieee80211com *ic, struct mbuf *m)
+{
+ struct rtwn_softc *sc = ic->ic_softc;
+ int error;
+
+ RTWN_LOCK(sc);
+ if ((sc->sc_flags & RTWN_RUNNING) == 0) {
+ RTWN_UNLOCK(sc);
+ return (ENXIO);
+ }
+ error = mbufq_enqueue(&sc->sc_snd, m);
+ if (error) {
+ RTWN_UNLOCK(sc);
+ return (error);
+ }
+ rtwn_start(sc);
+ RTWN_UNLOCK(sc);
+ return (0);
+}
+
+static void
+rtwn_parent(struct ieee80211com *ic)
+{
+ struct rtwn_softc *sc = ic->ic_softc;
+ int startall = 0;
+
+ RTWN_LOCK(sc);
+ if (ic->ic_nrunning> 0) {
+ if (!(sc->sc_flags & RTWN_RUNNING)) {
+ rtwn_init_locked(sc);
+ startall = 1;
+ }
+ } else if (sc->sc_flags & RTWN_RUNNING)
+ rtwn_stop_locked(sc);
+ RTWN_UNLOCK(sc);
+ if (startall)
+ ieee80211_start_all(ic);
+}
+
+static void
+rtwn_start(struct rtwn_softc *sc)
+{
+ struct ieee80211_node *ni;
+ struct mbuf *m;
+
+ RTWN_LOCK_ASSERT(sc);
+
+ if ((sc->sc_flags & RTWN_RUNNING) == 0)
+ return;
+
+ while (sc->qfullmsk == 0 && (m = mbufq_dequeue(&sc->sc_snd)) != NULL) {
+ ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
+ if (rtwn_tx(sc, m, ni) != 0) {
+ if_inc_counter(ni->ni_vap->iv_ifp,
+ IFCOUNTER_OERRORS, 1);
+ ieee80211_free_node(ni);
+ continue;
+ }
+ sc->sc_tx_timer = 5;
+ }
+}
+
+static void
+rtwn_watchdog(void *arg)
+{
+ struct rtwn_softc *sc = arg;
+ struct ieee80211com *ic = &sc->sc_ic;
+
+ RTWN_LOCK_ASSERT(sc);
+
+ KASSERT(sc->sc_flags & RTWN_RUNNING, ("not running"));
+
+ if (sc->sc_tx_timer != 0 && --sc->sc_tx_timer == 0) {
+ ic_printf(ic, "device timeout\n");
+ ieee80211_runtask(ic, &sc->sc_reinit_task);
+ return;
+ }
+ callout_reset(&sc->watchdog_to, hz, rtwn_watchdog, sc);
+}
+
+static int
+rtwn_power_on(struct rtwn_softc *sc)
+{
+ uint32_t reg;
+ int ntries;
+
+ /* Wait for autoload done bit. */
+ for (ntries = 0; ntries < 1000; ntries++) {
+ if (rtwn_read_1(sc, R92C_APS_FSMCO) & R92C_APS_FSMCO_PFM_ALDN)
+ break;
+ DELAY(5);
+ }
+ if (ntries == 1000) {
+ device_printf(sc->sc_dev,
+ "timeout waiting for chip autoload\n");
+ return (ETIMEDOUT);
+ }
+
+ /* Unlock ISO/CLK/Power control register. */
+ rtwn_write_1(sc, R92C_RSV_CTRL, 0);
+
+ /* TODO: check if we need this for 8188CE */
+ if (sc->board_type != R92C_BOARD_TYPE_DONGLE) {
+ /* bt coex */
+ reg = rtwn_read_4(sc, R92C_APS_FSMCO);
+ reg |= (R92C_APS_FSMCO_SOP_ABG |
+ R92C_APS_FSMCO_SOP_AMB |
+ R92C_APS_FSMCO_XOP_BTCK);
+ rtwn_write_4(sc, R92C_APS_FSMCO, reg);
+ }
+
+ /* Move SPS into PWM mode. */
+ rtwn_write_1(sc, R92C_SPS0_CTRL, 0x2b);
+
+ /* Set low byte to 0x0f, leave others unchanged. */
+ rtwn_write_4(sc, R92C_AFE_XTAL_CTRL,
+ (rtwn_read_4(sc, R92C_AFE_XTAL_CTRL) & 0xffffff00) | 0x0f);
+
+ /* TODO: check if we need this for 8188CE */
+ if (sc->board_type != R92C_BOARD_TYPE_DONGLE) {
+ /* bt coex */
+ reg = rtwn_read_4(sc, R92C_AFE_XTAL_CTRL);
+ reg &= (~0x00024800); /* XXX magic from linux */
+ rtwn_write_4(sc, R92C_AFE_XTAL_CTRL, reg);
+ }
+
+ rtwn_write_2(sc, R92C_SYS_ISO_CTRL,
+ (rtwn_read_2(sc, R92C_SYS_ISO_CTRL) & 0xff) |
+ R92C_SYS_ISO_CTRL_PWC_EV12V | R92C_SYS_ISO_CTRL_DIOR);
+ DELAY(200);
+
+ /* TODO: linux does additional btcoex stuff here */
+
+ /* Auto enable WLAN. */
+ rtwn_write_2(sc, R92C_APS_FSMCO,
+ rtwn_read_2(sc, R92C_APS_FSMCO) | R92C_APS_FSMCO_APFM_ONMAC);
+ for (ntries = 0; ntries < 1000; ntries++) {
+ if (!(rtwn_read_2(sc, R92C_APS_FSMCO) &
+ R92C_APS_FSMCO_APFM_ONMAC))
+ break;
+ DELAY(5);
+ }
+ if (ntries == 1000) {
+ device_printf(sc->sc_dev, "timeout waiting for MAC auto ON\n");
+ return (ETIMEDOUT);
+ }
+
+ /* Enable radio, GPIO and LED functions. */
+ rtwn_write_2(sc, R92C_APS_FSMCO,
+ R92C_APS_FSMCO_AFSM_PCIE |
+ R92C_APS_FSMCO_PDN_EN |
+ R92C_APS_FSMCO_PFM_ALDN);
+ /* Release RF digital isolation. */
+ rtwn_write_2(sc, R92C_SYS_ISO_CTRL,
+ rtwn_read_2(sc, R92C_SYS_ISO_CTRL) & ~R92C_SYS_ISO_CTRL_DIOR);
+
+ if (sc->chip & RTWN_CHIP_92C)
+ rtwn_write_1(sc, R92C_PCIE_CTRL_REG + 3, 0x77);
+ else
+ rtwn_write_1(sc, R92C_PCIE_CTRL_REG + 3, 0x22);
+
+ rtwn_write_4(sc, R92C_INT_MIG, 0);
+
+ if (sc->board_type != R92C_BOARD_TYPE_DONGLE) {
+ /* bt coex */
+ reg = rtwn_read_4(sc, R92C_AFE_XTAL_CTRL + 2);
+ reg &= 0xfd; /* XXX magic from linux */
+ rtwn_write_4(sc, R92C_AFE_XTAL_CTRL + 2, reg);
+ }
+
+ rtwn_write_1(sc, R92C_GPIO_MUXCFG,
+ rtwn_read_1(sc, R92C_GPIO_MUXCFG) & ~R92C_GPIO_MUXCFG_RFKILL);
+
+ reg = rtwn_read_1(sc, R92C_GPIO_IO_SEL);
+ if (!(reg & R92C_GPIO_IO_SEL_RFKILL)) {
+ device_printf(sc->sc_dev,
+ "radio is disabled by hardware switch\n");
+ return (EPERM);
+ }
+
+ /* Initialize MAC. */
+ reg = rtwn_read_1(sc, R92C_APSD_CTRL);
+ rtwn_write_1(sc, R92C_APSD_CTRL,
+ rtwn_read_1(sc, R92C_APSD_CTRL) & ~R92C_APSD_CTRL_OFF);
+ for (ntries = 0; ntries < 200; ntries++) {
+ if (!(rtwn_read_1(sc, R92C_APSD_CTRL) &
+ R92C_APSD_CTRL_OFF_STATUS))
+ break;
+ DELAY(500);
+ }
+ if (ntries == 200) {
+ device_printf(sc->sc_dev,
+ "timeout waiting for MAC initialization\n");
+ return (ETIMEDOUT);
+ }
+
+ /* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */
+ reg = rtwn_read_2(sc, R92C_CR);
+ reg |= R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN |
+ R92C_CR_TXDMA_EN | R92C_CR_RXDMA_EN | R92C_CR_PROTOCOL_EN |
+ R92C_CR_SCHEDULE_EN | R92C_CR_MACTXEN | R92C_CR_MACRXEN |
+ R92C_CR_ENSEC;
+ rtwn_write_2(sc, R92C_CR, reg);
+
+ rtwn_write_1(sc, 0xfe10, 0x19);
+
+ return (0);
+}
+
+static int
+rtwn_llt_init(struct rtwn_softc *sc)
+{
+ int i, error;
+
+ /* Reserve pages [0; R92C_TX_PAGE_COUNT]. */
+ for (i = 0; i < R92C_TX_PAGE_COUNT; i++) {
+ if ((error = rtwn_llt_write(sc, i, i + 1)) != 0)
+ return (error);
+ }
+ /* NB: 0xff indicates end-of-list. */
+ if ((error = rtwn_llt_write(sc, i, 0xff)) != 0)
+ return (error);
+ /*
+ * Use pages [R92C_TX_PAGE_COUNT + 1; R92C_TXPKTBUF_COUNT - 1]
+ * as ring buffer.
+ */
+ for (++i; i < R92C_TXPKTBUF_COUNT - 1; i++) {
+ if ((error = rtwn_llt_write(sc, i, i + 1)) != 0)
+ return (error);
+ }
+ /* Make the last page point to the beginning of the ring buffer. */
+ error = rtwn_llt_write(sc, i, R92C_TX_PAGE_COUNT + 1);
+ return (error);
+}
+
+static void
+rtwn_fw_reset(struct rtwn_softc *sc)
+{
+ uint16_t reg;
+ int ntries;
+
+ /* Tell 8051 to reset itself. */
+ rtwn_write_1(sc, R92C_HMETFR + 3, 0x20);
+
+ /* Wait until 8051 resets by itself. */
+ for (ntries = 0; ntries < 100; ntries++) {
+ reg = rtwn_read_2(sc, R92C_SYS_FUNC_EN);
+ if (!(reg & R92C_SYS_FUNC_EN_CPUEN))
+ goto sleep;
+ DELAY(50);
+ }
+ /* Force 8051 reset. */
+ rtwn_write_2(sc, R92C_SYS_FUNC_EN, reg & ~R92C_SYS_FUNC_EN_CPUEN);
+sleep:
+ /*
+ * We must sleep for one second to let the firmware settle.
+ * Accessing registers too early will hang the whole system.
+ */
+ if (msleep(&reg, &sc->sc_mtx, 0, "rtwnrst", hz)) {
+ device_printf(sc->sc_dev, "timeout waiting for firmware "
+ "initialization to complete\n");
+ }
+}
+
+static void
+rtwn_fw_loadpage(struct rtwn_softc *sc, int page, const uint8_t *buf, int len)
+{
+ uint32_t reg;
+ int off, mlen, i;
+
+ reg = rtwn_read_4(sc, R92C_MCUFWDL);
+ reg = RW(reg, R92C_MCUFWDL_PAGE, page);
+ rtwn_write_4(sc, R92C_MCUFWDL, reg);
+
+ DELAY(5);
+
+ off = R92C_FW_START_ADDR;
+ while (len > 0) {
+ if (len > 196)
+ mlen = 196;
+ else if (len > 4)
+ mlen = 4;
+ else
+ mlen = 1;
+ for (i = 0; i < mlen; i++)
+ rtwn_write_1(sc, off++, buf[i]);
+ buf += mlen;
+ len -= mlen;
+ }
+}
+
+static int
+rtwn_load_firmware(struct rtwn_softc *sc)
+{
+ const struct firmware *fw;
+ const struct r92c_fw_hdr *hdr;
+ const char *name;
+ const u_char *ptr;
+ size_t len;
+ uint32_t reg;
+ int mlen, ntries, page, error = 0;
+
+ /* Read firmware image from the filesystem. */
+ if ((sc->chip & (RTWN_CHIP_UMC_A_CUT | RTWN_CHIP_92C)) ==
+ RTWN_CHIP_UMC_A_CUT)
+ name = "rtwn-rtl8192cfwU";
+ else
+ name = "rtwn-rtl8192cfwU_B";
+ RTWN_UNLOCK(sc);
+ fw = firmware_get(name);
+ RTWN_LOCK(sc);
+ if (fw == NULL) {
+ device_printf(sc->sc_dev,
+ "could not read firmware %s\n", name);
+ return (ENOENT);
+ }
+ len = fw->datasize;
+ if (len < sizeof(*hdr)) {
+ device_printf(sc->sc_dev, "firmware too short\n");
+ error = EINVAL;
+ goto fail;
+ }
+ ptr = fw->data;
+ hdr = (const struct r92c_fw_hdr *)ptr;
+ /* Check if there is a valid FW header and skip it. */
+ if ((le16toh(hdr->signature) >> 4) == 0x88c ||
+ (le16toh(hdr->signature) >> 4) == 0x92c) {
+ DPRINTF(("FW V%d.%d %02d-%02d %02d:%02d\n",
+ le16toh(hdr->version), le16toh(hdr->subversion),
+ hdr->month, hdr->date, hdr->hour, hdr->minute));
+ ptr += sizeof(*hdr);
+ len -= sizeof(*hdr);
+ }
+
+ if (rtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RAM_DL_SEL)
+ rtwn_fw_reset(sc);
+
+ /* Enable FW download. */
+ rtwn_write_2(sc, R92C_SYS_FUNC_EN,
+ rtwn_read_2(sc, R92C_SYS_FUNC_EN) |
+ R92C_SYS_FUNC_EN_CPUEN);
+ rtwn_write_1(sc, R92C_MCUFWDL,
+ rtwn_read_1(sc, R92C_MCUFWDL) | R92C_MCUFWDL_EN);
+ rtwn_write_1(sc, R92C_MCUFWDL + 2,
+ rtwn_read_1(sc, R92C_MCUFWDL + 2) & ~0x08);
+
+ /* Reset the FWDL checksum. */
+ rtwn_write_1(sc, R92C_MCUFWDL,
+ rtwn_read_1(sc, R92C_MCUFWDL) | R92C_MCUFWDL_CHKSUM_RPT);
+
+ for (page = 0; len > 0; page++) {
+ mlen = MIN(len, R92C_FW_PAGE_SIZE);
+ rtwn_fw_loadpage(sc, page, ptr, mlen);
+ ptr += mlen;
+ len -= mlen;
+ }
+
+ /* Disable FW download. */
+ rtwn_write_1(sc, R92C_MCUFWDL,
+ rtwn_read_1(sc, R92C_MCUFWDL) & ~R92C_MCUFWDL_EN);
+ rtwn_write_1(sc, R92C_MCUFWDL + 1, 0);
+
+ /* Wait for checksum report. */
+ for (ntries = 0; ntries < 1000; ntries++) {
+ if (rtwn_read_4(sc, R92C_MCUFWDL) & R92C_MCUFWDL_CHKSUM_RPT)
+ break;
+ DELAY(5);
+ }
+ if (ntries == 1000) {
+ device_printf(sc->sc_dev,
+ "timeout waiting for checksum report\n");
+ error = ETIMEDOUT;
+ goto fail;
+ }
+
+ reg = rtwn_read_4(sc, R92C_MCUFWDL);
+ reg = (reg & ~R92C_MCUFWDL_WINTINI_RDY) | R92C_MCUFWDL_RDY;
+ rtwn_write_4(sc, R92C_MCUFWDL, reg);
+ /* Wait for firmware readiness. */
+ for (ntries = 0; ntries < 2000; ntries++) {
+ if (rtwn_read_4(sc, R92C_MCUFWDL) & R92C_MCUFWDL_WINTINI_RDY)
+ break;
+ DELAY(50);
+ }
+ if (ntries == 1000) {
+ device_printf(sc->sc_dev,
+ "timeout waiting for firmware readiness\n");
+ error = ETIMEDOUT;
+ goto fail;
+ }
+fail:
+ firmware_put(fw, FIRMWARE_UNLOAD);
+ return (error);
+}
+
+static int
+rtwn_dma_init(struct rtwn_softc *sc)
+{
+ uint32_t reg;
+ int error;
+
+ /* Initialize LLT table. */
+ error = rtwn_llt_init(sc);
+ if (error != 0)
+ return error;
+
+ /* Set number of pages for normal priority queue. */
+ rtwn_write_2(sc, R92C_RQPN_NPQ, 0);
+ rtwn_write_4(sc, R92C_RQPN,
+ /* Set number of pages for public queue. */
+ SM(R92C_RQPN_PUBQ, R92C_PUBQ_NPAGES) |
+ /* Set number of pages for high priority queue. */
+ SM(R92C_RQPN_HPQ, R92C_HPQ_NPAGES) |
+ /* Set number of pages for low priority queue. */
+ SM(R92C_RQPN_LPQ, R92C_LPQ_NPAGES) |
+ /* Load values. */
+ R92C_RQPN_LD);
+
+ rtwn_write_1(sc, R92C_TXPKTBUF_BCNQ_BDNY, R92C_TX_PAGE_BOUNDARY);
+ rtwn_write_1(sc, R92C_TXPKTBUF_MGQ_BDNY, R92C_TX_PAGE_BOUNDARY);
+ rtwn_write_1(sc, R92C_TXPKTBUF_WMAC_LBK_BF_HD, R92C_TX_PAGE_BOUNDARY);
+ rtwn_write_1(sc, R92C_TRXFF_BNDY, R92C_TX_PAGE_BOUNDARY);
+ rtwn_write_1(sc, R92C_TDECTRL + 1, R92C_TX_PAGE_BOUNDARY);
+
+ reg = rtwn_read_2(sc, R92C_TRXDMA_CTRL);
+ reg &= ~R92C_TRXDMA_CTRL_QMAP_M;
+ reg |= 0xF771;
+ rtwn_write_2(sc, R92C_TRXDMA_CTRL, reg);
+
+ rtwn_write_4(sc, R92C_TCR, R92C_TCR_CFENDFORM | (1 << 12) | (1 << 13));
+
+ /* Configure Tx DMA. */
+ rtwn_write_4(sc, R92C_BKQ_DESA, sc->tx_ring[RTWN_BK_QUEUE].paddr);
+ rtwn_write_4(sc, R92C_BEQ_DESA, sc->tx_ring[RTWN_BE_QUEUE].paddr);
+ rtwn_write_4(sc, R92C_VIQ_DESA, sc->tx_ring[RTWN_VI_QUEUE].paddr);
+ rtwn_write_4(sc, R92C_VOQ_DESA, sc->tx_ring[RTWN_VO_QUEUE].paddr);
+ rtwn_write_4(sc, R92C_BCNQ_DESA, sc->tx_ring[RTWN_BEACON_QUEUE].paddr);
+ rtwn_write_4(sc, R92C_MGQ_DESA, sc->tx_ring[RTWN_MGNT_QUEUE].paddr);
+ rtwn_write_4(sc, R92C_HQ_DESA, sc->tx_ring[RTWN_HIGH_QUEUE].paddr);
+
+ /* Configure Rx DMA. */
+ rtwn_write_4(sc, R92C_RX_DESA, sc->rx_ring.paddr);
+
+ /* Set Tx/Rx transfer page boundary. */
+ rtwn_write_2(sc, R92C_TRXFF_BNDY + 2, 0x27ff);
+
+ /* Set Tx/Rx transfer page size. */
+ rtwn_write_1(sc, R92C_PBP,
+ SM(R92C_PBP_PSRX, R92C_PBP_128) |
+ SM(R92C_PBP_PSTX, R92C_PBP_128));
+ return (0);
+}
+
+static void
+rtwn_mac_init(struct rtwn_softc *sc)
+{
+ int i;
+
+ /* Write MAC initialization values. */
+ for (i = 0; i < nitems(rtl8192ce_mac); i++)
+ rtwn_write_1(sc, rtl8192ce_mac[i].reg, rtl8192ce_mac[i].val);
+}
+
+static void
+rtwn_bb_init(struct rtwn_softc *sc)
+{
+ const struct rtwn_bb_prog *prog;
+ uint32_t reg;
+ int i;
+
+ /* Enable BB and RF. */
+ rtwn_write_2(sc, R92C_SYS_FUNC_EN,
+ rtwn_read_2(sc, R92C_SYS_FUNC_EN) |
+ R92C_SYS_FUNC_EN_BBRSTB | R92C_SYS_FUNC_EN_BB_GLB_RST |
+ R92C_SYS_FUNC_EN_DIO_RF);
+
+ rtwn_write_2(sc, R92C_AFE_PLL_CTRL, 0xdb83);
+
+ rtwn_write_1(sc, R92C_RF_CTRL,
+ R92C_RF_CTRL_EN | R92C_RF_CTRL_RSTB | R92C_RF_CTRL_SDMRSTB);
+
+ rtwn_write_1(sc, R92C_SYS_FUNC_EN,
+ R92C_SYS_FUNC_EN_DIO_PCIE | R92C_SYS_FUNC_EN_PCIEA |
+ R92C_SYS_FUNC_EN_PPLL | R92C_SYS_FUNC_EN_BB_GLB_RST |
+ R92C_SYS_FUNC_EN_BBRSTB);
+
+ rtwn_write_1(sc, R92C_AFE_XTAL_CTRL + 1, 0x80);
+
+ rtwn_write_4(sc, R92C_LEDCFG0,
+ rtwn_read_4(sc, R92C_LEDCFG0) | 0x00800000);
+
+ /* Select BB programming. */
+ prog = (sc->chip & RTWN_CHIP_92C) ?
+ &rtl8192ce_bb_prog_2t : &rtl8192ce_bb_prog_1t;
+
+ /* Write BB initialization values. */
+ for (i = 0; i < prog->count; i++) {
+ rtwn_bb_write(sc, prog->regs[i], prog->vals[i]);
+ DELAY(1);
+ }
+
+ if (sc->chip & RTWN_CHIP_92C_1T2R) {
+ /* 8192C 1T only configuration. */
+ reg = rtwn_bb_read(sc, R92C_FPGA0_TXINFO);
+ reg = (reg & ~0x00000003) | 0x2;
+ rtwn_bb_write(sc, R92C_FPGA0_TXINFO, reg);
+
+ reg = rtwn_bb_read(sc, R92C_FPGA1_TXINFO);
+ reg = (reg & ~0x00300033) | 0x00200022;
+ rtwn_bb_write(sc, R92C_FPGA1_TXINFO, reg);
+
+ reg = rtwn_bb_read(sc, R92C_CCK0_AFESETTING);
+ reg = (reg & ~0xff000000) | 0x45 << 24;
+ rtwn_bb_write(sc, R92C_CCK0_AFESETTING, reg);
+
+ reg = rtwn_bb_read(sc, R92C_OFDM0_TRXPATHENA);
+ reg = (reg & ~0x000000ff) | 0x23;
+ rtwn_bb_write(sc, R92C_OFDM0_TRXPATHENA, reg);
+
+ reg = rtwn_bb_read(sc, R92C_OFDM0_AGCPARAM1);
+ reg = (reg & ~0x00000030) | 1 << 4;
+ rtwn_bb_write(sc, R92C_OFDM0_AGCPARAM1, reg);
+
+ reg = rtwn_bb_read(sc, 0xe74);
+ reg = (reg & ~0x0c000000) | 2 << 26;
+ rtwn_bb_write(sc, 0xe74, reg);
+ reg = rtwn_bb_read(sc, 0xe78);
+ reg = (reg & ~0x0c000000) | 2 << 26;
+ rtwn_bb_write(sc, 0xe78, reg);
+ reg = rtwn_bb_read(sc, 0xe7c);
+ reg = (reg & ~0x0c000000) | 2 << 26;
+ rtwn_bb_write(sc, 0xe7c, reg);
+ reg = rtwn_bb_read(sc, 0xe80);
+ reg = (reg & ~0x0c000000) | 2 << 26;
+ rtwn_bb_write(sc, 0xe80, reg);
+ reg = rtwn_bb_read(sc, 0xe88);
+ reg = (reg & ~0x0c000000) | 2 << 26;
+ rtwn_bb_write(sc, 0xe88, reg);
+ }
+
+ /* Write AGC values. */
+ for (i = 0; i < prog->agccount; i++) {
+ rtwn_bb_write(sc, R92C_OFDM0_AGCRSSITABLE,
+ prog->agcvals[i]);
+ DELAY(1);
+ }
+
+ if (rtwn_bb_read(sc, R92C_HSSI_PARAM2(0)) &
+ R92C_HSSI_PARAM2_CCK_HIPWR)
+ sc->sc_flags |= RTWN_FLAG_CCK_HIPWR;
+}
+
+static void
+rtwn_rf_init(struct rtwn_softc *sc)
+{
+ const struct rtwn_rf_prog *prog;
+ uint32_t reg, type;
+ int i, j, idx, off;
+
+ /* Select RF programming based on board type. */
+ if (!(sc->chip & RTWN_CHIP_92C)) {
+ if (sc->board_type == R92C_BOARD_TYPE_MINICARD)
+ prog = rtl8188ce_rf_prog;
+ else if (sc->board_type == R92C_BOARD_TYPE_HIGHPA)
+ prog = rtl8188ru_rf_prog;
+ else
+ prog = rtl8188cu_rf_prog;
+ } else
+ prog = rtl8192ce_rf_prog;
+
+ for (i = 0; i < sc->nrxchains; i++) {
+ /* Save RF_ENV control type. */
+ idx = i / 2;
+ off = (i % 2) * 16;
+ reg = rtwn_bb_read(sc, R92C_FPGA0_RFIFACESW(idx));
+ type = (reg >> off) & 0x10;
+
+ /* Set RF_ENV enable. */
+ reg = rtwn_bb_read(sc, R92C_FPGA0_RFIFACEOE(i));
+ reg |= 0x100000;
+ rtwn_bb_write(sc, R92C_FPGA0_RFIFACEOE(i), reg);
+ DELAY(1);
+ /* Set RF_ENV output high. */
+ reg = rtwn_bb_read(sc, R92C_FPGA0_RFIFACEOE(i));
+ reg |= 0x10;
+ rtwn_bb_write(sc, R92C_FPGA0_RFIFACEOE(i), reg);
+ DELAY(1);
+ /* Set address and data lengths of RF registers. */
+ reg = rtwn_bb_read(sc, R92C_HSSI_PARAM2(i));
+ reg &= ~R92C_HSSI_PARAM2_ADDR_LENGTH;
+ rtwn_bb_write(sc, R92C_HSSI_PARAM2(i), reg);
+ DELAY(1);
+ reg = rtwn_bb_read(sc, R92C_HSSI_PARAM2(i));
+ reg &= ~R92C_HSSI_PARAM2_DATA_LENGTH;
+ rtwn_bb_write(sc, R92C_HSSI_PARAM2(i), reg);
+ DELAY(1);
+
+ /* Write RF initialization values for this chain. */
+ for (j = 0; j < prog[i].count; j++) {
+ if (prog[i].regs[j] >= 0xf9 &&
+ prog[i].regs[j] <= 0xfe) {
+ /*
+ * These are fake RF registers offsets that
+ * indicate a delay is required.
+ */
+ DELAY(50);
+ continue;
+ }
+ rtwn_rf_write(sc, i, prog[i].regs[j],
+ prog[i].vals[j]);
+ DELAY(1);
+ }
+
+ /* Restore RF_ENV control type. */
+ reg = rtwn_bb_read(sc, R92C_FPGA0_RFIFACESW(idx));
+ reg &= ~(0x10 << off) | (type << off);
+ rtwn_bb_write(sc, R92C_FPGA0_RFIFACESW(idx), reg);
+
+ /* Cache RF register CHNLBW. */
+ sc->rf_chnlbw[i] = rtwn_rf_read(sc, i, R92C_RF_CHNLBW);
+ }
+
+ if ((sc->chip & (RTWN_CHIP_UMC_A_CUT | RTWN_CHIP_92C)) ==
+ RTWN_CHIP_UMC_A_CUT) {
+ rtwn_rf_write(sc, 0, R92C_RF_RX_G1, 0x30255);
+ rtwn_rf_write(sc, 0, R92C_RF_RX_G2, 0x50a00);
+ }
+}
+
+static void
+rtwn_cam_init(struct rtwn_softc *sc)
+{
+ /* Invalidate all CAM entries. */
+ rtwn_write_4(sc, R92C_CAMCMD,
+ R92C_CAMCMD_POLLING | R92C_CAMCMD_CLR);
+}
+
+static void
+rtwn_pa_bias_init(struct rtwn_softc *sc)
+{
+ uint8_t reg;
+ int i;
+
+ for (i = 0; i < sc->nrxchains; i++) {
+ if (sc->pa_setting & (1 << i))
+ continue;
+ rtwn_rf_write(sc, i, R92C_RF_IPA, 0x0f406);
+ rtwn_rf_write(sc, i, R92C_RF_IPA, 0x4f406);
+ rtwn_rf_write(sc, i, R92C_RF_IPA, 0x8f406);
+ rtwn_rf_write(sc, i, R92C_RF_IPA, 0xcf406);
+ }
+ if (!(sc->pa_setting & 0x10)) {
+ reg = rtwn_read_1(sc, 0x16);
+ reg = (reg & ~0xf0) | 0x90;
+ rtwn_write_1(sc, 0x16, reg);
+ }
+}
+
+static void
+rtwn_rxfilter_init(struct rtwn_softc *sc)
+{
+ /* Initialize Rx filter. */
+ /* TODO: use better filter for monitor mode. */
+ rtwn_write_4(sc, R92C_RCR,
+ R92C_RCR_AAP | R92C_RCR_APM | R92C_RCR_AM | R92C_RCR_AB |
+ R92C_RCR_APP_ICV | R92C_RCR_AMF | R92C_RCR_HTC_LOC_CTRL |
+ R92C_RCR_APP_MIC | R92C_RCR_APP_PHYSTS);
+ /* Accept all multicast frames. */
+ rtwn_write_4(sc, R92C_MAR + 0, 0xffffffff);
+ rtwn_write_4(sc, R92C_MAR + 4, 0xffffffff);
+ /* Accept all management frames. */
+ rtwn_write_2(sc, R92C_RXFLTMAP0, 0xffff);
+ /* Reject all control frames. */
+ rtwn_write_2(sc, R92C_RXFLTMAP1, 0x0000);
+ /* Accept all data frames. */
+ rtwn_write_2(sc, R92C_RXFLTMAP2, 0xffff);
+}
+
+static void
+rtwn_edca_init(struct rtwn_softc *sc)
+{
+
+ rtwn_write_2(sc, R92C_SPEC_SIFS, 0x1010);
+ rtwn_write_2(sc, R92C_MAC_SPEC_SIFS, 0x1010);
+ rtwn_write_2(sc, R92C_SIFS_CCK, 0x1010);
+ rtwn_write_2(sc, R92C_SIFS_OFDM, 0x0e0e);
+ rtwn_write_4(sc, R92C_EDCA_BE_PARAM, 0x005ea42b);
+ rtwn_write_4(sc, R92C_EDCA_BK_PARAM, 0x0000a44f);
+ rtwn_write_4(sc, R92C_EDCA_VI_PARAM, 0x005e4322);
+ rtwn_write_4(sc, R92C_EDCA_VO_PARAM, 0x002f3222);
+}
+
+static void
+rtwn_write_txpower(struct rtwn_softc *sc, int chain,
+ uint16_t power[RTWN_RIDX_COUNT])
+{
+ uint32_t reg;
+
+ /* Write per-CCK rate Tx power. */
+ if (chain == 0) {
+ reg = rtwn_bb_read(sc, R92C_TXAGC_A_CCK1_MCS32);
+ reg = RW(reg, R92C_TXAGC_A_CCK1, power[0]);
+ rtwn_bb_write(sc, R92C_TXAGC_A_CCK1_MCS32, reg);
+ reg = rtwn_bb_read(sc, R92C_TXAGC_B_CCK11_A_CCK2_11);
+ reg = RW(reg, R92C_TXAGC_A_CCK2, power[1]);
+ reg = RW(reg, R92C_TXAGC_A_CCK55, power[2]);
+ reg = RW(reg, R92C_TXAGC_A_CCK11, power[3]);
+ rtwn_bb_write(sc, R92C_TXAGC_B_CCK11_A_CCK2_11, reg);
+ } else {
+ reg = rtwn_bb_read(sc, R92C_TXAGC_B_CCK1_55_MCS32);
+ reg = RW(reg, R92C_TXAGC_B_CCK1, power[0]);
+ reg = RW(reg, R92C_TXAGC_B_CCK2, power[1]);
+ reg = RW(reg, R92C_TXAGC_B_CCK55, power[2]);
+ rtwn_bb_write(sc, R92C_TXAGC_B_CCK1_55_MCS32, reg);
+ reg = rtwn_bb_read(sc, R92C_TXAGC_B_CCK11_A_CCK2_11);
+ reg = RW(reg, R92C_TXAGC_B_CCK11, power[3]);
+ rtwn_bb_write(sc, R92C_TXAGC_B_CCK11_A_CCK2_11, reg);
+ }
+ /* Write per-OFDM rate Tx power. */
+ rtwn_bb_write(sc, R92C_TXAGC_RATE18_06(chain),
+ SM(R92C_TXAGC_RATE06, power[ 4]) |
+ SM(R92C_TXAGC_RATE09, power[ 5]) |
+ SM(R92C_TXAGC_RATE12, power[ 6]) |
+ SM(R92C_TXAGC_RATE18, power[ 7]));
+ rtwn_bb_write(sc, R92C_TXAGC_RATE54_24(chain),
+ SM(R92C_TXAGC_RATE24, power[ 8]) |
+ SM(R92C_TXAGC_RATE36, power[ 9]) |
+ SM(R92C_TXAGC_RATE48, power[10]) |
+ SM(R92C_TXAGC_RATE54, power[11]));
+ /* Write per-MCS Tx power. */
+ rtwn_bb_write(sc, R92C_TXAGC_MCS03_MCS00(chain),
+ SM(R92C_TXAGC_MCS00, power[12]) |
+ SM(R92C_TXAGC_MCS01, power[13]) |
+ SM(R92C_TXAGC_MCS02, power[14]) |
+ SM(R92C_TXAGC_MCS03, power[15]));
+ rtwn_bb_write(sc, R92C_TXAGC_MCS07_MCS04(chain),
+ SM(R92C_TXAGC_MCS04, power[16]) |
+ SM(R92C_TXAGC_MCS05, power[17]) |
+ SM(R92C_TXAGC_MCS06, power[18]) |
+ SM(R92C_TXAGC_MCS07, power[19]));
+ rtwn_bb_write(sc, R92C_TXAGC_MCS11_MCS08(chain),
+ SM(R92C_TXAGC_MCS08, power[20]) |
+ SM(R92C_TXAGC_MCS09, power[21]) |
+ SM(R92C_TXAGC_MCS10, power[22]) |
+ SM(R92C_TXAGC_MCS11, power[23]));
+ rtwn_bb_write(sc, R92C_TXAGC_MCS15_MCS12(chain),
+ SM(R92C_TXAGC_MCS12, power[24]) |
+ SM(R92C_TXAGC_MCS13, power[25]) |
+ SM(R92C_TXAGC_MCS14, power[26]) |
+ SM(R92C_TXAGC_MCS15, power[27]));
+}
+
+static void
+rtwn_get_txpower(struct rtwn_softc *sc, int chain,
+ struct ieee80211_channel *c, struct ieee80211_channel *extc,
+ uint16_t power[RTWN_RIDX_COUNT])
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct r92c_rom *rom = &sc->rom;
+ uint16_t cckpow, ofdmpow, htpow, diff, max;
+ const struct rtwn_txpwr *base;
+ int ridx, chan, group;
+
+ /* Determine channel group. */
+ chan = ieee80211_chan2ieee(ic, c); /* XXX center freq! */
+ if (chan <= 3)
+ group = 0;
+ else if (chan <= 9)
+ group = 1;
+ else
+ group = 2;
+
+ /* Get original Tx power based on board type and RF chain. */
+ if (!(sc->chip & RTWN_CHIP_92C)) {
+ if (sc->board_type == R92C_BOARD_TYPE_HIGHPA)
+ base = &rtl8188ru_txagc[chain];
+ else
+ base = &rtl8192cu_txagc[chain];
+ } else
+ base = &rtl8192cu_txagc[chain];
+
+ memset(power, 0, RTWN_RIDX_COUNT * sizeof(power[0]));
+ if (sc->regulatory == 0) {
+ for (ridx = 0; ridx <= 3; ridx++)
+ power[ridx] = base->pwr[0][ridx];
+ }
+ for (ridx = 4; ridx < RTWN_RIDX_COUNT; ridx++) {
+ if (sc->regulatory == 3) {
+ power[ridx] = base->pwr[0][ridx];
+ /* Apply vendor limits. */
+ if (extc != NULL)
+ max = rom->ht40_max_pwr[group];
+ else
+ max = rom->ht20_max_pwr[group];
+ max = (max >> (chain * 4)) & 0xf;
+ if (power[ridx] > max)
+ power[ridx] = max;
+ } else if (sc->regulatory == 1) {
+ if (extc == NULL)
+ power[ridx] = base->pwr[group][ridx];
+ } else if (sc->regulatory != 2)
+ power[ridx] = base->pwr[0][ridx];
+ }
+
+ /* Compute per-CCK rate Tx power. */
+ cckpow = rom->cck_tx_pwr[chain][group];
+ for (ridx = 0; ridx <= 3; ridx++) {
+ power[ridx] += cckpow;
+ if (power[ridx] > R92C_MAX_TX_PWR)
+ power[ridx] = R92C_MAX_TX_PWR;
+ }
+
+ htpow = rom->ht40_1s_tx_pwr[chain][group];
+ if (sc->ntxchains > 1) {
+ /* Apply reduction for 2 spatial streams. */
+ diff = rom->ht40_2s_tx_pwr_diff[group];
+ diff = (diff >> (chain * 4)) & 0xf;
+ htpow = (htpow > diff) ? htpow - diff : 0;
+ }
+
+ /* Compute per-OFDM rate Tx power. */
+ diff = rom->ofdm_tx_pwr_diff[group];
+ diff = (diff >> (chain * 4)) & 0xf;
+ ofdmpow = htpow + diff; /* HT->OFDM correction. */
+ for (ridx = 4; ridx <= 11; ridx++) {
+ power[ridx] += ofdmpow;
+ if (power[ridx] > R92C_MAX_TX_PWR)
+ power[ridx] = R92C_MAX_TX_PWR;
+ }
+
+ /* Compute per-MCS Tx power. */
+ if (extc == NULL) {
+ diff = rom->ht20_tx_pwr_diff[group];
+ diff = (diff >> (chain * 4)) & 0xf;
+ htpow += diff; /* HT40->HT20 correction. */
+ }
+ for (ridx = 12; ridx <= 27; ridx++) {
+ power[ridx] += htpow;
+ if (power[ridx] > R92C_MAX_TX_PWR)
+ power[ridx] = R92C_MAX_TX_PWR;
+ }
+#ifdef RTWN_DEBUG
+ if (sc->sc_debug >= 4) {
+ /* Dump per-rate Tx power values. */
+ printf("Tx power for chain %d:\n", chain);
+ for (ridx = 0; ridx < RTWN_RIDX_COUNT; ridx++)
+ printf("Rate %d = %u\n", ridx, power[ridx]);
+ }
+#endif
+}
+
+static void
+rtwn_set_txpower(struct rtwn_softc *sc, struct ieee80211_channel *c,
+ struct ieee80211_channel *extc)
+{
+ uint16_t power[RTWN_RIDX_COUNT];
+ int i;
+
+ for (i = 0; i < sc->ntxchains; i++) {
+ /* Compute per-rate Tx power values. */
+ rtwn_get_txpower(sc, i, c, extc, power);
+ /* Write per-rate Tx power values to hardware. */
+ rtwn_write_txpower(sc, i, power);
+ }
+}
+
+static void
+rtwn_scan_start(struct ieee80211com *ic)
+{
+
+ /* XXX do nothing? */
+}
+
+static void
+rtwn_scan_end(struct ieee80211com *ic)
+{
+
+ /* XXX do nothing? */
+}
+
+static void
+rtwn_set_channel(struct ieee80211com *ic)
+{
+ struct rtwn_softc *sc = ic->ic_softc;
+ struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
+
+ RTWN_LOCK(sc);
+ if (vap->iv_state == IEEE80211_S_SCAN) {
+ /* Make link LED blink during scan. */
+ rtwn_set_led(sc, RTWN_LED_LINK, !sc->ledlink);
+ }
+ rtwn_set_chan(sc, ic->ic_curchan, NULL);
+ RTWN_UNLOCK(sc);
+}
+
+static void
+rtwn_update_mcast(struct ieee80211com *ic)
+{
+
+ /* XXX do nothing? */
+}
+
+static void
+rtwn_set_chan(struct rtwn_softc *sc, struct ieee80211_channel *c,
+ struct ieee80211_channel *extc)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ u_int chan;
+ int i;
+
+ chan = ieee80211_chan2ieee(ic, c); /* XXX center freq! */
+ if (chan == 0 || chan == IEEE80211_CHAN_ANY) {
+ device_printf(sc->sc_dev,
+ "%s: invalid channel %x\n", __func__, chan);
+ return;
+ }
+
+ /* Set Tx power for this new channel. */
+ rtwn_set_txpower(sc, c, extc);
+
+ for (i = 0; i < sc->nrxchains; i++) {
+ rtwn_rf_write(sc, i, R92C_RF_CHNLBW,
+ RW(sc->rf_chnlbw[i], R92C_RF_CHNLBW_CHNL, chan));
+ }
+#ifndef IEEE80211_NO_HT
+ if (extc != NULL) {
+ uint32_t reg;
+
+ /* Is secondary channel below or above primary? */
+ int prichlo = c->ic_freq < extc->ic_freq;
+
+ rtwn_write_1(sc, R92C_BWOPMODE,
+ rtwn_read_1(sc, R92C_BWOPMODE) & ~R92C_BWOPMODE_20MHZ);
+
+ reg = rtwn_read_1(sc, R92C_RRSR + 2);
+ reg = (reg & ~0x6f) | (prichlo ? 1 : 2) << 5;
+ rtwn_write_1(sc, R92C_RRSR + 2, reg);
+
+ rtwn_bb_write(sc, R92C_FPGA0_RFMOD,
+ rtwn_bb_read(sc, R92C_FPGA0_RFMOD) | R92C_RFMOD_40MHZ);
+ rtwn_bb_write(sc, R92C_FPGA1_RFMOD,
+ rtwn_bb_read(sc, R92C_FPGA1_RFMOD) | R92C_RFMOD_40MHZ);
+
+ /* Set CCK side band. */
+ reg = rtwn_bb_read(sc, R92C_CCK0_SYSTEM);
+ reg = (reg & ~0x00000010) | (prichlo ? 0 : 1) << 4;
+ rtwn_bb_write(sc, R92C_CCK0_SYSTEM, reg);
+
+ reg = rtwn_bb_read(sc, R92C_OFDM1_LSTF);
+ reg = (reg & ~0x00000c00) | (prichlo ? 1 : 2) << 10;
+ rtwn_bb_write(sc, R92C_OFDM1_LSTF, reg);
+
+ rtwn_bb_write(sc, R92C_FPGA0_ANAPARAM2,
+ rtwn_bb_read(sc, R92C_FPGA0_ANAPARAM2) &
+ ~R92C_FPGA0_ANAPARAM2_CBW20);
+
+ reg = rtwn_bb_read(sc, 0x818);
+ reg = (reg & ~0x0c000000) | (prichlo ? 2 : 1) << 26;
+ rtwn_bb_write(sc, 0x818, reg);
+
+ /* Select 40MHz bandwidth. */
+ rtwn_rf_write(sc, 0, R92C_RF_CHNLBW,
+ (sc->rf_chnlbw[0] & ~0xfff) | chan);
+ } else
+#endif
+ {
+ rtwn_write_1(sc, R92C_BWOPMODE,
+ rtwn_read_1(sc, R92C_BWOPMODE) | R92C_BWOPMODE_20MHZ);
+
+ rtwn_bb_write(sc, R92C_FPGA0_RFMOD,
+ rtwn_bb_read(sc, R92C_FPGA0_RFMOD) & ~R92C_RFMOD_40MHZ);
+ rtwn_bb_write(sc, R92C_FPGA1_RFMOD,
+ rtwn_bb_read(sc, R92C_FPGA1_RFMOD) & ~R92C_RFMOD_40MHZ);
+
+ rtwn_bb_write(sc, R92C_FPGA0_ANAPARAM2,
+ rtwn_bb_read(sc, R92C_FPGA0_ANAPARAM2) |
+ R92C_FPGA0_ANAPARAM2_CBW20);
+
+ /* Select 20MHz bandwidth. */
+ rtwn_rf_write(sc, 0, R92C_RF_CHNLBW,
+ (sc->rf_chnlbw[0] & ~0xfff) | R92C_RF_CHNLBW_BW20 | chan);
+ }
+}
+
+static int
+rtwn_iq_calib_chain(struct rtwn_softc *sc, int chain, uint16_t tx[2],
+ uint16_t rx[2])
+{
+ uint32_t status;
+ int offset = chain * 0x20;
+
+ if (chain == 0) { /* IQ calibration for chain 0. */
+ /* IQ calibration settings for chain 0. */
+ rtwn_bb_write(sc, 0xe30, 0x10008c1f);
+ rtwn_bb_write(sc, 0xe34, 0x10008c1f);
+ rtwn_bb_write(sc, 0xe38, 0x82140102);
+
+ if (sc->ntxchains > 1) {
+ rtwn_bb_write(sc, 0xe3c, 0x28160202); /* 2T */
+ /* IQ calibration settings for chain 1. */
+ rtwn_bb_write(sc, 0xe50, 0x10008c22);
+ rtwn_bb_write(sc, 0xe54, 0x10008c22);
+ rtwn_bb_write(sc, 0xe58, 0x82140102);
+ rtwn_bb_write(sc, 0xe5c, 0x28160202);
+ } else
+ rtwn_bb_write(sc, 0xe3c, 0x28160502); /* 1T */
+
+ /* LO calibration settings. */
+ rtwn_bb_write(sc, 0xe4c, 0x001028d1);
+ /* We're doing LO and IQ calibration in one shot. */
+ rtwn_bb_write(sc, 0xe48, 0xf9000000);
+ rtwn_bb_write(sc, 0xe48, 0xf8000000);
+
+ } else { /* IQ calibration for chain 1. */
+ /* We're doing LO and IQ calibration in one shot. */
+ rtwn_bb_write(sc, 0xe60, 0x00000002);
+ rtwn_bb_write(sc, 0xe60, 0x00000000);
+ }
+
+ /* Give LO and IQ calibrations the time to complete. */
+ DELAY(1000);
+
+ /* Read IQ calibration status. */
+ status = rtwn_bb_read(sc, 0xeac);
+
+ if (status & (1 << (28 + chain * 3)))
+ return (0); /* Tx failed. */
+ /* Read Tx IQ calibration results. */
+ tx[0] = (rtwn_bb_read(sc, 0xe94 + offset) >> 16) & 0x3ff;
+ tx[1] = (rtwn_bb_read(sc, 0xe9c + offset) >> 16) & 0x3ff;
+ if (tx[0] == 0x142 || tx[1] == 0x042)
+ return (0); /* Tx failed. */
+
+ if (status & (1 << (27 + chain * 3)))
+ return (1); /* Rx failed. */
+ /* Read Rx IQ calibration results. */
+ rx[0] = (rtwn_bb_read(sc, 0xea4 + offset) >> 16) & 0x3ff;
+ rx[1] = (rtwn_bb_read(sc, 0xeac + offset) >> 16) & 0x3ff;
+ if (rx[0] == 0x132 || rx[1] == 0x036)
+ return (1); /* Rx failed. */
+
+ return (3); /* Both Tx and Rx succeeded. */
+}
+
+static void
+rtwn_iq_calib_run(struct rtwn_softc *sc, int n, uint16_t tx[2][2],
+ uint16_t rx[2][2])
+{
+ /* Registers to save and restore during IQ calibration. */
+ struct iq_cal_regs {
+ uint32_t adda[16];
+ uint8_t txpause;
+ uint8_t bcn_ctrl;
+ uint8_t ustime_tsf;
+ uint32_t gpio_muxcfg;
+ uint32_t ofdm0_trxpathena;
+ uint32_t ofdm0_trmuxpar;
+ uint32_t fpga0_rfifacesw1;
+ } iq_cal_regs;
+ static const uint16_t reg_adda[16] = {
+ 0x85c, 0xe6c, 0xe70, 0xe74,
+ 0xe78, 0xe7c, 0xe80, 0xe84,
+ 0xe88, 0xe8c, 0xed0, 0xed4,
+ 0xed8, 0xedc, 0xee0, 0xeec
+ };
+ int i, chain;
+ uint32_t hssi_param1;
+
+ if (n == 0) {
+ for (i = 0; i < nitems(reg_adda); i++)
+ iq_cal_regs.adda[i] = rtwn_bb_read(sc, reg_adda[i]);
+
+ iq_cal_regs.txpause = rtwn_read_1(sc, R92C_TXPAUSE);
+ iq_cal_regs.bcn_ctrl = rtwn_read_1(sc, R92C_BCN_CTRL);
+ iq_cal_regs.ustime_tsf = rtwn_read_1(sc, R92C_USTIME_TSF);
+ iq_cal_regs.gpio_muxcfg = rtwn_read_4(sc, R92C_GPIO_MUXCFG);
+ }
+
+ if (sc->ntxchains == 1) {
+ rtwn_bb_write(sc, reg_adda[0], 0x0b1b25a0);
+ for (i = 1; i < nitems(reg_adda); i++)
+ rtwn_bb_write(sc, reg_adda[i], 0x0bdb25a0);
+ } else {
+ for (i = 0; i < nitems(reg_adda); i++)
+ rtwn_bb_write(sc, reg_adda[i], 0x04db25a4);
+ }
+
+ hssi_param1 = rtwn_bb_read(sc, R92C_HSSI_PARAM1(0));
+ if (!(hssi_param1 & R92C_HSSI_PARAM1_PI)) {
+ rtwn_bb_write(sc, R92C_HSSI_PARAM1(0),
+ hssi_param1 | R92C_HSSI_PARAM1_PI);
+ rtwn_bb_write(sc, R92C_HSSI_PARAM1(1),
+ hssi_param1 | R92C_HSSI_PARAM1_PI);
+ }
+
+ if (n == 0) {
+ iq_cal_regs.ofdm0_trxpathena =
+ rtwn_bb_read(sc, R92C_OFDM0_TRXPATHENA);
+ iq_cal_regs.ofdm0_trmuxpar =
+ rtwn_bb_read(sc, R92C_OFDM0_TRMUXPAR);
+ iq_cal_regs.fpga0_rfifacesw1 =
+ rtwn_bb_read(sc, R92C_FPGA0_RFIFACESW(1));
+ }
+
+ rtwn_bb_write(sc, R92C_OFDM0_TRXPATHENA, 0x03a05600);
+ rtwn_bb_write(sc, R92C_OFDM0_TRMUXPAR, 0x000800e4);
+ rtwn_bb_write(sc, R92C_FPGA0_RFIFACESW(1), 0x22204000);
+ if (sc->ntxchains > 1) {
+ rtwn_bb_write(sc, R92C_LSSI_PARAM(0), 0x00010000);
+ rtwn_bb_write(sc, R92C_LSSI_PARAM(1), 0x00010000);
+ }
+
+ rtwn_write_1(sc, R92C_TXPAUSE, 0x3f);
+ rtwn_write_1(sc, R92C_BCN_CTRL, iq_cal_regs.bcn_ctrl & ~(0x08));
+ rtwn_write_1(sc, R92C_USTIME_TSF, iq_cal_regs.ustime_tsf & ~(0x08));
+ rtwn_write_1(sc, R92C_GPIO_MUXCFG,
+ iq_cal_regs.gpio_muxcfg & ~(0x20));
+
+ rtwn_bb_write(sc, 0x0b68, 0x00080000);
+ if (sc->ntxchains > 1)
+ rtwn_bb_write(sc, 0x0b6c, 0x00080000);
+
+ rtwn_bb_write(sc, 0x0e28, 0x80800000);
+ rtwn_bb_write(sc, 0x0e40, 0x01007c00);
+ rtwn_bb_write(sc, 0x0e44, 0x01004800);
+
+ rtwn_bb_write(sc, 0x0b68, 0x00080000);
+
+ for (chain = 0; chain < sc->ntxchains; chain++) {
+ if (chain > 0) {
+ /* Put chain 0 on standby. */
+ rtwn_bb_write(sc, 0x0e28, 0x00);
+ rtwn_bb_write(sc, R92C_LSSI_PARAM(0), 0x00010000);
+ rtwn_bb_write(sc, 0x0e28, 0x80800000);
+
+ /* Enable chain 1. */
+ for (i = 0; i < nitems(reg_adda); i++)
+ rtwn_bb_write(sc, reg_adda[i], 0x0b1b25a4);
+ }
+
+ /* Run IQ calibration twice. */
+ for (i = 0; i < 2; i++) {
+ int ret;
+
+ ret = rtwn_iq_calib_chain(sc, chain,
+ tx[chain], rx[chain]);
+ if (ret == 0) {
+ DPRINTF(("%s: chain %d: Tx failed.\n",
+ __func__, chain));
+ tx[chain][0] = 0xff;
+ tx[chain][1] = 0xff;
+ rx[chain][0] = 0xff;
+ rx[chain][1] = 0xff;
+ } else if (ret == 1) {
+ DPRINTF(("%s: chain %d: Rx failed.\n",
+ __func__, chain));
+ rx[chain][0] = 0xff;
+ rx[chain][1] = 0xff;
+ } else if (ret == 3) {
+ DPRINTF(("%s: chain %d: Both Tx and Rx "
+ "succeeded.\n", __func__, chain));
+ }
+ }
+
+ DPRINTF(("%s: results for run %d chain %d: tx[0]=0x%x, "
+ "tx[1]=0x%x rx[0]=0x%x rx[1]=0x%x\n", __func__, n, chain,
+ tx[chain][0], tx[chain][1], rx[chain][0], rx[chain][1]));
+ }
+
+ rtwn_bb_write(sc, R92C_OFDM0_TRXPATHENA,
+ iq_cal_regs.ofdm0_trxpathena);
+ rtwn_bb_write(sc, R92C_FPGA0_RFIFACESW(1),
+ iq_cal_regs.fpga0_rfifacesw1);
+ rtwn_bb_write(sc, R92C_OFDM0_TRMUXPAR, iq_cal_regs.ofdm0_trmuxpar);
+
+ rtwn_bb_write(sc, 0x0e28, 0x00);
+ rtwn_bb_write(sc, R92C_LSSI_PARAM(0), 0x00032ed3);
+ if (sc->ntxchains > 1)
+ rtwn_bb_write(sc, R92C_LSSI_PARAM(1), 0x00032ed3);
+
+ if (n != 0) {
+ if (!(hssi_param1 & R92C_HSSI_PARAM1_PI)) {
+ rtwn_bb_write(sc, R92C_HSSI_PARAM1(0), hssi_param1);
+ rtwn_bb_write(sc, R92C_HSSI_PARAM1(1), hssi_param1);
+ }
+
+ for (i = 0; i < nitems(reg_adda); i++)
+ rtwn_bb_write(sc, reg_adda[i], iq_cal_regs.adda[i]);
+
+ rtwn_write_1(sc, R92C_TXPAUSE, iq_cal_regs.txpause);
+ rtwn_write_1(sc, R92C_BCN_CTRL, iq_cal_regs.bcn_ctrl);
+ rtwn_write_1(sc, R92C_USTIME_TSF, iq_cal_regs.ustime_tsf);
+ rtwn_write_4(sc, R92C_GPIO_MUXCFG, iq_cal_regs.gpio_muxcfg);
+ }
+}
+
+#define RTWN_IQ_CAL_MAX_TOLERANCE 5
+static int
+rtwn_iq_calib_compare_results(uint16_t tx1[2][2], uint16_t rx1[2][2],
+ uint16_t tx2[2][2], uint16_t rx2[2][2], int ntxchains)
+{
+ int chain, i, tx_ok[2], rx_ok[2];
+
+ tx_ok[0] = tx_ok[1] = rx_ok[0] = rx_ok[1] = 0;
+ for (chain = 0; chain < ntxchains; chain++) {
+ for (i = 0; i < 2; i++) {
+ if (tx1[chain][i] == 0xff || tx2[chain][i] == 0xff ||
+ rx1[chain][i] == 0xff || rx2[chain][i] == 0xff)
+ continue;
+
+ tx_ok[chain] = (abs(tx1[chain][i] - tx2[chain][i]) <=
+ RTWN_IQ_CAL_MAX_TOLERANCE);
+
+ rx_ok[chain] = (abs(rx1[chain][i] - rx2[chain][i]) <=
+ RTWN_IQ_CAL_MAX_TOLERANCE);
+ }
+ }
+
+ if (ntxchains > 1)
+ return (tx_ok[0] && tx_ok[1] && rx_ok[0] && rx_ok[1]);
+ else
+ return (tx_ok[0] && rx_ok[0]);
+}
+#undef RTWN_IQ_CAL_MAX_TOLERANCE
+
+static void
+rtwn_iq_calib_write_results(struct rtwn_softc *sc, uint16_t tx[2],
+ uint16_t rx[2], int chain)
+{
+ uint32_t reg, val, x;
+ long y, tx_c;
+
+ if (tx[0] == 0xff || tx[1] == 0xff)
+ return;
+
+ reg = rtwn_bb_read(sc, R92C_OFDM0_TXIQIMBALANCE(chain));
+ val = ((reg >> 22) & 0x3ff);
+ x = tx[0];
+ if (x & 0x0200)
+ x |= 0xfc00;
+ reg = (((x * val) >> 8) & 0x3ff);
+ rtwn_bb_write(sc, R92C_OFDM0_TXIQIMBALANCE(chain), reg);
+
+ reg = rtwn_bb_read(sc, R92C_OFDM0_ECCATHRESHOLD);
+ if (((x * val) >> 7) & 0x01)
+ reg |= 0x80000000;
+ else
+ reg &= ~0x80000000;
+ rtwn_bb_write(sc, R92C_OFDM0_ECCATHRESHOLD, reg);
+
+ y = tx[1];
+ if (y & 0x00000200)
+ y |= 0xfffffc00;
+ tx_c = (y * val) >> 8;
+ reg = rtwn_bb_read(sc, R92C_OFDM0_TXAFE(chain));
+ reg |= ((((tx_c & 0x3c0) >> 6) << 24) & 0xf0000000);
+ rtwn_bb_write(sc, R92C_OFDM0_TXAFE(chain), reg);
+
+ reg = rtwn_bb_read(sc, R92C_OFDM0_TXIQIMBALANCE(chain));
+ reg |= (((tx_c & 0x3f) << 16) & 0x003F0000);
+ rtwn_bb_write(sc, R92C_OFDM0_TXIQIMBALANCE(chain), reg);
+
+ reg = rtwn_bb_read(sc, R92C_OFDM0_ECCATHRESHOLD);
+ if (((y * val) >> 7) & 0x01)
+ reg |= 0x20000000;
+ else
+ reg &= ~0x20000000;
+ rtwn_bb_write(sc, R92C_OFDM0_ECCATHRESHOLD, reg);
+
+ if (rx[0] == 0xff || rx[1] == 0xff)
+ return;
+
+ reg = rtwn_bb_read(sc, R92C_OFDM0_RXIQIMBALANCE(chain));
+ reg |= (rx[0] & 0x3ff);
+ rtwn_bb_write(sc, R92C_OFDM0_RXIQIMBALANCE(chain), reg);
+ reg |= (((rx[1] & 0x03f) << 8) & 0xFC00);
+ rtwn_bb_write(sc, R92C_OFDM0_RXIQIMBALANCE(chain), reg);
+
+ if (chain == 0) {
+ reg = rtwn_bb_read(sc, R92C_OFDM0_RXIQEXTANTA);
+ reg |= (((rx[1] & 0xf) >> 6) & 0x000f);
+ rtwn_bb_write(sc, R92C_OFDM0_RXIQEXTANTA, reg);
+ } else {
+ reg = rtwn_bb_read(sc, R92C_OFDM0_AGCRSSITABLE);
+ reg |= ((((rx[1] & 0xf) >> 6) << 12) & 0xf000);
+ rtwn_bb_write(sc, R92C_OFDM0_AGCRSSITABLE, reg);
+ }
+}
+
+#define RTWN_IQ_CAL_NRUN 3
+static void
+rtwn_iq_calib(struct rtwn_softc *sc)
+{
+ uint16_t tx[RTWN_IQ_CAL_NRUN][2][2], rx[RTWN_IQ_CAL_NRUN][2][2];
+ int n, valid;
+
+ valid = 0;
+ for (n = 0; n < RTWN_IQ_CAL_NRUN; n++) {
+ rtwn_iq_calib_run(sc, n, tx[n], rx[n]);
+
+ if (n == 0)
+ continue;
+
+ /* Valid results remain stable after consecutive runs. */
+ valid = rtwn_iq_calib_compare_results(tx[n - 1], rx[n - 1],
+ tx[n], rx[n], sc->ntxchains);
+ if (valid)
+ break;
+ }
+
+ if (valid) {
+ rtwn_iq_calib_write_results(sc, tx[n][0], rx[n][0], 0);
+ if (sc->ntxchains > 1)
+ rtwn_iq_calib_write_results(sc, tx[n][1], rx[n][1], 1);
+ }
+}
+#undef RTWN_IQ_CAL_NRUN
+
+static void
+rtwn_lc_calib(struct rtwn_softc *sc)
+{
+ uint32_t rf_ac[2];
+ uint8_t txmode;
+ int i;
+
+ txmode = rtwn_read_1(sc, R92C_OFDM1_LSTF + 3);
+ if ((txmode & 0x70) != 0) {
+ /* Disable all continuous Tx. */
+ rtwn_write_1(sc, R92C_OFDM1_LSTF + 3, txmode & ~0x70);
+
+ /* Set RF mode to standby mode. */
+ for (i = 0; i < sc->nrxchains; i++) {
+ rf_ac[i] = rtwn_rf_read(sc, i, R92C_RF_AC);
+ rtwn_rf_write(sc, i, R92C_RF_AC,
+ RW(rf_ac[i], R92C_RF_AC_MODE,
+ R92C_RF_AC_MODE_STANDBY));
+ }
+ } else {
+ /* Block all Tx queues. */
+ rtwn_write_1(sc, R92C_TXPAUSE, 0xff);
+ }
+ /* Start calibration. */
+ rtwn_rf_write(sc, 0, R92C_RF_CHNLBW,
+ rtwn_rf_read(sc, 0, R92C_RF_CHNLBW) | R92C_RF_CHNLBW_LCSTART);
+
+ /* Give calibration the time to complete. */
+ DELAY(100);
+
+ /* Restore configuration. */
+ if ((txmode & 0x70) != 0) {
+ /* Restore Tx mode. */
+ rtwn_write_1(sc, R92C_OFDM1_LSTF + 3, txmode);
+ /* Restore RF mode. */
+ for (i = 0; i < sc->nrxchains; i++)
+ rtwn_rf_write(sc, i, R92C_RF_AC, rf_ac[i]);
+ } else {
+ /* Unblock all Tx queues. */
+ rtwn_write_1(sc, R92C_TXPAUSE, 0x00);
+ }
+}
+
+static void
+rtwn_temp_calib(struct rtwn_softc *sc)
+{
+ int temp;
+
+ if (sc->thcal_state == 0) {
+ /* Start measuring temperature. */
+ rtwn_rf_write(sc, 0, R92C_RF_T_METER, 0x60);
+ sc->thcal_state = 1;
+ return;
+ }
+ sc->thcal_state = 0;
+
+ /* Read measured temperature. */
+ temp = rtwn_rf_read(sc, 0, R92C_RF_T_METER) & 0x1f;
+ if (temp == 0) /* Read failed, skip. */
+ return;
+ DPRINTFN(2, ("temperature=%d\n", temp));
+
+ /*
+ * Redo IQ and LC calibration if temperature changed significantly
+ * since last calibration.
+ */
+ if (sc->thcal_lctemp == 0) {
+ /* First calibration is performed in rtwn_init(). */
+ sc->thcal_lctemp = temp;
+ } else if (abs(temp - sc->thcal_lctemp) > 1) {
+ DPRINTF(("IQ/LC calib triggered by temp: %d -> %d\n",
+ sc->thcal_lctemp, temp));
+ rtwn_iq_calib(sc);
+ rtwn_lc_calib(sc);
+ /* Record temperature of last calibration. */
+ sc->thcal_lctemp = temp;
+ }
+}
+
+static void
+rtwn_init_locked(struct rtwn_softc *sc)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
+ uint32_t reg;
+ uint8_t macaddr[IEEE80211_ADDR_LEN];
+ int i, error;
+
+ RTWN_LOCK_ASSERT(sc);
+
+ /* Init firmware commands ring. */
+ sc->fwcur = 0;
+
+ /* Power on adapter. */
+ error = rtwn_power_on(sc);
+ if (error != 0) {
+ device_printf(sc->sc_dev, "could not power on adapter\n");
+ goto fail;
+ }
+
+ /* Initialize DMA. */
+ error = rtwn_dma_init(sc);
+ if (error != 0) {
+ device_printf(sc->sc_dev, "could not initialize DMA\n");
+ goto fail;
+ }
+
+ /* Set info size in Rx descriptors (in 64-bit words). */
+ rtwn_write_1(sc, R92C_RX_DRVINFO_SZ, 4);
+
+ /* Disable interrupts. */
+ rtwn_write_4(sc, R92C_HISR, 0x00000000);
+ rtwn_write_4(sc, R92C_HIMR, 0x00000000);
+
+ /* Set MAC address. */
+ IEEE80211_ADDR_COPY(macaddr, vap ? vap->iv_myaddr : ic->ic_macaddr);
+ for (i = 0; i < IEEE80211_ADDR_LEN; i++)
+ rtwn_write_1(sc, R92C_MACID + i, macaddr[i]);
+
+ /* Set initial network type. */
+ reg = rtwn_read_4(sc, R92C_CR);
+ reg = RW(reg, R92C_CR_NETTYPE, R92C_CR_NETTYPE_INFRA);
+ rtwn_write_4(sc, R92C_CR, reg);
+
+ rtwn_rxfilter_init(sc);
+
+ reg = rtwn_read_4(sc, R92C_RRSR);
+ reg = RW(reg, R92C_RRSR_RATE_BITMAP, R92C_RRSR_RATE_ALL);
+ rtwn_write_4(sc, R92C_RRSR, reg);
+
+ /* Set short/long retry limits. */
+ rtwn_write_2(sc, R92C_RL,
+ SM(R92C_RL_SRL, 0x07) | SM(R92C_RL_LRL, 0x07));
+
+ /* Initialize EDCA parameters. */
+ rtwn_edca_init(sc);
+
+ /* Set data and response automatic rate fallback retry counts. */
+ rtwn_write_4(sc, R92C_DARFRC + 0, 0x01000000);
+ rtwn_write_4(sc, R92C_DARFRC + 4, 0x07060504);
+ rtwn_write_4(sc, R92C_RARFRC + 0, 0x01000000);
+ rtwn_write_4(sc, R92C_RARFRC + 4, 0x07060504);
+
+ rtwn_write_2(sc, R92C_FWHW_TXQ_CTRL, 0x1f80);
+
+ /* Set ACK timeout. */
+ rtwn_write_1(sc, R92C_ACKTO, 0x40);
+
+ /* Initialize beacon parameters. */
+ rtwn_write_2(sc, R92C_TBTT_PROHIBIT, 0x6404);
+ rtwn_write_1(sc, R92C_DRVERLYINT, 0x05);
+ rtwn_write_1(sc, R92C_BCNDMATIM, 0x02);
+ rtwn_write_2(sc, R92C_BCNTCFG, 0x660f);
+
+ /* Setup AMPDU aggregation. */
+ rtwn_write_4(sc, R92C_AGGLEN_LMT, 0x99997631); /* MCS7~0 */
+ rtwn_write_1(sc, R92C_AGGR_BREAK_TIME, 0x16);
+
+ rtwn_write_1(sc, R92C_BCN_MAX_ERR, 0xff);
+ rtwn_write_1(sc, R92C_BCN_CTRL, R92C_BCN_CTRL_DIS_TSF_UDT0);
+
+ rtwn_write_4(sc, R92C_PIFS, 0x1c);
+ rtwn_write_4(sc, R92C_MCUTST_1, 0x0);
+
+ /* Load 8051 microcode. */
+ error = rtwn_load_firmware(sc);
+ if (error != 0)
+ goto fail;
+
+ /* Initialize MAC/BB/RF blocks. */
+ rtwn_mac_init(sc);
+ rtwn_bb_init(sc);
+ rtwn_rf_init(sc);
+
+ /* Turn CCK and OFDM blocks on. */
+ reg = rtwn_bb_read(sc, R92C_FPGA0_RFMOD);
+ reg |= R92C_RFMOD_CCK_EN;
+ rtwn_bb_write(sc, R92C_FPGA0_RFMOD, reg);
+ reg = rtwn_bb_read(sc, R92C_FPGA0_RFMOD);
+ reg |= R92C_RFMOD_OFDM_EN;
+ rtwn_bb_write(sc, R92C_FPGA0_RFMOD, reg);
+
+ /* Clear per-station keys table. */
+ rtwn_cam_init(sc);
+
+ /* Enable hardware sequence numbering. */
+ rtwn_write_1(sc, R92C_HWSEQ_CTRL, 0xff);
+
+ /* Perform LO and IQ calibrations. */
+ rtwn_iq_calib(sc);
+ /* Perform LC calibration. */
+ rtwn_lc_calib(sc);
+
+ rtwn_pa_bias_init(sc);
+
+ /* Initialize GPIO setting. */
+ rtwn_write_1(sc, R92C_GPIO_MUXCFG,
+ rtwn_read_1(sc, R92C_GPIO_MUXCFG) & ~R92C_GPIO_MUXCFG_ENBT);
+
+ /* Fix for lower temperature. */
+ rtwn_write_1(sc, 0x15, 0xe9);
+
+ /* CLear pending interrupts. */
+ rtwn_write_4(sc, R92C_HISR, 0xffffffff);
+
+ /* Enable interrupts. */
+ rtwn_write_4(sc, R92C_HIMR, RTWN_INT_ENABLE);
+
+ sc->sc_flags |= RTWN_RUNNING;
+
+ callout_reset(&sc->watchdog_to, hz, rtwn_watchdog, sc);
+ return;
+
+fail:
+ rtwn_stop_locked(sc);
+}
+
+static void
+rtwn_init(struct rtwn_softc *sc)
+{
+
+ RTWN_LOCK(sc);
+ rtwn_init_locked(sc);
+ RTWN_UNLOCK(sc);
+
+ if (sc->sc_flags & RTWN_RUNNING)
+ ieee80211_start_all(&sc->sc_ic);
+}
+
+static void
+rtwn_stop_locked(struct rtwn_softc *sc)
+{
+ uint16_t reg;
+ int i;
+
+ RTWN_LOCK_ASSERT(sc);
+
+ sc->sc_tx_timer = 0;
+ callout_stop(&sc->watchdog_to);
+ callout_stop(&sc->calib_to);
+ sc->sc_flags &= ~RTWN_RUNNING;
+
+ /* Disable interrupts. */
+ rtwn_write_4(sc, R92C_HISR, 0x00000000);
+ rtwn_write_4(sc, R92C_HIMR, 0x00000000);
+
+ /* Stop hardware. */
+ rtwn_write_1(sc, R92C_TXPAUSE, 0xff);
+ rtwn_write_1(sc, R92C_RF_CTRL, 0x00);
+ reg = rtwn_read_1(sc, R92C_SYS_FUNC_EN);
+ reg |= R92C_SYS_FUNC_EN_BB_GLB_RST;
+ rtwn_write_1(sc, R92C_SYS_FUNC_EN, reg);
+ reg &= ~R92C_SYS_FUNC_EN_BB_GLB_RST;
+ rtwn_write_1(sc, R92C_SYS_FUNC_EN, reg);
+ reg = rtwn_read_2(sc, R92C_CR);
+ reg &= ~(R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN |
+ R92C_CR_TXDMA_EN | R92C_CR_RXDMA_EN | R92C_CR_PROTOCOL_EN |
+ R92C_CR_SCHEDULE_EN | R92C_CR_MACTXEN | R92C_CR_MACRXEN |
+ R92C_CR_ENSEC);
+ rtwn_write_2(sc, R92C_CR, reg);
+ if (rtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RAM_DL_SEL)
+ rtwn_fw_reset(sc);
+ /* TODO: linux does additional btcoex stuff here */
+ rtwn_write_2(sc, R92C_AFE_PLL_CTRL, 0x80); /* linux magic number */
+ rtwn_write_1(sc, R92C_SPS0_CTRL, 0x23); /* ditto */
+ rtwn_write_1(sc, R92C_AFE_XTAL_CTRL, 0x0e); /* different with btcoex */
+ rtwn_write_1(sc, R92C_RSV_CTRL, 0x0e);
+ rtwn_write_1(sc, R92C_APS_FSMCO, R92C_APS_FSMCO_PDN_EN);
+
+ for (i = 0; i < RTWN_NTXQUEUES; i++)
+ rtwn_reset_tx_list(sc, i);
+ rtwn_reset_rx_list(sc);
+}
+
+static void
+rtwn_stop(struct rtwn_softc *sc)
+{
+ RTWN_LOCK(sc);
+ rtwn_stop_locked(sc);
+ RTWN_UNLOCK(sc);
+}
+
+static void
+rtwn_intr(void *arg)
+{
+ struct rtwn_softc *sc = arg;
+ uint32_t status;
+ int i;
+
+ RTWN_LOCK(sc);
+ status = rtwn_read_4(sc, R92C_HISR);
+ if (status == 0 || status == 0xffffffff) {
+ RTWN_UNLOCK(sc);
+ return;
+ }
+
+ /* Disable interrupts. */
+ rtwn_write_4(sc, R92C_HIMR, 0x00000000);
+
+ /* Ack interrupts. */
+ rtwn_write_4(sc, R92C_HISR, status);
+
+ /* Vendor driver treats RX errors like ROK... */
+ if (status & (R92C_IMR_ROK | R92C_IMR_RXFOVW | R92C_IMR_RDU)) {
+ bus_dmamap_sync(sc->rx_ring.desc_dmat, sc->rx_ring.desc_map,
+ BUS_DMASYNC_POSTREAD);
+
+ for (i = 0; i < RTWN_RX_LIST_COUNT; i++) {
+ struct r92c_rx_desc *rx_desc = &sc->rx_ring.desc[i];
+ struct rtwn_rx_data *rx_data = &sc->rx_ring.rx_data[i];
+
+ if (le32toh(rx_desc->rxdw0) & R92C_RXDW0_OWN)
+ continue;
+
+ rtwn_rx_frame(sc, rx_desc, rx_data, i);
+ }
+ }
+
+ if (status & R92C_IMR_BDOK)
+ rtwn_tx_done(sc, RTWN_BEACON_QUEUE);
+ if (status & R92C_IMR_HIGHDOK)
+ rtwn_tx_done(sc, RTWN_HIGH_QUEUE);
+ if (status & R92C_IMR_MGNTDOK)
+ rtwn_tx_done(sc, RTWN_MGNT_QUEUE);
+ if (status & R92C_IMR_BKDOK)
+ rtwn_tx_done(sc, RTWN_BK_QUEUE);
+ if (status & R92C_IMR_BEDOK)
+ rtwn_tx_done(sc, RTWN_BE_QUEUE);
+ if (status & R92C_IMR_VIDOK)
+ rtwn_tx_done(sc, RTWN_VI_QUEUE);
+ if (status & R92C_IMR_VODOK)
+ rtwn_tx_done(sc, RTWN_VO_QUEUE);
+
+ /* Enable interrupts. */
+ rtwn_write_4(sc, R92C_HIMR, RTWN_INT_ENABLE);
+
+ RTWN_UNLOCK(sc);
+}
+
+static void
+rtwn_hw_reset(void *arg0, int pending)
+{
+ struct rtwn_softc *sc = arg0;
+ struct ieee80211com *ic = &sc->sc_ic;
+
+ rtwn_stop(sc);
+ rtwn_init(sc);
+ ieee80211_notify_radio(ic, 1);
+}
diff --git a/sys/dev/rtwn/if_rtwnreg.h b/sys/dev/rtwn/if_rtwnreg.h
new file mode 100644
index 0000000..a5f1cc2
--- /dev/null
+++ b/sys/dev/rtwn/if_rtwnreg.h
@@ -0,0 +1,2106 @@
+/* $OpenBSD: if_rtwnreg.h,v 1.3 2015/06/14 08:02:47 stsp Exp $ */
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2015 Stefan Sperling <stsp@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
+ */
+
+#define R92C_MAX_CHAINS 2
+
+/* Maximum number of output pipes is 3. */
+#define R92C_MAX_EPOUT 3
+
+#define R92C_MAX_TX_PWR 0x3f
+
+#define R92C_PUBQ_NPAGES 176
+#define R92C_HPQ_NPAGES 41
+#define R92C_LPQ_NPAGES 28
+#define R92C_TXPKTBUF_COUNT 256
+#define R92C_TX_PAGE_COUNT \
+ (R92C_PUBQ_NPAGES + R92C_HPQ_NPAGES + R92C_LPQ_NPAGES)
+#define R92C_TX_PAGE_BOUNDARY (R92C_TX_PAGE_COUNT + 1)
+
+#define R92C_H2C_NBOX 4
+
+/* USB Requests. */
+#define R92C_REQ_REGS 0x05
+
+/*
+ * MAC registers.
+ */
+/* System Configuration. */
+#define R92C_SYS_ISO_CTRL 0x000
+#define R92C_SYS_FUNC_EN 0x002
+#define R92C_APS_FSMCO 0x004
+#define R92C_SYS_CLKR 0x008
+#define R92C_AFE_MISC 0x010
+#define R92C_SPS0_CTRL 0x011
+#define R92C_SPS_OCP_CFG 0x018
+#define R92C_RSV_CTRL 0x01c
+#define R92C_RF_CTRL 0x01f
+#define R92C_LDOA15_CTRL 0x020
+#define R92C_LDOV12D_CTRL 0x021
+#define R92C_LDOHCI12_CTRL 0x022
+#define R92C_LPLDO_CTRL 0x023
+#define R92C_AFE_XTAL_CTRL 0x024
+#define R92C_AFE_PLL_CTRL 0x028
+#define R92C_EFUSE_CTRL 0x030
+#define R92C_EFUSE_TEST 0x034
+#define R92C_PWR_DATA 0x038
+#define R92C_CAL_TIMER 0x03c
+#define R92C_ACLK_MON 0x03e
+#define R92C_GPIO_MUXCFG 0x040
+#define R92C_GPIO_IO_SEL 0x042
+#define R92C_MAC_PINMUX_CFG 0x043
+#define R92C_GPIO_PIN_CTRL 0x044
+#define R92C_GPIO_INTM 0x048
+#define R92C_LEDCFG0 0x04c
+#define R92C_LEDCFG1 0x04d
+#define R92C_LEDCFG2 0x04e
+#define R92C_LEDCFG3 0x04f
+#define R92C_FSIMR 0x050
+#define R92C_FSISR 0x054
+#define R92C_HSIMR 0x058
+#define R92C_HSISR 0x05c
+#define R92C_MCUFWDL 0x080
+#define R92C_HMEBOX_EXT(idx) (0x088 + (idx) * 2)
+#define R92C_BIST_SCAN 0x0d0
+#define R92C_BIST_RPT 0x0d4
+#define R92C_BIST_ROM_RPT 0x0d8
+#define R92C_USB_SIE_INTF 0x0e0
+#define R92C_PCIE_MIO_INTF 0x0e4
+#define R92C_PCIE_MIO_INTD 0x0e8
+#define R92C_HPON_FSM 0x0ec
+#define R92C_SYS_CFG 0x0f0
+/* MAC General Configuration. */
+#define R92C_CR 0x100
+#define R92C_PBP 0x104
+#define R92C_TRXDMA_CTRL 0x10c
+#define R92C_TRXFF_BNDY 0x114
+#define R92C_TRXFF_STATUS 0x118
+#define R92C_RXFF_PTR 0x11c
+#define R92C_HIMR 0x120
+#define R92C_HISR 0x124
+#define R92C_HIMRE 0x128
+#define R92C_HISRE 0x12c
+#define R92C_CPWM 0x12f
+#define R92C_FWIMR 0x130
+#define R92C_FWISR 0x134
+#define R92C_PKTBUF_DBG_CTRL 0x140
+#define R92C_PKTBUF_DBG_DATA_L 0x144
+#define R92C_PKTBUF_DBG_DATA_H 0x148
+#define R92C_TC0_CTRL(i) (0x150 + (i) * 4)
+#define R92C_TCUNIT_BASE 0x164
+#define R92C_MBIST_START 0x174
+#define R92C_MBIST_DONE 0x178
+#define R92C_MBIST_FAIL 0x17c
+#define R92C_C2HEVT_MSG_NORMAL 0x1a0
+#define R92C_C2HEVT_MSG_TEST 0x1b8
+#define R92C_C2HEVT_CLEAR 0x1bf
+#define R92C_MCUTST_1 0x1c0
+#define R92C_FMETHR 0x1c8
+#define R92C_HMETFR 0x1cc
+#define R92C_HMEBOX(idx) (0x1d0 + (idx) * 4)
+#define R92C_LLT_INIT 0x1e0
+#define R92C_BB_ACCESS_CTRL 0x1e8
+#define R92C_BB_ACCESS_DATA 0x1ec
+/* Tx DMA Configuration. */
+#define R92C_RQPN 0x200
+#define R92C_FIFOPAGE 0x204
+#define R92C_TDECTRL 0x208
+#define R92C_TXDMA_OFFSET_CHK 0x20c
+#define R92C_TXDMA_STATUS 0x210
+#define R92C_RQPN_NPQ 0x214
+/* Rx DMA Configuration. */
+#define R92C_RXDMA_AGG_PG_TH 0x280
+#define R92C_RXPKT_NUM 0x284
+#define R92C_RXDMA_STATUS 0x288
+
+#define R92C_PCIE_CTRL_REG 0x300
+#define R92C_INT_MIG 0x304
+#define R92C_BCNQ_DESA 0x308
+#define R92C_HQ_DESA 0x310
+#define R92C_MGQ_DESA 0x318
+#define R92C_VOQ_DESA 0x320
+#define R92C_VIQ_DESA 0x328
+#define R92C_BEQ_DESA 0x330
+#define R92C_BKQ_DESA 0x338
+#define R92C_RX_DESA 0x340
+#define R92C_DBI 0x348
+#define R92C_MDIO 0x354
+#define R92C_DBG_SEL 0x360
+#define R92C_PCIE_HRPWM 0x361
+#define R92C_PCIE_HCPWM 0x363
+#define R92C_UART_CTRL 0x364
+#define R92C_UART_TX_DES 0x370
+#define R92C_UART_RX_DES 0x378
+
+#define R92C_VOQ_INFORMATION 0x0400
+#define R92C_VIQ_INFORMATION 0x0404
+#define R92C_BEQ_INFORMATION 0x0408
+#define R92C_BKQ_INFORMATION 0x040C
+#define R92C_MGQ_INFORMATION 0x0410
+#define R92C_HGQ_INFORMATION 0x0414
+#define R92C_BCNQ_INFORMATION 0x0418
+#define R92C_CPU_MGQ_INFORMATION 0x041C
+
+/* Protocol Configuration. */
+#define R92C_FWHW_TXQ_CTRL 0x420
+#define R92C_HWSEQ_CTRL 0x423
+#define R92C_TXPKTBUF_BCNQ_BDNY 0x424
+#define R92C_TXPKTBUF_MGQ_BDNY 0x425
+#define R92C_SPEC_SIFS 0x428
+#define R92C_RL 0x42a
+#define R92C_DARFRC 0x430
+#define R92C_RARFRC 0x438
+#define R92C_RRSR 0x440
+#define R92C_ARFR(i) (0x444 + (i) * 4)
+#define R92C_AGGLEN_LMT 0x458
+#define R92C_AMPDU_MIN_SPACE 0x45c
+#define R92C_TXPKTBUF_WMAC_LBK_BF_HD 0x45d
+#define R92C_FAST_EDCA_CTRL 0x460
+#define R92C_RD_RESP_PKT_TH 0x463
+#define R92C_INIRTS_RATE_SEL 0x480
+#define R92C_INIDATA_RATE_SEL(macid) (0x484 + (macid))
+/* EDCA Configuration. */
+#define R92C_EDCA_VO_PARAM 0x500
+#define R92C_EDCA_VI_PARAM 0x504
+#define R92C_EDCA_BE_PARAM 0x508
+#define R92C_EDCA_BK_PARAM 0x50c
+#define R92C_BCNTCFG 0x510
+#define R92C_PIFS 0x512
+#define R92C_RDG_PIFS 0x513
+#define R92C_SIFS_CCK 0x514
+#define R92C_SIFS_OFDM 0x516
+#define R92C_AGGR_BREAK_TIME 0x51a
+#define R92C_SLOT 0x51b
+#define R92C_TX_PTCL_CTRL 0x520
+#define R92C_TXPAUSE 0x522
+#define R92C_DIS_TXREQ_CLR 0x523
+#define R92C_RD_CTRL 0x524
+#define R92C_TBTT_PROHIBIT 0x540
+#define R92C_RD_NAV_NXT 0x544
+#define R92C_NAV_PROT_LEN 0x546
+#define R92C_BCN_CTRL 0x550
+#define R92C_USTIME_TSF 0x551
+#define R92C_MBID_NUM 0x552
+#define R92C_DUAL_TSF_RST 0x553
+#define R92C_BCN_INTERVAL 0x554
+#define R92C_DRVERLYINT 0x558
+#define R92C_BCNDMATIM 0x559
+#define R92C_ATIMWND 0x55a
+#define R92C_BCN_MAX_ERR 0x55d
+#define R92C_RXTSF_OFFSET_CCK 0x55e
+#define R92C_RXTSF_OFFSET_OFDM 0x55f
+#define R92C_TSFTR 0x560
+#define R92C_INIT_TSFTR 0x564
+#define R92C_PSTIMER 0x580
+#define R92C_TIMER0 0x584
+#define R92C_TIMER1 0x588
+#define R92C_ACMHWCTRL 0x5c0
+#define R92C_ACMRSTCTRL 0x5c1
+#define R92C_ACMAVG 0x5c2
+#define R92C_VO_ADMTIME 0x5c4
+#define R92C_VI_ADMTIME 0x5c6
+#define R92C_BE_ADMTIME 0x5c8
+#define R92C_EDCA_RANDOM_GEN 0x5cc
+#define R92C_SCH_TXCMD 0x5d0
+/* WMAC Configuration. */
+#define R92C_APSD_CTRL 0x600
+#define R92C_BWOPMODE 0x603
+#define R92C_TCR 0x604
+#define R92C_RCR 0x608
+#define R92C_RX_DRVINFO_SZ 0x60f
+#define R92C_MACID 0x610
+#define R92C_BSSID 0x618
+#define R92C_MAR 0x620
+#define R92C_MAC_SPEC_SIFS 0x63a
+#define R92C_R2T_SIFS 0x63c
+#define R92C_T2T_SIFS 0x63e
+#define R92C_ACKTO 0x640
+#define R92C_CAMCMD 0x670
+#define R92C_CAMWRITE 0x674
+#define R92C_CAMREAD 0x678
+#define R92C_CAMDBG 0x67c
+#define R92C_SECCFG 0x680
+#define R92C_RXFLTMAP0 0x6a0
+#define R92C_RXFLTMAP1 0x6a2
+#define R92C_RXFLTMAP2 0x6a4
+
+/* Bits for R92C_SYS_ISO_CTRL. */
+#define R92C_SYS_ISO_CTRL_MD2PP 0x0001
+#define R92C_SYS_ISO_CTRL_UA2USB 0x0002
+#define R92C_SYS_ISO_CTRL_UD2CORE 0x0004
+#define R92C_SYS_ISO_CTRL_PA2PCIE 0x0008
+#define R92C_SYS_ISO_CTRL_PD2CORE 0x0010
+#define R92C_SYS_ISO_CTRL_IP2MAC 0x0020
+#define R92C_SYS_ISO_CTRL_DIOP 0x0040
+#define R92C_SYS_ISO_CTRL_DIOE 0x0080
+#define R92C_SYS_ISO_CTRL_EB2CORE 0x0100
+#define R92C_SYS_ISO_CTRL_DIOR 0x0200
+#define R92C_SYS_ISO_CTRL_PWC_EV25V 0x4000
+#define R92C_SYS_ISO_CTRL_PWC_EV12V 0x8000
+
+/* Bits for R92C_SYS_FUNC_EN. */
+#define R92C_SYS_FUNC_EN_BBRSTB 0x0001
+#define R92C_SYS_FUNC_EN_BB_GLB_RST 0x0002
+#define R92C_SYS_FUNC_EN_USBA 0x0004
+#define R92C_SYS_FUNC_EN_UPLL 0x0008
+#define R92C_SYS_FUNC_EN_USBD 0x0010
+#define R92C_SYS_FUNC_EN_DIO_PCIE 0x0020
+#define R92C_SYS_FUNC_EN_PCIEA 0x0040
+#define R92C_SYS_FUNC_EN_PPLL 0x0080
+#define R92C_SYS_FUNC_EN_PCIED 0x0100
+#define R92C_SYS_FUNC_EN_DIOE 0x0200
+#define R92C_SYS_FUNC_EN_CPUEN 0x0400
+#define R92C_SYS_FUNC_EN_DCORE 0x0800
+#define R92C_SYS_FUNC_EN_ELDR 0x1000
+#define R92C_SYS_FUNC_EN_DIO_RF 0x2000
+#define R92C_SYS_FUNC_EN_HWPDN 0x4000
+#define R92C_SYS_FUNC_EN_MREGEN 0x8000
+
+/* Bits for R92C_APS_FSMCO. */
+#define R92C_APS_FSMCO_PFM_LDALL 0x00000001
+#define R92C_APS_FSMCO_PFM_ALDN 0x00000002
+#define R92C_APS_FSMCO_PFM_LDKP 0x00000004
+#define R92C_APS_FSMCO_PFM_WOWL 0x00000008
+#define R92C_APS_FSMCO_PDN_EN 0x00000010
+#define R92C_APS_FSMCO_PDN_PL 0x00000020
+#define R92C_APS_FSMCO_APFM_ONMAC 0x00000100
+#define R92C_APS_FSMCO_APFM_OFF 0x00000200
+#define R92C_APS_FSMCO_APFM_RSM 0x00000400
+#define R92C_APS_FSMCO_AFSM_HSUS 0x00000800
+#define R92C_APS_FSMCO_AFSM_PCIE 0x00001000
+#define R92C_APS_FSMCO_APDM_MAC 0x00002000
+#define R92C_APS_FSMCO_APDM_HOST 0x00004000
+#define R92C_APS_FSMCO_APDM_HPDN 0x00008000
+#define R92C_APS_FSMCO_RDY_MACON 0x00010000
+#define R92C_APS_FSMCO_SUS_HOST 0x00020000
+#define R92C_APS_FSMCO_ROP_ALD 0x00100000
+#define R92C_APS_FSMCO_ROP_PWR 0x00200000
+#define R92C_APS_FSMCO_ROP_SPS 0x00400000
+#define R92C_APS_FSMCO_SOP_MRST 0x02000000
+#define R92C_APS_FSMCO_SOP_FUSE 0x04000000
+#define R92C_APS_FSMCO_SOP_ABG 0x08000000
+#define R92C_APS_FSMCO_SOP_AMB 0x10000000
+#define R92C_APS_FSMCO_SOP_RCK 0x20000000
+#define R92C_APS_FSMCO_SOP_A8M 0x40000000
+#define R92C_APS_FSMCO_XOP_BTCK 0x80000000
+
+/* Bits for R92C_SYS_CLKR. */
+#define R92C_SYS_CLKR_ANAD16V_EN 0x00000001
+#define R92C_SYS_CLKR_ANA8M 0x00000002
+#define R92C_SYS_CLKR_MACSLP 0x00000010
+#define R92C_SYS_CLKR_LOADER_EN 0x00000020
+#define R92C_SYS_CLKR_80M_SSC_DIS 0x00000080
+#define R92C_SYS_CLKR_80M_SSC_EN_HO 0x00000100
+#define R92C_SYS_CLKR_PHY_SSC_RSTB 0x00000200
+#define R92C_SYS_CLKR_SEC_EN 0x00000400
+#define R92C_SYS_CLKR_MAC_EN 0x00000800
+#define R92C_SYS_CLKR_SYS_EN 0x00001000
+#define R92C_SYS_CLKR_RING_EN 0x00002000
+
+/* Bits for R92C_RF_CTRL. */
+#define R92C_RF_CTRL_EN 0x01
+#define R92C_RF_CTRL_RSTB 0x02
+#define R92C_RF_CTRL_SDMRSTB 0x04
+
+/* Bits for R92C_LDOV12D_CTRL. */
+#define R92C_LDOV12D_CTRL_LDV12_EN 0x01
+
+/* Bits for R92C_EFUSE_CTRL. */
+#define R92C_EFUSE_CTRL_DATA_M 0x000000ff
+#define R92C_EFUSE_CTRL_DATA_S 0
+#define R92C_EFUSE_CTRL_ADDR_M 0x0003ff00
+#define R92C_EFUSE_CTRL_ADDR_S 8
+#define R92C_EFUSE_CTRL_VALID 0x80000000
+
+/* Bits for R92C_GPIO_MUXCFG. */
+#define R92C_GPIO_MUXCFG_RFKILL 0x0008
+#define R92C_GPIO_MUXCFG_ENBT 0x0020
+
+/* Bits for R92C_GPIO_IO_SEL. */
+#define R92C_GPIO_IO_SEL_RFKILL 0x0008
+
+/* Bits for R92C_LEDCFG0. */
+#define R92C_LEDCFG0_DIS 0x08
+
+/* Bits for R92C_LEDCFG2. */
+#define R92C_LEDCFG2_EN 0x60
+#define R92C_LEDCFG2_DIS 0x68
+
+/* Bits for R92C_MCUFWDL. */
+#define R92C_MCUFWDL_EN 0x00000001
+#define R92C_MCUFWDL_RDY 0x00000002
+#define R92C_MCUFWDL_CHKSUM_RPT 0x00000004
+#define R92C_MCUFWDL_MACINI_RDY 0x00000008
+#define R92C_MCUFWDL_BBINI_RDY 0x00000010
+#define R92C_MCUFWDL_RFINI_RDY 0x00000020
+#define R92C_MCUFWDL_WINTINI_RDY 0x00000040
+#define R92C_MCUFWDL_RAM_DL_SEL 0x00000080 /* 1: RAM, 0: ROM */
+#define R92C_MCUFWDL_PAGE_M 0x00070000
+#define R92C_MCUFWDL_PAGE_S 16
+#define R92C_MCUFWDL_CPRST 0x00800000
+
+/* Bits for R92C_HPON_FSM. */
+#define R92C_HPON_FSM_CHIP_BONDING_ID_S 22
+#define R92C_HPON_FSM_CHIP_BONDING_ID_M 0x00c00000
+#define R92C_HPON_FSM_CHIP_BONDING_ID_92C_1T2R 1
+
+/* Bits for R92C_SYS_CFG. */
+#define R92C_SYS_CFG_XCLK_VLD 0x00000001
+#define R92C_SYS_CFG_ACLK_VLD 0x00000002
+#define R92C_SYS_CFG_UCLK_VLD 0x00000004
+#define R92C_SYS_CFG_PCLK_VLD 0x00000008
+#define R92C_SYS_CFG_PCIRSTB 0x00000010
+#define R92C_SYS_CFG_V15_VLD 0x00000020
+#define R92C_SYS_CFG_TRP_B15V_EN 0x00000080
+#define R92C_SYS_CFG_SIC_IDLE 0x00000100
+#define R92C_SYS_CFG_BD_MAC2 0x00000200
+#define R92C_SYS_CFG_BD_MAC1 0x00000400
+#define R92C_SYS_CFG_IC_MACPHY_MODE 0x00000800
+#define R92C_SYS_CFG_CHIP_VER_RTL_M 0x0000f000
+#define R92C_SYS_CFG_CHIP_VER_RTL_S 12
+#define R92C_SYS_CFG_BT_FUNC 0x00010000
+#define R92C_SYS_CFG_VENDOR_UMC 0x00080000
+#define R92C_SYS_CFG_PAD_HWPD_IDN 0x00400000
+#define R92C_SYS_CFG_TRP_VAUX_EN 0x00800000
+#define R92C_SYS_CFG_TRP_BT_EN 0x01000000
+#define R92C_SYS_CFG_BD_PKG_SEL 0x02000000
+#define R92C_SYS_CFG_BD_HCI_SEL 0x04000000
+#define R92C_SYS_CFG_TYPE_92C 0x08000000
+
+/* Bits for R92C_CR. */
+#define R92C_CR_HCI_TXDMA_EN 0x00000001
+#define R92C_CR_HCI_RXDMA_EN 0x00000002
+#define R92C_CR_TXDMA_EN 0x00000004
+#define R92C_CR_RXDMA_EN 0x00000008
+#define R92C_CR_PROTOCOL_EN 0x00000010
+#define R92C_CR_SCHEDULE_EN 0x00000020
+#define R92C_CR_MACTXEN 0x00000040
+#define R92C_CR_MACRXEN 0x00000080
+#define R92C_CR_ENSEC 0x00000200
+#define R92C_CR_NETTYPE_S 16
+#define R92C_CR_NETTYPE_M 0x00030000
+#define R92C_CR_NETTYPE_NOLINK 0
+#define R92C_CR_NETTYPE_ADHOC 1
+#define R92C_CR_NETTYPE_INFRA 2
+#define R92C_CR_NETTYPE_AP 3
+
+/* Bits for R92C_PBP. */
+#define R92C_PBP_PSRX_M 0x0f
+#define R92C_PBP_PSRX_S 0
+#define R92C_PBP_PSTX_M 0xf0
+#define R92C_PBP_PSTX_S 4
+#define R92C_PBP_64 0
+#define R92C_PBP_128 1
+#define R92C_PBP_256 2
+#define R92C_PBP_512 3
+#define R92C_PBP_1024 4
+
+/* Bits for R92C_TRXDMA_CTRL. */
+#define R92C_TRXDMA_CTRL_RXDMA_AGG_EN 0x0004
+#define R92C_TRXDMA_CTRL_TXDMA_VOQ_MAP_M 0x0030
+#define R92C_TRXDMA_CTRL_TXDMA_VOQ_MAP_S 4
+#define R92C_TRXDMA_CTRL_TXDMA_VIQ_MAP_M 0x00c0
+#define R92C_TRXDMA_CTRL_TXDMA_VIQ_MAP_S 6
+#define R92C_TRXDMA_CTRL_TXDMA_BEQ_MAP_M 0x0300
+#define R92C_TRXDMA_CTRL_TXDMA_BEQ_MAP_S 8
+#define R92C_TRXDMA_CTRL_TXDMA_BKQ_MAP_M 0x0c00
+#define R92C_TRXDMA_CTRL_TXDMA_BKQ_MAP_S 10
+#define R92C_TRXDMA_CTRL_TXDMA_MGQ_MAP_M 0x3000
+#define R92C_TRXDMA_CTRL_TXDMA_MGQ_MAP_S 12
+#define R92C_TRXDMA_CTRL_TXDMA_HIQ_MAP_M 0xc000
+#define R92C_TRXDMA_CTRL_TXDMA_HIQ_MAP_S 14
+#define R92C_TRXDMA_CTRL_QUEUE_LOW 1
+#define R92C_TRXDMA_CTRL_QUEUE_NORMAL 2
+#define R92C_TRXDMA_CTRL_QUEUE_HIGH 3
+#define R92C_TRXDMA_CTRL_QMAP_M 0xfff0
+#define R92C_TRXDMA_CTRL_QMAP_S 4
+/* Shortcuts. */
+#define R92C_TRXDMA_CTRL_QMAP_3EP 0xf5b0
+#define R92C_TRXDMA_CTRL_QMAP_HQ_LQ 0xf5f0
+#define R92C_TRXDMA_CTRL_QMAP_HQ_NQ 0xfaf0
+#define R92C_TRXDMA_CTRL_QMAP_LQ 0x5550
+#define R92C_TRXDMA_CTRL_QMAP_NQ 0xaaa0
+#define R92C_TRXDMA_CTRL_QMAP_HQ 0xfff0
+
+/* Bits for R92C_LLT_INIT. */
+#define R92C_LLT_INIT_DATA_M 0x000000ff
+#define R92C_LLT_INIT_DATA_S 0
+#define R92C_LLT_INIT_ADDR_M 0x0000ff00
+#define R92C_LLT_INIT_ADDR_S 8
+#define R92C_LLT_INIT_OP_M 0xc0000000
+#define R92C_LLT_INIT_OP_S 30
+#define R92C_LLT_INIT_OP_NO_ACTIVE 0
+#define R92C_LLT_INIT_OP_WRITE 1
+
+/* Bits for R92C_RQPN. */
+#define R92C_RQPN_HPQ_M 0x000000ff
+#define R92C_RQPN_HPQ_S 0
+#define R92C_RQPN_LPQ_M 0x0000ff00
+#define R92C_RQPN_LPQ_S 8
+#define R92C_RQPN_PUBQ_M 0x00ff0000
+#define R92C_RQPN_PUBQ_S 16
+#define R92C_RQPN_LD 0x80000000
+
+/* Bits for R92C_TDECTRL. */
+#define R92C_TDECTRL_BLK_DESC_NUM_M 0x0000000f
+#define R92C_TDECTRL_BLK_DESC_NUM_S 4
+
+/* Bits for R92C_FWHW_TXQ_CTRL. */
+#define R92C_FWHW_TXQ_CTRL_AMPDU_RTY_NEW 0x80
+
+/* Bits for R92C_SPEC_SIFS. */
+#define R92C_SPEC_SIFS_CCK_M 0x00ff
+#define R92C_SPEC_SIFS_CCK_S 0
+#define R92C_SPEC_SIFS_OFDM_M 0xff00
+#define R92C_SPEC_SIFS_OFDM_S 8
+
+/* Bits for R92C_RL. */
+#define R92C_RL_LRL_M 0x003f
+#define R92C_RL_LRL_S 0
+#define R92C_RL_SRL_M 0x3f00
+#define R92C_RL_SRL_S 8
+
+/* Bits for R92C_RRSR. */
+#define R92C_RRSR_RATE_BITMAP_M 0x000fffff
+#define R92C_RRSR_RATE_BITMAP_S 0
+#define R92C_RRSR_RATE_CCK_ONLY_1M 0xffff1
+#define R92C_RRSR_RATE_ALL 0xfffff
+#define R92C_RRSR_RSC_LOWSUBCHNL 0x00200000
+#define R92C_RRSR_RSC_UPSUBCHNL 0x00400000
+#define R92C_RRSR_SHORT 0x00800000
+
+/* Bits for R92C_EDCA_XX_PARAM. */
+#define R92C_EDCA_PARAM_AIFS_M 0x000000ff
+#define R92C_EDCA_PARAM_AIFS_S 0
+#define R92C_EDCA_PARAM_ECWMIN_M 0x00000f00
+#define R92C_EDCA_PARAM_ECWMIN_S 8
+#define R92C_EDCA_PARAM_ECWMAX_M 0x0000f000
+#define R92C_EDCA_PARAM_ECWMAX_S 12
+#define R92C_EDCA_PARAM_TXOP_M 0xffff0000
+#define R92C_EDCA_PARAM_TXOP_S 16
+
+/* Bits for R92C_TXPAUSE. */
+#define R92C_TXPAUSE_AC_VO 0x01
+#define R92C_TXPAUSE_AC_VI 0x02
+#define R92C_TXPAUSE_AC_BE 0x04
+#define R92C_TXPAUSE_AC_BK 0x08
+
+/* Bits for R92C_BCN_CTRL. */
+#define R92C_BCN_CTRL_EN_MBSSID 0x02
+#define R92C_BCN_CTRL_TXBCN_RPT 0x04
+#define R92C_BCN_CTRL_EN_BCN 0x08
+#define R92C_BCN_CTRL_DIS_TSF_UDT0 0x10
+
+/* Bits for R92C_APSD_CTRL. */
+#define R92C_APSD_CTRL_OFF 0x40
+#define R92C_APSD_CTRL_OFF_STATUS 0x80
+
+/* Bits for R92C_BWOPMODE. */
+#define R92C_BWOPMODE_11J 0x01
+#define R92C_BWOPMODE_5G 0x02
+#define R92C_BWOPMODE_20MHZ 0x04
+
+/* Bits for R92C_TCR. */
+#define R92C_TCR_TSFRST 0x00000001
+#define R92C_TCR_DIS_GCLK 0x00000002
+#define R92C_TCR_PAD_SEL 0x00000004
+#define R92C_TCR_PWR_ST 0x00000040
+#define R92C_TCR_PWRBIT_OW_EN 0x00000080
+#define R92C_TCR_ACRC 0x00000100
+#define R92C_TCR_CFENDFORM 0x00000200
+#define R92C_TCR_ICV 0x00000400
+
+/* Bits for R92C_RCR. */
+#define R92C_RCR_AAP 0x00000001
+#define R92C_RCR_APM 0x00000002
+#define R92C_RCR_AM 0x00000004
+#define R92C_RCR_AB 0x00000008
+#define R92C_RCR_ADD3 0x00000010
+#define R92C_RCR_APWRMGT 0x00000020
+#define R92C_RCR_CBSSID_DATA 0x00000040
+#define R92C_RCR_CBSSID_BCN 0x00000080
+#define R92C_RCR_ACRC32 0x00000100
+#define R92C_RCR_AICV 0x00000200
+#define R92C_RCR_ADF 0x00000800
+#define R92C_RCR_ACF 0x00001000
+#define R92C_RCR_AMF 0x00002000
+#define R92C_RCR_HTC_LOC_CTRL 0x00004000
+#define R92C_RCR_MFBEN 0x00400000
+#define R92C_RCR_LSIGEN 0x00800000
+#define R92C_RCR_ENMBID 0x01000000
+#define R92C_RCR_APP_BA_SSN 0x08000000
+#define R92C_RCR_APP_PHYSTS 0x10000000
+#define R92C_RCR_APP_ICV 0x20000000
+#define R92C_RCR_APP_MIC 0x40000000
+#define R92C_RCR_APPFCS 0x80000000
+
+/* Bits for R92C_CAMCMD. */
+#define R92C_CAMCMD_ADDR_M 0x0000ffff
+#define R92C_CAMCMD_ADDR_S 0
+#define R92C_CAMCMD_WRITE 0x00010000
+#define R92C_CAMCMD_CLR 0x40000000
+#define R92C_CAMCMD_POLLING 0x80000000
+
+/* IMR */
+
+/*Beacon DMA interrupt 6 */
+#define R92C_IMR_BCNDMAINT6 0x80000000
+/*Beacon DMA interrupt 5 */
+#define R92C_IMR_BCNDMAINT5 0x40000000
+/*Beacon DMA interrupt 4 */
+#define R92C_IMR_BCNDMAINT4 0x20000000
+/*Beacon DMA interrupt 3 */
+#define R92C_IMR_BCNDMAINT3 0x10000000
+/*Beacon DMA interrupt 2 */
+#define R92C_IMR_BCNDMAINT2 0x08000000
+/*Beacon DMA interrupt 1 */
+#define R92C_IMR_BCNDMAINT1 0x04000000
+/*Beacon Queue DMA OK interrupt 8 */
+#define R92C_IMR_BCNDOK8 0x02000000
+/*Beacon Queue DMA OK interrupt 7 */
+#define R92C_IMR_BCNDOK7 0x01000000
+/*Beacon Queue DMA OK interrupt 6 */
+#define R92C_IMR_BCNDOK6 0x00800000
+/*Beacon Queue DMA OK interrupt 5 */
+#define R92C_IMR_BCNDOK5 0x00400000
+/*Beacon Queue DMA OK interrupt 4 */
+#define R92C_IMR_BCNDOK4 0x00200000
+/*Beacon Queue DMA OK interrupt 3 */
+#define R92C_IMR_BCNDOK3 0x00100000
+/*Beacon Queue DMA OK interrupt 2 */
+#define R92C_IMR_BCNDOK2 0x00080000
+/*Beacon Queue DMA OK interrupt 1 */
+#define R92C_IMR_BCNDOK1 0x00040000
+/*Timeout interrupt 2 */
+#define R92C_IMR_TIMEOUT2 0x00020000
+/*Timeout interrupt 1 */
+#define R92C_IMR_TIMEOUT1 0x00010000
+/*Transmit FIFO Overflow */
+#define R92C_IMR_TXFOVW 0x00008000
+/*Power save time out interrupt */
+#define R92C_IMR_PSTIMEOUT 0x00004000
+/*Beacon DMA interrupt 0 */
+#define R92C_IMR_BCNINT 0x00002000
+/*Receive FIFO Overflow */
+#define R92C_IMR_RXFOVW 0x00001000
+/*Receive Descriptor Unavailable */
+#define R92C_IMR_RDU 0x00000800
+/*For 92C,ATIM Window End interrupt */
+#define R92C_IMR_ATIMEND 0x00000400
+/*Beacon Queue DMA OK interrupt */
+#define R92C_IMR_BDOK 0x00000200
+/*High Queue DMA OK interrupt */
+#define R92C_IMR_HIGHDOK 0x00000100
+/*Transmit Beacon OK interrupt */
+#define R92C_IMR_TBDOK 0x00000080
+/*Management Queue DMA OK interrupt */
+#define R92C_IMR_MGNTDOK 0x00000040
+/*For 92C,Transmit Beacon Error interrupt */
+#define R92C_IMR_TBDER 0x00000020
+/*AC_BK DMA OK interrupt */
+#define R92C_IMR_BKDOK 0x00000010
+/*AC_BE DMA OK interrupt */
+#define R92C_IMR_BEDOK 0x00000008
+/*AC_VI DMA OK interrupt */
+#define R92C_IMR_VIDOK 0x00000004
+/*AC_VO DMA interrupt */
+#define R92C_IMR_VODOK 0x00000002
+/*Receive DMA OK interrupt */
+#define R92C_IMR_ROK 0x00000001
+
+#define R92C_IBSS_INT_MASK (R92C_IMR_BCNINT | R92C_IMR_TBDOK | R92C_IMR_TBDER)
+
+/*
+ * Baseband registers.
+ */
+#define R92C_FPGA0_RFMOD 0x800
+#define R92C_FPGA0_TXINFO 0x804
+#define R92C_HSSI_PARAM1(chain) (0x820 + (chain) * 8)
+#define R92C_HSSI_PARAM2(chain) (0x824 + (chain) * 8)
+#define R92C_TXAGC_RATE18_06(i) (((i) == 0) ? 0xe00 : 0x830)
+#define R92C_TXAGC_RATE54_24(i) (((i) == 0) ? 0xe04 : 0x834)
+#define R92C_TXAGC_A_CCK1_MCS32 0xe08
+#define R92C_TXAGC_B_CCK1_55_MCS32 0x838
+#define R92C_TXAGC_B_CCK11_A_CCK2_11 0x86c
+#define R92C_TXAGC_MCS03_MCS00(i) (((i) == 0) ? 0xe10 : 0x83c)
+#define R92C_TXAGC_MCS07_MCS04(i) (((i) == 0) ? 0xe14 : 0x848)
+#define R92C_TXAGC_MCS11_MCS08(i) (((i) == 0) ? 0xe18 : 0x84c)
+#define R92C_TXAGC_MCS15_MCS12(i) (((i) == 0) ? 0xe1c : 0x868)
+#define R92C_LSSI_PARAM(chain) (0x840 + (chain) * 4)
+#define R92C_FPGA0_RFIFACEOE(chain) (0x860 + (chain) * 4)
+#define R92C_FPGA0_RFIFACESW(idx) (0x870 + (idx) * 4)
+#define R92C_FPGA0_RFPARAM(idx) (0x878 + (idx) * 4)
+#define R92C_FPGA0_ANAPARAM2 0x884
+#define R92C_LSSI_READBACK(chain) (0x8a0 + (chain) * 4)
+#define R92C_HSPI_READBACK(chain) (0x8b8 + (chain) * 4)
+#define R92C_FPGA1_RFMOD 0x900
+#define R92C_FPGA1_TXINFO 0x90c
+#define R92C_CCK0_SYSTEM 0xa00
+#define R92C_CCK0_AFESETTING 0xa04
+#define R92C_OFDM0_TRXPATHENA 0xc04
+#define R92C_OFDM0_TRMUXPAR 0xc08
+#define R92C_OFDM0_RXIQIMBALANCE(chain) (0xc14 + (chain) * 8)
+#define R92C_OFDM0_ECCATHRESHOLD 0xc4c
+#define R92C_OFDM0_AGCCORE1(chain) (0xc50 + (chain) * 8)
+#define R92C_OFDM0_AGCPARAM1 0xc70
+#define R92C_OFDM0_AGCRSSITABLE 0xc78
+#define R92C_OFDM0_TXIQIMBALANCE(chain) (0xc80 + (chain) * 8)
+#define R92C_OFDM0_TXAFE(chain) (0xc94 + (chain) * 8)
+#define R92C_OFDM0_RXIQEXTANTA 0xca0
+#define R92C_OFDM1_LSTF 0xd00
+
+/* Bits for R92C_FPGA[01]_RFMOD. */
+#define R92C_RFMOD_40MHZ 0x00000001
+#define R92C_RFMOD_JAPAN 0x00000002
+#define R92C_RFMOD_CCK_TXSC 0x00000030
+#define R92C_RFMOD_CCK_EN 0x01000000
+#define R92C_RFMOD_OFDM_EN 0x02000000
+
+/* Bits for R92C_HSSI_PARAM1(i). */
+#define R92C_HSSI_PARAM1_PI 0x00000100
+
+/* Bits for R92C_HSSI_PARAM2(i). */
+#define R92C_HSSI_PARAM2_CCK_HIPWR 0x00000200
+#define R92C_HSSI_PARAM2_ADDR_LENGTH 0x00000400
+#define R92C_HSSI_PARAM2_DATA_LENGTH 0x00000800
+#define R92C_HSSI_PARAM2_READ_ADDR_M 0x7f800000
+#define R92C_HSSI_PARAM2_READ_ADDR_S 23
+#define R92C_HSSI_PARAM2_READ_EDGE 0x80000000
+
+/* Bits for R92C_TXAGC_A_CCK1_MCS32. */
+#define R92C_TXAGC_A_CCK1_M 0x0000ff00
+#define R92C_TXAGC_A_CCK1_S 8
+
+/* Bits for R92C_TXAGC_B_CCK11_A_CCK2_11. */
+#define R92C_TXAGC_B_CCK11_M 0x000000ff
+#define R92C_TXAGC_B_CCK11_S 0
+#define R92C_TXAGC_A_CCK2_M 0x0000ff00
+#define R92C_TXAGC_A_CCK2_S 8
+#define R92C_TXAGC_A_CCK55_M 0x00ff0000
+#define R92C_TXAGC_A_CCK55_S 16
+#define R92C_TXAGC_A_CCK11_M 0xff000000
+#define R92C_TXAGC_A_CCK11_S 24
+
+/* Bits for R92C_TXAGC_B_CCK1_55_MCS32. */
+#define R92C_TXAGC_B_CCK1_M 0x0000ff00
+#define R92C_TXAGC_B_CCK1_S 8
+#define R92C_TXAGC_B_CCK2_M 0x00ff0000
+#define R92C_TXAGC_B_CCK2_S 16
+#define R92C_TXAGC_B_CCK55_M 0xff000000
+#define R92C_TXAGC_B_CCK55_S 24
+
+/* Bits for R92C_TXAGC_RATE18_06(x). */
+#define R92C_TXAGC_RATE06_M 0x000000ff
+#define R92C_TXAGC_RATE06_S 0
+#define R92C_TXAGC_RATE09_M 0x0000ff00
+#define R92C_TXAGC_RATE09_S 8
+#define R92C_TXAGC_RATE12_M 0x00ff0000
+#define R92C_TXAGC_RATE12_S 16
+#define R92C_TXAGC_RATE18_M 0xff000000
+#define R92C_TXAGC_RATE18_S 24
+
+/* Bits for R92C_TXAGC_RATE54_24(x). */
+#define R92C_TXAGC_RATE24_M 0x000000ff
+#define R92C_TXAGC_RATE24_S 0
+#define R92C_TXAGC_RATE36_M 0x0000ff00
+#define R92C_TXAGC_RATE36_S 8
+#define R92C_TXAGC_RATE48_M 0x00ff0000
+#define R92C_TXAGC_RATE48_S 16
+#define R92C_TXAGC_RATE54_M 0xff000000
+#define R92C_TXAGC_RATE54_S 24
+
+/* Bits for R92C_TXAGC_MCS03_MCS00(x). */
+#define R92C_TXAGC_MCS00_M 0x000000ff
+#define R92C_TXAGC_MCS00_S 0
+#define R92C_TXAGC_MCS01_M 0x0000ff00
+#define R92C_TXAGC_MCS01_S 8
+#define R92C_TXAGC_MCS02_M 0x00ff0000
+#define R92C_TXAGC_MCS02_S 16
+#define R92C_TXAGC_MCS03_M 0xff000000
+#define R92C_TXAGC_MCS03_S 24
+
+/* Bits for R92C_TXAGC_MCS07_MCS04(x). */
+#define R92C_TXAGC_MCS04_M 0x000000ff
+#define R92C_TXAGC_MCS04_S 0
+#define R92C_TXAGC_MCS05_M 0x0000ff00
+#define R92C_TXAGC_MCS05_S 8
+#define R92C_TXAGC_MCS06_M 0x00ff0000
+#define R92C_TXAGC_MCS06_S 16
+#define R92C_TXAGC_MCS07_M 0xff000000
+#define R92C_TXAGC_MCS07_S 24
+
+/* Bits for R92C_TXAGC_MCS11_MCS08(x). */
+#define R92C_TXAGC_MCS08_M 0x000000ff
+#define R92C_TXAGC_MCS08_S 0
+#define R92C_TXAGC_MCS09_M 0x0000ff00
+#define R92C_TXAGC_MCS09_S 8
+#define R92C_TXAGC_MCS10_M 0x00ff0000
+#define R92C_TXAGC_MCS10_S 16
+#define R92C_TXAGC_MCS11_M 0xff000000
+#define R92C_TXAGC_MCS11_S 24
+
+/* Bits for R92C_TXAGC_MCS15_MCS12(x). */
+#define R92C_TXAGC_MCS12_M 0x000000ff
+#define R92C_TXAGC_MCS12_S 0
+#define R92C_TXAGC_MCS13_M 0x0000ff00
+#define R92C_TXAGC_MCS13_S 8
+#define R92C_TXAGC_MCS14_M 0x00ff0000
+#define R92C_TXAGC_MCS14_S 16
+#define R92C_TXAGC_MCS15_M 0xff000000
+#define R92C_TXAGC_MCS15_S 24
+
+/* Bits for R92C_LSSI_PARAM(i). */
+#define R92C_LSSI_PARAM_DATA_M 0x000fffff
+#define R92C_LSSI_PARAM_DATA_S 0
+#define R92C_LSSI_PARAM_ADDR_M 0x03f00000
+#define R92C_LSSI_PARAM_ADDR_S 20
+
+/* Bits for R92C_FPGA0_ANAPARAM2. */
+#define R92C_FPGA0_ANAPARAM2_CBW20 0x00000400
+
+/* Bits for R92C_LSSI_READBACK(i). */
+#define R92C_LSSI_READBACK_DATA_M 0x000fffff
+#define R92C_LSSI_READBACK_DATA_S 0
+
+/* Bits for R92C_OFDM0_AGCCORE1(i). */
+#define R92C_OFDM0_AGCCORE1_GAIN_M 0x0000007f
+#define R92C_OFDM0_AGCCORE1_GAIN_S 0
+
+
+/*
+ * USB registers.
+ */
+#define R92C_USB_INFO 0xfe17
+#define R92C_USB_SPECIAL_OPTION 0xfe55
+#define R92C_USB_HCPWM 0xfe57
+#define R92C_USB_HRPWM 0xfe58
+#define R92C_USB_DMA_AGG_TO 0xfe5b
+#define R92C_USB_AGG_TO 0xfe5c
+#define R92C_USB_AGG_TH 0xfe5d
+#define R92C_USB_VID 0xfe60
+#define R92C_USB_PID 0xfe62
+#define R92C_USB_OPTIONAL 0xfe64
+#define R92C_USB_EP 0xfe65
+#define R92C_USB_PHY 0xfe68
+#define R92C_USB_MAC_ADDR 0xfe70
+#define R92C_USB_STRING 0xfe80
+
+/* Bits for R92C_USB_SPECIAL_OPTION. */
+#define R92C_USB_SPECIAL_OPTION_AGG_EN 0x08
+
+/* Bits for R92C_USB_EP. */
+#define R92C_USB_EP_HQ_M 0x000f
+#define R92C_USB_EP_HQ_S 0
+#define R92C_USB_EP_NQ_M 0x00f0
+#define R92C_USB_EP_NQ_S 4
+#define R92C_USB_EP_LQ_M 0x0f00
+#define R92C_USB_EP_LQ_S 8
+
+
+/*
+ * Firmware base address.
+ */
+#define R92C_FW_START_ADDR 0x1000
+#define R92C_FW_PAGE_SIZE 4096
+
+
+/*
+ * RF (6052) registers.
+ */
+#define R92C_RF_AC 0x00
+#define R92C_RF_IQADJ_G(i) (0x01 + (i))
+#define R92C_RF_POW_TRSW 0x05
+#define R92C_RF_GAIN_RX 0x06
+#define R92C_RF_GAIN_TX 0x07
+#define R92C_RF_TXM_IDAC 0x08
+#define R92C_RF_BS_IQGEN 0x0f
+#define R92C_RF_MODE1 0x10
+#define R92C_RF_MODE2 0x11
+#define R92C_RF_RX_AGC_HP 0x12
+#define R92C_RF_TX_AGC 0x13
+#define R92C_RF_BIAS 0x14
+#define R92C_RF_IPA 0x15
+#define R92C_RF_POW_ABILITY 0x17
+#define R92C_RF_CHNLBW 0x18
+#define R92C_RF_RX_G1 0x1a
+#define R92C_RF_RX_G2 0x1b
+#define R92C_RF_RX_BB2 0x1c
+#define R92C_RF_RX_BB1 0x1d
+#define R92C_RF_RCK1 0x1e
+#define R92C_RF_RCK2 0x1f
+#define R92C_RF_TX_G(i) (0x20 + (i))
+#define R92C_RF_TX_BB1 0x23
+#define R92C_RF_T_METER 0x24
+#define R92C_RF_SYN_G(i) (0x25 + (i))
+#define R92C_RF_RCK_OS 0x30
+#define R92C_RF_TXPA_G(i) (0x31 + (i))
+
+/* Bits for R92C_RF_AC. */
+#define R92C_RF_AC_MODE_M 0x70000
+#define R92C_RF_AC_MODE_S 16
+#define R92C_RF_AC_MODE_STANDBY 1
+
+/* Bits for R92C_RF_CHNLBW. */
+#define R92C_RF_CHNLBW_CHNL_M 0x003ff
+#define R92C_RF_CHNLBW_CHNL_S 0
+#define R92C_RF_CHNLBW_BW20 0x00400
+#define R92C_RF_CHNLBW_LCSTART 0x08000
+
+
+/*
+ * CAM entries.
+ */
+#define R92C_CAM_ENTRY_COUNT 32
+
+#define R92C_CAM_CTL0(entry) ((entry) * 8 + 0)
+#define R92C_CAM_CTL1(entry) ((entry) * 8 + 1)
+#define R92C_CAM_KEY(entry, i) ((entry) * 8 + 2 + (i))
+
+/* Bits for R92C_CAM_CTL0(i). */
+#define R92C_CAM_KEYID_M 0x00000003
+#define R92C_CAM_KEYID_S 0
+#define R92C_CAM_ALGO_M 0x0000001c
+#define R92C_CAM_ALGO_S 2
+#define R92C_CAM_ALGO_NONE 0
+#define R92C_CAM_ALGO_WEP40 1
+#define R92C_CAM_ALGO_TKIP 2
+#define R92C_CAM_ALGO_AES 4
+#define R92C_CAM_ALGO_WEP104 5
+#define R92C_CAM_VALID 0x00008000
+#define R92C_CAM_MACLO_M 0xffff0000
+#define R92C_CAM_MACLO_S 16
+
+/* Rate adaptation modes. */
+#define R92C_RAID_11GN 1
+#define R92C_RAID_11N 3
+#define R92C_RAID_11BG 4
+#define R92C_RAID_11G 5 /* "pure" 11g */
+#define R92C_RAID_11B 6
+
+
+/* Macros to access unaligned little-endian memory. */
+#define LE_READ_2(x) ((x)[0] | (x)[1] << 8)
+#define LE_READ_4(x) ((x)[0] | (x)[1] << 8 | (x)[2] << 16 | (x)[3] << 24)
+
+/*
+ * Macros to access subfields in registers.
+ */
+/* Mask and Shift (getter). */
+#define MS(val, field) \
+ (((val) & field##_M) >> field##_S)
+
+/* Shift and Mask (setter). */
+#define SM(field, val) \
+ (((val) << field##_S) & field##_M)
+
+/* Rewrite. */
+#define RW(var, field, val) \
+ (((var) & ~field##_M) | SM(field, val))
+
+/*
+ * Firmware image header.
+ */
+struct r92c_fw_hdr {
+ /* QWORD0 */
+ uint16_t signature;
+ uint8_t category;
+ uint8_t function;
+ uint16_t version;
+ uint16_t subversion;
+ /* QWORD1 */
+ uint8_t month;
+ uint8_t date;
+ uint8_t hour;
+ uint8_t minute;
+ uint16_t ramcodesize;
+ uint16_t reserved2;
+ /* QWORD2 */
+ uint32_t svnidx;
+ uint32_t reserved3;
+ /* QWORD3 */
+ uint32_t reserved4;
+ uint32_t reserved5;
+} __packed;
+
+/*
+ * Host to firmware commands.
+ */
+struct r92c_fw_cmd {
+ uint8_t id;
+#define R92C_CMD_AP_OFFLOAD 0
+#define R92C_CMD_SET_PWRMODE 1
+#define R92C_CMD_JOINBSS_RPT 2
+#define R92C_CMD_RSVD_PAGE 3
+#define R92C_CMD_RSSI 4
+#define R92C_CMD_RSSI_SETTING 5
+#define R92C_CMD_MACID_CONFIG 6
+#define R92C_CMD_MACID_PS_MODE 7
+#define R92C_CMD_P2P_PS_OFFLOAD 8
+#define R92C_CMD_SELECTIVE_SUSPEND 9
+#define R92C_CMD_FLAG_EXT 0x80
+
+ uint8_t msg[5];
+} __packed;
+
+/* Structure for R92C_CMD_RSSI_SETTING. */
+struct r92c_fw_cmd_rssi {
+ uint8_t macid;
+ uint8_t reserved;
+ uint8_t pwdb;
+} __packed;
+
+/* Structure for R92C_CMD_MACID_CONFIG. */
+struct r92c_fw_cmd_macid_cfg {
+ uint32_t mask;
+ uint8_t macid;
+#define RTWN_MACID_BSS 0
+#define RTWN_MACID_BC 4 /* Broadcast. */
+#define RTWN_MACID_VALID 0x80
+} __packed;
+
+/*
+ * RTL8192CU ROM image.
+ */
+struct r92c_rom {
+ uint16_t id; /* 0x8129 */
+ uint8_t reserved1[5];
+ uint8_t dbg_sel;
+ uint16_t reserved2;
+ uint16_t vid;
+ uint16_t pid;
+ uint8_t usb_opt;
+ uint8_t ep_setting;
+ uint16_t reserved3;
+ uint8_t usb_phy;
+ uint8_t reserved4[3];
+ uint8_t macaddr[6];
+ uint8_t string[61]; /* "Realtek" */
+ uint8_t subcustomer_id;
+ uint8_t cck_tx_pwr[R92C_MAX_CHAINS][3];
+ uint8_t ht40_1s_tx_pwr[R92C_MAX_CHAINS][3];
+ uint8_t ht40_2s_tx_pwr_diff[3];
+ uint8_t ht20_tx_pwr_diff[3];
+ uint8_t ofdm_tx_pwr_diff[3];
+ uint8_t ht40_max_pwr[3];
+ uint8_t ht20_max_pwr[3];
+ uint8_t xtal_calib;
+ uint8_t tssi[R92C_MAX_CHAINS];
+ uint8_t thermal_meter;
+ uint8_t rf_opt1;
+#define R92C_ROM_RF1_REGULATORY_M 0x07
+#define R92C_ROM_RF1_REGULATORY_S 0
+#define R92C_ROM_RF1_BOARD_TYPE_M 0xe0
+#define R92C_ROM_RF1_BOARD_TYPE_S 5
+#define R92C_BOARD_TYPE_DONGLE 0
+#define R92C_BOARD_TYPE_HIGHPA 1
+#define R92C_BOARD_TYPE_MINICARD 2
+#define R92C_BOARD_TYPE_SOLO 3
+#define R92C_BOARD_TYPE_COMBO 4
+
+ uint8_t rf_opt2;
+ uint8_t rf_opt3;
+ uint8_t rf_opt4;
+ uint8_t channel_plan;
+ uint8_t version;
+ uint8_t curstomer_id;
+} __packed;
+
+/* Rx MAC descriptor. */
+struct r92c_rx_desc {
+ uint32_t rxdw0;
+#define R92C_RXDW0_PKTLEN_M 0x00003fff
+#define R92C_RXDW0_PKTLEN_S 0
+#define R92C_RXDW0_CRCERR 0x00004000
+#define R92C_RXDW0_ICVERR 0x00008000
+#define R92C_RXDW0_INFOSZ_M 0x000f0000
+#define R92C_RXDW0_INFOSZ_S 16
+#define R92C_RXDW0_QOS 0x00800000
+#define R92C_RXDW0_SHIFT_M 0x03000000
+#define R92C_RXDW0_SHIFT_S 24
+#define R92C_RXDW0_PHYST 0x04000000
+#define R92C_RXDW0_DECRYPTED 0x08000000
+#define R92C_RXDW0_LS 0x10000000
+#define R92C_RXDW0_FS 0x20000000
+#define R92C_RXDW0_EOR 0x40000000
+#define R92C_RXDW0_OWN 0x80000000
+
+ uint32_t rxdw1;
+ uint32_t rxdw2;
+#define R92C_RXDW2_PKTCNT_M 0x00ff0000
+#define R92C_RXDW2_PKTCNT_S 16
+
+ uint32_t rxdw3;
+#define R92C_RXDW3_RATE_M 0x0000003f
+#define R92C_RXDW3_RATE_S 0
+#define R92C_RXDW3_HT 0x00000040
+#define R92C_RXDW3_HTC 0x00000400
+
+ uint32_t rxdw4;
+ uint32_t rxdw5;
+
+ uint32_t rxbufaddr;
+ uint32_t rxbufaddr64;
+} __packed __attribute__((aligned(4)));
+
+/* Rx PHY descriptor. */
+struct r92c_rx_phystat {
+ uint32_t phydw0;
+ uint32_t phydw1;
+ uint32_t phydw2;
+ uint32_t phydw3;
+ uint32_t phydw4;
+ uint32_t phydw5;
+ uint32_t phydw6;
+ uint32_t phydw7;
+} __packed __attribute__((aligned(4)));
+
+/* Rx PHY CCK descriptor. */
+struct r92c_rx_cck {
+ uint8_t adc_pwdb[4];
+ uint8_t sq_rpt;
+ uint8_t agc_rpt;
+} __packed;
+
+/* Tx MAC descriptor. */
+struct r92c_tx_desc {
+ uint32_t txdw0;
+#define R92C_TXDW0_PKTLEN_M 0x0000ffff
+#define R92C_TXDW0_PKTLEN_S 0
+#define R92C_TXDW0_OFFSET_M 0x00ff0000
+#define R92C_TXDW0_OFFSET_S 16
+#define R92C_TXDW0_BMCAST 0x01000000
+#define R92C_TXDW0_LSG 0x04000000
+#define R92C_TXDW0_FSG 0x08000000
+#define R92C_TXDW0_OWN 0x80000000
+
+ uint32_t txdw1;
+#define R92C_TXDW1_MACID_M 0x0000001f
+#define R92C_TXDW1_MACID_S 0
+#define R92C_TXDW1_AGGEN 0x00000020
+#define R92C_TXDW1_AGGBK 0x00000040
+#define R92C_TXDW1_QSEL_M 0x00001f00
+#define R92C_TXDW1_QSEL_S 8
+#define R92C_TXDW1_QSEL_BE 0x00
+#define R92C_TXDW1_QSEL_BK 0x02
+#define R92C_TXDW1_QSEL_VI 0x05
+#define R92C_TXDW1_QSEL_VO 0x07
+#define R92C_TXDW1_QSEL_BEACON 0x10
+#define R92C_TXDW1_QSEL_HIGH 0x11
+#define R92C_TXDW1_QSEL_MGNT 0x12
+#define R92C_TXDW1_QSEL_CMD 0x13
+#define R92C_TXDW1_RAID_M 0x000f0000
+#define R92C_TXDW1_RAID_S 16
+#define R92C_TXDW1_CIPHER_M 0x00c00000
+#define R92C_TXDW1_CIPHER_S 22
+#define R92C_TXDW1_CIPHER_NONE 0
+#define R92C_TXDW1_CIPHER_RC4 1
+#define R92C_TXDW1_CIPHER_AES 3
+#define R92C_TXDW1_PKTOFF_M 0x7c000000
+#define R92C_TXDW1_PKTOFF_S 26
+
+ uint32_t txdw2;
+ uint16_t txdw3;
+ uint16_t txdseq;
+
+ uint32_t txdw4;
+#define R92C_TXDW4_RTSRATE_M 0x0000003f
+#define R92C_TXDW4_RTSRATE_S 0
+#define R92C_TXDW4_QOS 0x00000040
+#define R92C_TXDW4_HWSEQ 0x00000080
+#define R92C_TXDW4_DRVRATE 0x00000100
+#define R92C_TXDW4_CTS2SELF 0x00000800
+#define R92C_TXDW4_RTSEN 0x00001000
+#define R92C_TXDW4_HWRTSEN 0x00002000
+#define R92C_TXDW4_SCO_M 0x003f0000
+#define R92C_TXDW4_SCO_S 20
+#define R92C_TXDW4_SCO_SCA 1
+#define R92C_TXDW4_SCO_SCB 2
+#define R92C_TXDW4_40MHZ 0x02000000
+
+ uint32_t txdw5;
+#define R92C_TXDW5_DATARATE_M 0x0000003f
+#define R92C_TXDW5_DATARATE_S 0
+#define R92C_TXDW5_SGI 0x00000040
+#define R92C_TXDW5_DATARATE_FBLIMIT_M 0x00001f00
+#define R92C_TXDW5_DATARATE_FBLIMIT_S 8
+#define R92C_TXDW5_RTSRATE_FBLIMIT_M 0x0001e000
+#define R92C_TXDW5_RTSRATE_FBLIMIT_S 13
+#define R92C_TXDW5_RETRY_LIMIT_ENABLE 0x00020000
+#define R92C_TXDW5_DATA_RETRY_LIMIT_M 0x00fc0000
+#define R92C_TXDW5_DATA_RETRY_LIMIT_S 18
+#define R92C_TXDW5_AGGNUM_M 0xff000000
+#define R92C_TXDW5_AGGNUM_S 24
+
+ uint32_t txdw6;
+
+ uint16_t txbufsize;
+ uint16_t pad;
+
+ uint32_t txbufaddr;
+ uint32_t txbufaddr64;
+
+ uint32_t nextdescaddr;
+ uint32_t nextdescaddr64;
+
+ uint32_t reserved[4];
+} __packed __attribute__((aligned(4)));
+
+
+/*
+ * Driver definitions.
+ */
+#define RTWN_NTXQUEUES 9
+#define RTWN_RX_LIST_COUNT 256
+#define RTWN_TX_LIST_COUNT 256
+#define RTWN_HOST_CMD_RING_COUNT 32
+
+/* TX queue indices. */
+#define RTWN_BK_QUEUE 0
+#define RTWN_BE_QUEUE 1
+#define RTWN_VI_QUEUE 2
+#define RTWN_VO_QUEUE 3
+#define RTWN_BEACON_QUEUE 4
+#define RTWN_TXCMD_QUEUE 5
+#define RTWN_MGNT_QUEUE 6
+#define RTWN_HIGH_QUEUE 7
+#define RTWN_HCCA_QUEUE 8
+
+/* RX queue indices. */
+#define RTWN_RX_QUEUE 0
+
+#define RTWN_RXBUFSZ (16 * 1024)
+#define RTWN_TXBUFSZ (sizeof(struct r92c_tx_desc) + IEEE80211_MAX_LEN)
+
+#define RTWN_RIDX_COUNT 28
+
+#define RTWN_TX_TIMEOUT 5000 /* ms */
+
+#define RTWN_LED_LINK 0
+#define RTWN_LED_DATA 1
+
+struct rtwn_rx_radiotap_header {
+ struct ieee80211_radiotap_header wr_ihdr;
+ uint8_t wr_flags;
+ uint8_t wr_rate;
+ uint16_t wr_chan_freq;
+ uint16_t wr_chan_flags;
+ uint8_t wr_dbm_antsignal;
+} __packed;
+
+#define RTWN_RX_RADIOTAP_PRESENT \
+ (1 << IEEE80211_RADIOTAP_FLAGS | \
+ 1 << IEEE80211_RADIOTAP_RATE | \
+ 1 << IEEE80211_RADIOTAP_CHANNEL | \
+ 1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL)
+
+struct rtwn_tx_radiotap_header {
+ struct ieee80211_radiotap_header wt_ihdr;
+ uint8_t wt_flags;
+ uint16_t wt_chan_freq;
+ uint16_t wt_chan_flags;
+} __packed;
+
+#define RTWN_TX_RADIOTAP_PRESENT \
+ (1 << IEEE80211_RADIOTAP_FLAGS | \
+ 1 << IEEE80211_RADIOTAP_CHANNEL)
+
+struct rtwn_softc;
+
+struct rtwn_rx_data {
+ bus_dmamap_t map;
+ struct mbuf *m;
+ bus_addr_t paddr;
+};
+
+struct rtwn_rx_ring {
+ struct r92c_rx_desc *desc;
+ bus_addr_t paddr;
+ bus_dma_tag_t desc_dmat;
+ bus_dmamap_t desc_map;
+ bus_dma_tag_t data_dmat;
+ bus_dma_segment_t seg;
+ struct rtwn_rx_data rx_data[RTWN_RX_LIST_COUNT];
+
+};
+struct rtwn_tx_data {
+ bus_dmamap_t map;
+ struct mbuf *m;
+ struct ieee80211_node *ni;
+};
+
+struct rtwn_tx_ring {
+ bus_addr_t paddr;
+ bus_dma_tag_t desc_dmat;
+ bus_dmamap_t desc_map;
+ bus_dma_tag_t data_dmat;
+ bus_dma_segment_t seg;
+ struct r92c_tx_desc *desc;
+ struct rtwn_tx_data tx_data[RTWN_TX_LIST_COUNT];
+ int queued;
+ int cur;
+};
+
+struct rtwn_host_cmd {
+ void (*cb)(struct rtwn_softc *, void *);
+ uint8_t data[256];
+};
+
+struct rtwn_cmd_key {
+ struct ieee80211_key key;
+ uint16_t associd;
+};
+
+struct rtwn_host_cmd_ring {
+ struct rtwn_host_cmd cmd[RTWN_HOST_CMD_RING_COUNT];
+ int cur;
+ int next;
+ int queued;
+};
+
+struct rtwn_vap {
+ struct ieee80211vap vap;
+ int (*newstate)(struct ieee80211vap *,
+ enum ieee80211_state, int);
+};
+#define RTWN_VAP(vap) ((struct rtwn_vap *)(vap))
+
+struct rtwn_softc {
+ device_t sc_dev;
+ struct mtx sc_mtx;
+ struct ieee80211com sc_ic;
+ struct mbufq sc_snd;
+
+ struct resource *irq;
+ struct resource *mem;
+ bus_space_tag_t sc_st;
+ bus_space_handle_t sc_sh;
+ void *sc_ih;
+ bus_size_t sc_mapsize;
+ int sc_cap_off;
+
+ struct task sc_reinit_task;
+ struct callout calib_to;
+ struct callout watchdog_to;
+
+ int sc_debug;
+
+ u_int sc_flags;
+#define RTWN_FLAG_CCK_HIPWR 0x01
+#define RTWN_FLAG_BUSY 0x02
+#define RTWN_RUNNING 0x04
+
+ u_int chip;
+#define RTWN_CHIP_88C 0x00
+#define RTWN_CHIP_92C 0x01
+#define RTWN_CHIP_92C_1T2R 0x02
+#define RTWN_CHIP_UMC 0x04
+#define RTWN_CHIP_UMC_A_CUT 0x08
+
+ uint8_t board_type;
+ uint8_t regulatory;
+ uint8_t pa_setting;
+ int avg_pwdb;
+ int thcal_state;
+ int thcal_lctemp;
+ int ntxchains;
+ int nrxchains;
+ int ledlink;
+
+ int sc_tx_timer;
+ int fwcur;
+ struct rtwn_rx_ring rx_ring;
+ struct rtwn_tx_ring tx_ring[RTWN_NTXQUEUES];
+ uint32_t qfullmsk;
+ struct r92c_rom rom;
+
+ uint32_t rf_chnlbw[R92C_MAX_CHAINS];
+
+ struct rtwn_rx_radiotap_header sc_rxtap;
+ struct rtwn_tx_radiotap_header sc_txtap;
+};
+
+/*
+ * MAC initialization values.
+ */
+static const struct {
+ uint16_t reg;
+ uint8_t val;
+} rtl8192ce_mac[] = {
+ { 0x420, 0x80 }, { 0x423, 0x00 }, { 0x430, 0x00 }, { 0x431, 0x00 },
+ { 0x432, 0x00 }, { 0x433, 0x01 }, { 0x434, 0x04 }, { 0x435, 0x05 },
+ { 0x436, 0x06 }, { 0x437, 0x07 }, { 0x438, 0x00 }, { 0x439, 0x00 },
+ { 0x43a, 0x00 }, { 0x43b, 0x01 }, { 0x43c, 0x04 }, { 0x43d, 0x05 },
+ { 0x43e, 0x06 }, { 0x43f, 0x07 }, { 0x440, 0x5d }, { 0x441, 0x01 },
+ { 0x442, 0x00 }, { 0x444, 0x15 }, { 0x445, 0xf0 }, { 0x446, 0x0f },
+ { 0x447, 0x00 }, { 0x458, 0x41 }, { 0x459, 0xa8 }, { 0x45a, 0x72 },
+ { 0x45b, 0xb9 }, { 0x460, 0x88 }, { 0x461, 0x88 }, { 0x462, 0x06 },
+ { 0x463, 0x03 }, { 0x4c8, 0x04 }, { 0x4c9, 0x08 }, { 0x4cc, 0x02 },
+ { 0x4cd, 0x28 }, { 0x4ce, 0x01 }, { 0x500, 0x26 }, { 0x501, 0xa2 },
+ { 0x502, 0x2f }, { 0x503, 0x00 }, { 0x504, 0x28 }, { 0x505, 0xa3 },
+ { 0x506, 0x5e }, { 0x507, 0x00 }, { 0x508, 0x2b }, { 0x509, 0xa4 },
+ { 0x50a, 0x5e }, { 0x50b, 0x00 }, { 0x50c, 0x4f }, { 0x50d, 0xa4 },
+ { 0x50e, 0x00 }, { 0x50f, 0x00 }, { 0x512, 0x1c }, { 0x514, 0x0a },
+ { 0x515, 0x10 }, { 0x516, 0x0a }, { 0x517, 0x10 }, { 0x51a, 0x16 },
+ { 0x524, 0x0f }, { 0x525, 0x4f }, { 0x546, 0x20 }, { 0x547, 0x00 },
+ { 0x559, 0x02 }, { 0x55a, 0x02 }, { 0x55d, 0xff }, { 0x605, 0x30 },
+ { 0x608, 0x0e }, { 0x609, 0x2a }, { 0x652, 0x20 }, { 0x63c, 0x0a },
+ { 0x63d, 0x0e }, { 0x700, 0x21 }, { 0x701, 0x43 }, { 0x702, 0x65 },
+ { 0x703, 0x87 }, { 0x708, 0x21 }, { 0x709, 0x43 }, { 0x70a, 0x65 },
+ { 0x70b, 0x87 }
+};
+
+/*
+ * Baseband initialization values.
+ */
+struct rtwn_bb_prog {
+ int count;
+ const uint16_t *regs;
+ const uint32_t *vals;
+ int agccount;
+ const uint32_t *agcvals;
+};
+
+/*
+ * RTL8192CU and RTL8192CE-VAU.
+ */
+static const uint16_t rtl8192ce_bb_regs[] = {
+ 0x024, 0x028, 0x800, 0x804, 0x808, 0x80c, 0x810, 0x814, 0x818,
+ 0x81c, 0x820, 0x824, 0x828, 0x82c, 0x830, 0x834, 0x838, 0x83c,
+ 0x840, 0x844, 0x848, 0x84c, 0x850, 0x854, 0x858, 0x85c, 0x860,
+ 0x864, 0x868, 0x86c, 0x870, 0x874, 0x878, 0x87c, 0x880, 0x884,
+ 0x888, 0x88c, 0x890, 0x894, 0x898, 0x89c, 0x900, 0x904, 0x908,
+ 0x90c, 0xa00, 0xa04, 0xa08, 0xa0c, 0xa10, 0xa14, 0xa18, 0xa1c,
+ 0xa20, 0xa24, 0xa28, 0xa2c, 0xa70, 0xa74, 0xc00, 0xc04, 0xc08,
+ 0xc0c, 0xc10, 0xc14, 0xc18, 0xc1c, 0xc20, 0xc24, 0xc28, 0xc2c,
+ 0xc30, 0xc34, 0xc38, 0xc3c, 0xc40, 0xc44, 0xc48, 0xc4c, 0xc50,
+ 0xc54, 0xc58, 0xc5c, 0xc60, 0xc64, 0xc68, 0xc6c, 0xc70, 0xc74,
+ 0xc78, 0xc7c, 0xc80, 0xc84, 0xc88, 0xc8c, 0xc90, 0xc94, 0xc98,
+ 0xc9c, 0xca0, 0xca4, 0xca8, 0xcac, 0xcb0, 0xcb4, 0xcb8, 0xcbc,
+ 0xcc0, 0xcc4, 0xcc8, 0xccc, 0xcd0, 0xcd4, 0xcd8, 0xcdc, 0xce0,
+ 0xce4, 0xce8, 0xcec, 0xd00, 0xd04, 0xd08, 0xd0c, 0xd10, 0xd14,
+ 0xd18, 0xd2c, 0xd30, 0xd34, 0xd38, 0xd3c, 0xd40, 0xd44, 0xd48,
+ 0xd4c, 0xd50, 0xd54, 0xd58, 0xd5c, 0xd60, 0xd64, 0xd68, 0xd6c,
+ 0xd70, 0xd74, 0xd78, 0xe00, 0xe04, 0xe08, 0xe10, 0xe14, 0xe18,
+ 0xe1c, 0xe28, 0xe30, 0xe34, 0xe38, 0xe3c, 0xe40, 0xe44, 0xe48,
+ 0xe4c, 0xe50, 0xe54, 0xe58, 0xe5c, 0xe60, 0xe68, 0xe6c, 0xe70,
+ 0xe74, 0xe78, 0xe7c, 0xe80, 0xe84, 0xe88, 0xe8c, 0xed0, 0xed4,
+ 0xed8, 0xedc, 0xee0, 0xeec, 0xf14, 0xf4c, 0xf00
+};
+
+static const uint32_t rtl8192ce_bb_vals_2t[] = {
+ 0x0011800f, 0x00ffdb83, 0x80040002, 0x00000003, 0x0000fc00,
+ 0x0000000a, 0x10005388, 0x020c3d10, 0x02200385, 0x00000000,
+ 0x01000100, 0x00390004, 0x01000100, 0x00390004, 0x27272727,
+ 0x27272727, 0x27272727, 0x27272727, 0x00010000, 0x00010000,
+ 0x27272727, 0x27272727, 0x00000000, 0x00000000, 0x569a569a,
+ 0x0c1b25a4, 0x66e60230, 0x061f0130, 0x27272727, 0x2b2b2b27,
+ 0x07000700, 0x22184000, 0x08080808, 0x00000000, 0xc0083070,
+ 0x000004d5, 0x00000000, 0xcc0000c0, 0x00000800, 0xfffffffe,
+ 0x40302010, 0x00706050, 0x00000000, 0x00000023, 0x00000000,
+ 0x81121313, 0x00d047c8, 0x80ff000c, 0x8c838300, 0x2e68120f,
+ 0x9500bb78, 0x11144028, 0x00881117, 0x89140f00, 0x1a1b0000,
+ 0x090e1317, 0x00000204, 0x00d30000, 0x101fbf00, 0x00000007,
+ 0x48071d40, 0x03a05633, 0x000000e4, 0x6c6c6c6c, 0x08800000,
+ 0x40000100, 0x08800000, 0x40000100, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x69e9ac44, 0x469652cf, 0x49795994,
+ 0x0a97971c, 0x1f7c403f, 0x000100b7, 0xec020107, 0x007f037f,
+ 0x69543420, 0x43bc0094, 0x69543420, 0x433c0094, 0x00000000,
+ 0x5116848b, 0x47c00bff, 0x00000036, 0x2c7f000d, 0x018610db,
+ 0x0000001f, 0x00b91612, 0x40000100, 0x20f60000, 0x40000100,
+ 0x20200000, 0x00121820, 0x00000000, 0x00121820, 0x00007f7f,
+ 0x00000000, 0x00000080, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x28000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x64b22427,
+ 0x00766932, 0x00222222, 0x00000000, 0x37644302, 0x2f97d40c,
+ 0x00080740, 0x00020403, 0x0000907f, 0x20010201, 0xa0633333,
+ 0x3333bc43, 0x7a8f5b6b, 0xcc979975, 0x00000000, 0x80608000,
+ 0x00000000, 0x00027293, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x6437140a, 0x00000000, 0x00000000, 0x30032064,
+ 0x4653de68, 0x04518a3c, 0x00002101, 0x2a201c16, 0x1812362e,
+ 0x322c2220, 0x000e3c24, 0x2a2a2a2a, 0x2a2a2a2a, 0x03902a2a,
+ 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x00000000,
+ 0x1000dc1f, 0x10008c1f, 0x02140102, 0x681604c2, 0x01007c00,
+ 0x01004800, 0xfb000000, 0x000028d1, 0x1000dc1f, 0x10008c1f,
+ 0x02140102, 0x28160d05, 0x00000010, 0x001b25a4, 0x63db25a4,
+ 0x63db25a4, 0x0c1b25a4, 0x0c1b25a4, 0x0c1b25a4, 0x0c1b25a4,
+ 0x63db25a4, 0x0c1b25a4, 0x63db25a4, 0x63db25a4, 0x63db25a4,
+ 0x63db25a4, 0x001b25a4, 0x001b25a4, 0x6fdb25a4, 0x00000003,
+ 0x00000000, 0x00000300
+};
+
+static const uint32_t rtl8192ce_bb_vals_1t[] = {
+ 0x0011800f, 0x00ffdb83, 0x80040000, 0x00000001, 0x0000fc00,
+ 0x0000000a, 0x10005388, 0x020c3d10, 0x02200385, 0x00000000,
+ 0x01000100, 0x00390004, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00010000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x569a569a,
+ 0x001b25a4, 0x66e60230, 0x061f0130, 0x00000000, 0x32323200,
+ 0x07000700, 0x22004000, 0x00000808, 0x00000000, 0xc0083070,
+ 0x000004d5, 0x00000000, 0xccc000c0, 0x00000800, 0xfffffffe,
+ 0x40302010, 0x00706050, 0x00000000, 0x00000023, 0x00000000,
+ 0x81121111, 0x00d047c8, 0x80ff000c, 0x8c838300, 0x2e68120f,
+ 0x9500bb78, 0x11144028, 0x00881117, 0x89140f00, 0x1a1b0000,
+ 0x090e1317, 0x00000204, 0x00d30000, 0x101fbf00, 0x00000007,
+ 0x48071d40, 0x03a05611, 0x000000e4, 0x6c6c6c6c, 0x08800000,
+ 0x40000100, 0x08800000, 0x40000100, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x69e9ac44, 0x469652cf, 0x49795994,
+ 0x0a97971c, 0x1f7c403f, 0x000100b7, 0xec020107, 0x007f037f,
+ 0x69543420, 0x43bc0094, 0x69543420, 0x433c0094, 0x00000000,
+ 0x5116848b, 0x47c00bff, 0x00000036, 0x2c7f000d, 0x018610db,
+ 0x0000001f, 0x00b91612, 0x40000100, 0x20f60000, 0x40000100,
+ 0x20200000, 0x00121820, 0x00000000, 0x00121820, 0x00007f7f,
+ 0x00000000, 0x00000080, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x28000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x64b22427,
+ 0x00766932, 0x00222222, 0x00000000, 0x37644302, 0x2f97d40c,
+ 0x00080740, 0x00020401, 0x0000907f, 0x20010201, 0xa0633333,
+ 0x3333bc43, 0x7a8f5b6b, 0xcc979975, 0x00000000, 0x80608000,
+ 0x00000000, 0x00027293, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x6437140a, 0x00000000, 0x00000000, 0x30032064,
+ 0x4653de68, 0x04518a3c, 0x00002101, 0x2a201c16, 0x1812362e,
+ 0x322c2220, 0x000e3c24, 0x2a2a2a2a, 0x2a2a2a2a, 0x03902a2a,
+ 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x00000000,
+ 0x1000dc1f, 0x10008c1f, 0x02140102, 0x681604c2, 0x01007c00,
+ 0x01004800, 0xfb000000, 0x000028d1, 0x1000dc1f, 0x10008c1f,
+ 0x02140102, 0x28160d05, 0x00000010, 0x001b25a4, 0x631b25a0,
+ 0x631b25a0, 0x081b25a0, 0x081b25a0, 0x081b25a0, 0x081b25a0,
+ 0x631b25a0, 0x081b25a0, 0x631b25a0, 0x631b25a0, 0x631b25a0,
+ 0x631b25a0, 0x001b25a0, 0x001b25a0, 0x6b1b25a0, 0x00000003,
+ 0x00000000, 0x00000300,
+};
+
+static const uint32_t rtl8192ce_agc_vals[] = {
+ 0x7b000001, 0x7b010001, 0x7b020001, 0x7b030001, 0x7b040001,
+ 0x7b050001, 0x7a060001, 0x79070001, 0x78080001, 0x77090001,
+ 0x760a0001, 0x750b0001, 0x740c0001, 0x730d0001, 0x720e0001,
+ 0x710f0001, 0x70100001, 0x6f110001, 0x6e120001, 0x6d130001,
+ 0x6c140001, 0x6b150001, 0x6a160001, 0x69170001, 0x68180001,
+ 0x67190001, 0x661a0001, 0x651b0001, 0x641c0001, 0x631d0001,
+ 0x621e0001, 0x611f0001, 0x60200001, 0x49210001, 0x48220001,
+ 0x47230001, 0x46240001, 0x45250001, 0x44260001, 0x43270001,
+ 0x42280001, 0x41290001, 0x402a0001, 0x262b0001, 0x252c0001,
+ 0x242d0001, 0x232e0001, 0x222f0001, 0x21300001, 0x20310001,
+ 0x06320001, 0x05330001, 0x04340001, 0x03350001, 0x02360001,
+ 0x01370001, 0x00380001, 0x00390001, 0x003a0001, 0x003b0001,
+ 0x003c0001, 0x003d0001, 0x003e0001, 0x003f0001, 0x7b400001,
+ 0x7b410001, 0x7b420001, 0x7b430001, 0x7b440001, 0x7b450001,
+ 0x7a460001, 0x79470001, 0x78480001, 0x77490001, 0x764a0001,
+ 0x754b0001, 0x744c0001, 0x734d0001, 0x724e0001, 0x714f0001,
+ 0x70500001, 0x6f510001, 0x6e520001, 0x6d530001, 0x6c540001,
+ 0x6b550001, 0x6a560001, 0x69570001, 0x68580001, 0x67590001,
+ 0x665a0001, 0x655b0001, 0x645c0001, 0x635d0001, 0x625e0001,
+ 0x615f0001, 0x60600001, 0x49610001, 0x48620001, 0x47630001,
+ 0x46640001, 0x45650001, 0x44660001, 0x43670001, 0x42680001,
+ 0x41690001, 0x406a0001, 0x266b0001, 0x256c0001, 0x246d0001,
+ 0x236e0001, 0x226f0001, 0x21700001, 0x20710001, 0x06720001,
+ 0x05730001, 0x04740001, 0x03750001, 0x02760001, 0x01770001,
+ 0x00780001, 0x00790001, 0x007a0001, 0x007b0001, 0x007c0001,
+ 0x007d0001, 0x007e0001, 0x007f0001, 0x3800001e, 0x3801001e,
+ 0x3802001e, 0x3803001e, 0x3804001e, 0x3805001e, 0x3806001e,
+ 0x3807001e, 0x3808001e, 0x3c09001e, 0x3e0a001e, 0x400b001e,
+ 0x440c001e, 0x480d001e, 0x4c0e001e, 0x500f001e, 0x5210001e,
+ 0x5611001e, 0x5a12001e, 0x5e13001e, 0x6014001e, 0x6015001e,
+ 0x6016001e, 0x6217001e, 0x6218001e, 0x6219001e, 0x621a001e,
+ 0x621b001e, 0x621c001e, 0x621d001e, 0x621e001e, 0x621f001e
+};
+
+static const struct rtwn_bb_prog rtl8192ce_bb_prog_2t = {
+ nitems(rtl8192ce_bb_regs),
+ rtl8192ce_bb_regs,
+ rtl8192ce_bb_vals_2t,
+ nitems(rtl8192ce_agc_vals),
+ rtl8192ce_agc_vals
+};
+
+static const struct rtwn_bb_prog rtl8192ce_bb_prog_1t = {
+ nitems(rtl8192ce_bb_regs),
+ rtl8192ce_bb_regs,
+ rtl8192ce_bb_vals_1t,
+ nitems(rtl8192ce_agc_vals),
+ rtl8192ce_agc_vals
+};
+
+/*
+ * RTL8188CU.
+ */
+static const uint32_t rtl8192cu_bb_vals[] = {
+ 0x0011800d, 0x00ffdb83, 0x80040002, 0x00000003, 0x0000fc00,
+ 0x0000000a, 0x10005388, 0x020c3d10, 0x02200385, 0x00000000,
+ 0x01000100, 0x00390004, 0x01000100, 0x00390004, 0x27272727,
+ 0x27272727, 0x27272727, 0x27272727, 0x00010000, 0x00010000,
+ 0x27272727, 0x27272727, 0x00000000, 0x00000000, 0x569a569a,
+ 0x0c1b25a4, 0x66e60230, 0x061f0130, 0x27272727, 0x2b2b2b27,
+ 0x07000700, 0x22184000, 0x08080808, 0x00000000, 0xc0083070,
+ 0x000004d5, 0x00000000, 0xcc0000c0, 0x00000800, 0xfffffffe,
+ 0x40302010, 0x00706050, 0x00000000, 0x00000023, 0x00000000,
+ 0x81121313, 0x00d047c8, 0x80ff000c, 0x8c838300, 0x2e68120f,
+ 0x9500bb78, 0x11144028, 0x00881117, 0x89140f00, 0x1a1b0000,
+ 0x090e1317, 0x00000204, 0x00d30000, 0x101fbf00, 0x00000007,
+ 0x48071d40, 0x03a05633, 0x000000e4, 0x6c6c6c6c, 0x08800000,
+ 0x40000100, 0x08800000, 0x40000100, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x69e9ac44, 0x469652cf, 0x49795994,
+ 0x0a97971c, 0x1f7c403f, 0x000100b7, 0xec020107, 0x007f037f,
+ 0x6954341e, 0x43bc0094, 0x6954341e, 0x433c0094, 0x00000000,
+ 0x5116848b, 0x47c00bff, 0x00000036, 0x2c7f000d, 0x0186115b,
+ 0x0000001f, 0x00b99612, 0x40000100, 0x20f60000, 0x40000100,
+ 0x20200000, 0x00121820, 0x00000000, 0x00121820, 0x00007f7f,
+ 0x00000000, 0x00000080, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x28000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x64b22427,
+ 0x00766932, 0x00222222, 0x00000000, 0x37644302, 0x2f97d40c,
+ 0x00080740, 0x00020403, 0x0000907f, 0x20010201, 0xa0633333,
+ 0x3333bc43, 0x7a8f5b6b, 0xcc979975, 0x00000000, 0x80608000,
+ 0x00000000, 0x00027293, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x6437140a, 0x00000000, 0x00000000, 0x30032064,
+ 0x4653de68, 0x04518a3c, 0x00002101, 0x2a201c16, 0x1812362e,
+ 0x322c2220, 0x000e3c24, 0x2a2a2a2a, 0x2a2a2a2a, 0x03902a2a,
+ 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x00000000,
+ 0x1000dc1f, 0x10008c1f, 0x02140102, 0x681604c2, 0x01007c00,
+ 0x01004800, 0xfb000000, 0x000028d1, 0x1000dc1f, 0x10008c1f,
+ 0x02140102, 0x28160d05, 0x00000010, 0x001b25a4, 0x63db25a4,
+ 0x63db25a4, 0x0c1b25a4, 0x0c1b25a4, 0x0c1b25a4, 0x0c1b25a4,
+ 0x63db25a4, 0x0c1b25a4, 0x63db25a4, 0x63db25a4, 0x63db25a4,
+ 0x63db25a4, 0x001b25a4, 0x001b25a4, 0x6fdb25a4, 0x00000003,
+ 0x00000000, 0x00000300
+};
+
+static const struct rtwn_bb_prog rtl8192cu_bb_prog = {
+ nitems(rtl8192ce_bb_regs),
+ rtl8192ce_bb_regs,
+ rtl8192cu_bb_vals,
+ nitems(rtl8192ce_agc_vals),
+ rtl8192ce_agc_vals
+};
+
+/*
+ * RTL8188CE-VAU.
+ */
+static const uint32_t rtl8188ce_bb_vals[] = {
+ 0x0011800d, 0x00ffdb83, 0x80040000, 0x00000001, 0x0000fc00,
+ 0x0000000a, 0x10005388, 0x020c3d10, 0x02200385, 0x00000000,
+ 0x01000100, 0x00390004, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00010000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x569a569a,
+ 0x001b25a4, 0x66e60230, 0x061f0130, 0x00000000, 0x32323200,
+ 0x07000700, 0x22004000, 0x00000808, 0x00000000, 0xc0083070,
+ 0x000004d5, 0x00000000, 0xccc000c0, 0x00000800, 0xfffffffe,
+ 0x40302010, 0x00706050, 0x00000000, 0x00000023, 0x00000000,
+ 0x81121111, 0x00d047c8, 0x80ff000c, 0x8c838300, 0x2e68120f,
+ 0x9500bb78, 0x11144028, 0x00881117, 0x89140f00, 0x1a1b0000,
+ 0x090e1317, 0x00000204, 0x00d30000, 0x101fbf00, 0x00000007,
+ 0x48071d40, 0x03a05611, 0x000000e4, 0x6c6c6c6c, 0x08800000,
+ 0x40000100, 0x08800000, 0x40000100, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x69e9ac44, 0x469652cf, 0x49795994,
+ 0x0a97971c, 0x1f7c403f, 0x000100b7, 0xec020107, 0x007f037f,
+ 0x6954341e, 0x43bc0094, 0x6954341e, 0x433c0094, 0x00000000,
+ 0x5116848b, 0x47c00bff, 0x00000036, 0x2c7f000d, 0x018610db,
+ 0x0000001f, 0x00b91612, 0x40000100, 0x20f60000, 0x40000100,
+ 0x20200000, 0x00121820, 0x00000000, 0x00121820, 0x00007f7f,
+ 0x00000000, 0x00000080, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x28000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x64b22427,
+ 0x00766932, 0x00222222, 0x00000000, 0x37644302, 0x2f97d40c,
+ 0x00080740, 0x00020401, 0x0000907f, 0x20010201, 0xa0633333,
+ 0x3333bc43, 0x7a8f5b6b, 0xcc979975, 0x00000000, 0x80608000,
+ 0x00000000, 0x00027293, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x6437140a, 0x00000000, 0x00000000, 0x30032064,
+ 0x4653de68, 0x04518a3c, 0x00002101, 0x2a201c16, 0x1812362e,
+ 0x322c2220, 0x000e3c24, 0x2a2a2a2a, 0x2a2a2a2a, 0x03902a2a,
+ 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x00000000,
+ 0x1000dc1f, 0x10008c1f, 0x02140102, 0x681604c2, 0x01007c00,
+ 0x01004800, 0xfb000000, 0x000028d1, 0x1000dc1f, 0x10008c1f,
+ 0x02140102, 0x28160d05, 0x00000008, 0x001b25a4, 0x631b25a0,
+ 0x631b25a0, 0x081b25a0, 0x081b25a0, 0x081b25a0, 0x081b25a0,
+ 0x631b25a0, 0x081b25a0, 0x631b25a0, 0x631b25a0, 0x631b25a0,
+ 0x631b25a0, 0x001b25a0, 0x001b25a0, 0x6b1b25a0, 0x00000003,
+ 0x00000000, 0x00000300
+};
+
+static const uint32_t rtl8188ce_agc_vals[] = {
+ 0x7b000001, 0x7b010001, 0x7b020001, 0x7b030001, 0x7b040001,
+ 0x7b050001, 0x7a060001, 0x79070001, 0x78080001, 0x77090001,
+ 0x760a0001, 0x750b0001, 0x740c0001, 0x730d0001, 0x720e0001,
+ 0x710f0001, 0x70100001, 0x6f110001, 0x6e120001, 0x6d130001,
+ 0x6c140001, 0x6b150001, 0x6a160001, 0x69170001, 0x68180001,
+ 0x67190001, 0x661a0001, 0x651b0001, 0x641c0001, 0x631d0001,
+ 0x621e0001, 0x611f0001, 0x60200001, 0x49210001, 0x48220001,
+ 0x47230001, 0x46240001, 0x45250001, 0x44260001, 0x43270001,
+ 0x42280001, 0x41290001, 0x402a0001, 0x262b0001, 0x252c0001,
+ 0x242d0001, 0x232e0001, 0x222f0001, 0x21300001, 0x20310001,
+ 0x06320001, 0x05330001, 0x04340001, 0x03350001, 0x02360001,
+ 0x01370001, 0x00380001, 0x00390001, 0x003a0001, 0x003b0001,
+ 0x003c0001, 0x003d0001, 0x003e0001, 0x003f0001, 0x7b400001,
+ 0x7b410001, 0x7b420001, 0x7b430001, 0x7b440001, 0x7b450001,
+ 0x7a460001, 0x79470001, 0x78480001, 0x77490001, 0x764a0001,
+ 0x754b0001, 0x744c0001, 0x734d0001, 0x724e0001, 0x714f0001,
+ 0x70500001, 0x6f510001, 0x6e520001, 0x6d530001, 0x6c540001,
+ 0x6b550001, 0x6a560001, 0x69570001, 0x68580001, 0x67590001,
+ 0x665a0001, 0x655b0001, 0x645c0001, 0x635d0001, 0x625e0001,
+ 0x615f0001, 0x60600001, 0x49610001, 0x48620001, 0x47630001,
+ 0x46640001, 0x45650001, 0x44660001, 0x43670001, 0x42680001,
+ 0x41690001, 0x406a0001, 0x266b0001, 0x256c0001, 0x246d0001,
+ 0x236e0001, 0x226f0001, 0x21700001, 0x20710001, 0x06720001,
+ 0x05730001, 0x04740001, 0x03750001, 0x02760001, 0x01770001,
+ 0x00780001, 0x00790001, 0x007a0001, 0x007b0001, 0x007c0001,
+ 0x007d0001, 0x007e0001, 0x007f0001, 0x3800001e, 0x3801001e,
+ 0x3802001e, 0x3803001e, 0x3804001e, 0x3805001e, 0x3806001e,
+ 0x3807001e, 0x3808001e, 0x3c09001e, 0x3e0a001e, 0x400b001e,
+ 0x440c001e, 0x480d001e, 0x4c0e001e, 0x500f001e, 0x5210001e,
+ 0x5611001e, 0x5a12001e, 0x5e13001e, 0x6014001e, 0x6015001e,
+ 0x6016001e, 0x6217001e, 0x6218001e, 0x6219001e, 0x621a001e,
+ 0x621b001e, 0x621c001e, 0x621d001e, 0x621e001e, 0x621f001e
+};
+
+static const struct rtwn_bb_prog rtl8188ce_bb_prog = {
+ nitems(rtl8192ce_bb_regs),
+ rtl8192ce_bb_regs,
+ rtl8188ce_bb_vals,
+ nitems(rtl8188ce_agc_vals),
+ rtl8188ce_agc_vals
+};
+
+static const uint32_t rtl8188cu_bb_vals[] = {
+ 0x0011800d, 0x00ffdb83, 0x80040000, 0x00000001, 0x0000fc00,
+ 0x0000000a, 0x10005388, 0x020c3d10, 0x02200385, 0x00000000,
+ 0x01000100, 0x00390004, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00010000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x569a569a,
+ 0x001b25a4, 0x66e60230, 0x061f0130, 0x00000000, 0x32323200,
+ 0x07000700, 0x22004000, 0x00000808, 0x00000000, 0xc0083070,
+ 0x000004d5, 0x00000000, 0xccc000c0, 0x00000800, 0xfffffffe,
+ 0x40302010, 0x00706050, 0x00000000, 0x00000023, 0x00000000,
+ 0x81121111, 0x00d047c8, 0x80ff000c, 0x8c838300, 0x2e68120f,
+ 0x9500bb78, 0x11144028, 0x00881117, 0x89140f00, 0x1a1b0000,
+ 0x090e1317, 0x00000204, 0x00d30000, 0x101fbf00, 0x00000007,
+ 0x48071d40, 0x03a05611, 0x000000e4, 0x6c6c6c6c, 0x08800000,
+ 0x40000100, 0x08800000, 0x40000100, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x69e9ac44, 0x469652cf, 0x49795994,
+ 0x0a97971c, 0x1f7c403f, 0x000100b7, 0xec020107, 0x007f037f,
+ 0x6954341e, 0x43bc0094, 0x6954341e, 0x433c0094, 0x00000000,
+ 0x5116848b, 0x47c00bff, 0x00000036, 0x2c7f000d, 0x018610db,
+ 0x0000001f, 0x00b91612, 0x40000100, 0x20f60000, 0x40000100,
+ 0x20200000, 0x00121820, 0x00000000, 0x00121820, 0x00007f7f,
+ 0x00000000, 0x00000080, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x28000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x64b22427,
+ 0x00766932, 0x00222222, 0x00000000, 0x37644302, 0x2f97d40c,
+ 0x00080740, 0x00020401, 0x0000907f, 0x20010201, 0xa0633333,
+ 0x3333bc43, 0x7a8f5b6b, 0xcc979975, 0x00000000, 0x80608000,
+ 0x00000000, 0x00027293, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x6437140a, 0x00000000, 0x00000000, 0x30032064,
+ 0x4653de68, 0x04518a3c, 0x00002101, 0x2a201c16, 0x1812362e,
+ 0x322c2220, 0x000e3c24, 0x2a2a2a2a, 0x2a2a2a2a, 0x03902a2a,
+ 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x00000000,
+ 0x1000dc1f, 0x10008c1f, 0x02140102, 0x681604c2, 0x01007c00,
+ 0x01004800, 0xfb000000, 0x000028d1, 0x1000dc1f, 0x10008c1f,
+ 0x02140102, 0x28160d05, 0x00000008, 0x001b25a4, 0x631b25a0,
+ 0x631b25a0, 0x081b25a0, 0x081b25a0, 0x081b25a0, 0x081b25a0,
+ 0x631b25a0, 0x081b25a0, 0x631b25a0, 0x631b25a0, 0x631b25a0,
+ 0x631b25a0, 0x001b25a0, 0x001b25a0, 0x6b1b25a0, 0x00000003,
+ 0x00000000, 0x00000300
+};
+
+static const struct rtwn_bb_prog rtl8188cu_bb_prog = {
+ nitems(rtl8192ce_bb_regs),
+ rtl8192ce_bb_regs,
+ rtl8188cu_bb_vals,
+ nitems(rtl8188ce_agc_vals),
+ rtl8188ce_agc_vals
+};
+
+/*
+ * RTL8188RU.
+ */
+static const uint16_t rtl8188ru_bb_regs[] = {
+ 0x024, 0x028, 0x040, 0x800, 0x804, 0x808, 0x80c, 0x810, 0x814,
+ 0x818, 0x81c, 0x820, 0x824, 0x828, 0x82c, 0x830, 0x834, 0x838,
+ 0x83c, 0x840, 0x844, 0x848, 0x84c, 0x850, 0x854, 0x858, 0x85c,
+ 0x860, 0x864, 0x868, 0x86c, 0x870, 0x874, 0x878, 0x87c, 0x880,
+ 0x884, 0x888, 0x88c, 0x890, 0x894, 0x898, 0x89c, 0x900, 0x904,
+ 0x908, 0x90c, 0xa00, 0xa04, 0xa08, 0xa0c, 0xa10, 0xa14, 0xa18,
+ 0xa1c, 0xa20, 0xa24, 0xa28, 0xa2c, 0xa70, 0xa74, 0xc00, 0xc04,
+ 0xc08, 0xc0c, 0xc10, 0xc14, 0xc18, 0xc1c, 0xc20, 0xc24, 0xc28,
+ 0xc2c, 0xc30, 0xc34, 0xc38, 0xc3c, 0xc40, 0xc44, 0xc48, 0xc4c,
+ 0xc50, 0xc54, 0xc58, 0xc5c, 0xc60, 0xc64, 0xc68, 0xc6c, 0xc70,
+ 0xc74, 0xc78, 0xc7c, 0xc80, 0xc84, 0xc88, 0xc8c, 0xc90, 0xc94,
+ 0xc98, 0xc9c, 0xca0, 0xca4, 0xca8, 0xcac, 0xcb0, 0xcb4, 0xcb8,
+ 0xcbc, 0xcc0, 0xcc4, 0xcc8, 0xccc, 0xcd0, 0xcd4, 0xcd8, 0xcdc,
+ 0xce0, 0xce4, 0xce8, 0xcec, 0xd00, 0xd04, 0xd08, 0xd0c, 0xd10,
+ 0xd14, 0xd18, 0xd2c, 0xd30, 0xd34, 0xd38, 0xd3c, 0xd40, 0xd44,
+ 0xd48, 0xd4c, 0xd50, 0xd54, 0xd58, 0xd5c, 0xd60, 0xd64, 0xd68,
+ 0xd6c, 0xd70, 0xd74, 0xd78, 0xe00, 0xe04, 0xe08, 0xe10, 0xe14,
+ 0xe18, 0xe1c, 0xe28, 0xe30, 0xe34, 0xe38, 0xe3c, 0xe40, 0xe44,
+ 0xe48, 0xe4c, 0xe50, 0xe54, 0xe58, 0xe5c, 0xe60, 0xe68, 0xe6c,
+ 0xe70, 0xe74, 0xe78, 0xe7c, 0xe80, 0xe84, 0xe88, 0xe8c, 0xed0,
+ 0xed4, 0xed8, 0xedc, 0xee0, 0xeec, 0xee8, 0xf14, 0xf4c, 0xf00
+};
+
+static const uint32_t rtl8188ru_bb_vals[] = {
+ 0x0011800d, 0x00ffdb83, 0x000c0004, 0x80040000, 0x00000001,
+ 0x0000fc00, 0x0000000a, 0x10005388, 0x020c3d10, 0x02200385,
+ 0x00000000, 0x01000100, 0x00390204, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00010000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x569a569a, 0x001b25a4, 0x66e60230, 0x061f0130, 0x00000000,
+ 0x32323200, 0x03000300, 0x22004000, 0x00000808, 0x00ffc3f1,
+ 0xc0083070, 0x000004d5, 0x00000000, 0xccc000c0, 0x00000800,
+ 0xfffffffe, 0x40302010, 0x00706050, 0x00000000, 0x00000023,
+ 0x00000000, 0x81121111, 0x00d047c8, 0x80ff000c, 0x8c838300,
+ 0x2e68120f, 0x9500bb78, 0x11144028, 0x00881117, 0x89140f00,
+ 0x15160000, 0x070b0f12, 0x00000104, 0x00d30000, 0x101fbf00,
+ 0x00000007, 0x48071d40, 0x03a05611, 0x000000e4, 0x6c6c6c6c,
+ 0x08800000, 0x40000100, 0x08800000, 0x40000100, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x69e9ac44, 0x469652cf,
+ 0x49795994, 0x0a97971c, 0x1f7c403f, 0x000100b7, 0xec020107,
+ 0x007f037f, 0x6954342e, 0x43bc0094, 0x6954342f, 0x433c0094,
+ 0x00000000, 0x5116848b, 0x47c00bff, 0x00000036, 0x2c56000d,
+ 0x018610db, 0x0000001f, 0x00b91612, 0x24000090, 0x20f60000,
+ 0x24000090, 0x20200000, 0x00121820, 0x00000000, 0x00121820,
+ 0x00007f7f, 0x00000000, 0x00000080, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x28000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x64b22427, 0x00766932, 0x00222222, 0x00000000, 0x37644302,
+ 0x2f97d40c, 0x00080740, 0x00020401, 0x0000907f, 0x20010201,
+ 0xa0633333, 0x3333bc43, 0x7a8f5b6b, 0xcc979975, 0x00000000,
+ 0x80608000, 0x00000000, 0x00027293, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x6437140a, 0x00000000, 0x00000000,
+ 0x30032064, 0x4653de68, 0x04518a3c, 0x00002101, 0x2a201c16,
+ 0x1812362e, 0x322c2220, 0x000e3c24, 0x2a2a2a2a, 0x2a2a2a2a,
+ 0x03902a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a,
+ 0x00000000, 0x1000dc1f, 0x10008c1f, 0x02140102, 0x681604c2,
+ 0x01007c00, 0x01004800, 0xfb000000, 0x000028d1, 0x1000dc1f,
+ 0x10008c1f, 0x02140102, 0x28160d05, 0x00000010, 0x001b25a4,
+ 0x631b25a0, 0x631b25a0, 0x081b25a0, 0x081b25a0, 0x081b25a0,
+ 0x081b25a0, 0x631b25a0, 0x081b25a0, 0x631b25a0, 0x631b25a0,
+ 0x631b25a0, 0x631b25a0, 0x001b25a0, 0x001b25a0, 0x6b1b25a0,
+ 0x31555448, 0x00000003, 0x00000000, 0x00000300
+};
+
+static const uint32_t rtl8188ru_agc_vals[] = {
+ 0x7b000001, 0x7b010001, 0x7b020001, 0x7b030001, 0x7b040001,
+ 0x7b050001, 0x7b060001, 0x7b070001, 0x7b080001, 0x7a090001,
+ 0x790a0001, 0x780b0001, 0x770c0001, 0x760d0001, 0x750e0001,
+ 0x740f0001, 0x73100001, 0x72110001, 0x71120001, 0x70130001,
+ 0x6f140001, 0x6e150001, 0x6d160001, 0x6c170001, 0x6b180001,
+ 0x6a190001, 0x691a0001, 0x681b0001, 0x671c0001, 0x661d0001,
+ 0x651e0001, 0x641f0001, 0x63200001, 0x62210001, 0x61220001,
+ 0x60230001, 0x46240001, 0x45250001, 0x44260001, 0x43270001,
+ 0x42280001, 0x41290001, 0x402a0001, 0x262b0001, 0x252c0001,
+ 0x242d0001, 0x232e0001, 0x222f0001, 0x21300001, 0x20310001,
+ 0x06320001, 0x05330001, 0x04340001, 0x03350001, 0x02360001,
+ 0x01370001, 0x00380001, 0x00390001, 0x003a0001, 0x003b0001,
+ 0x003c0001, 0x003d0001, 0x003e0001, 0x003f0001, 0x7b400001,
+ 0x7b410001, 0x7b420001, 0x7b430001, 0x7b440001, 0x7b450001,
+ 0x7b460001, 0x7b470001, 0x7b480001, 0x7a490001, 0x794a0001,
+ 0x784b0001, 0x774c0001, 0x764d0001, 0x754e0001, 0x744f0001,
+ 0x73500001, 0x72510001, 0x71520001, 0x70530001, 0x6f540001,
+ 0x6e550001, 0x6d560001, 0x6c570001, 0x6b580001, 0x6a590001,
+ 0x695a0001, 0x685b0001, 0x675c0001, 0x665d0001, 0x655e0001,
+ 0x645f0001, 0x63600001, 0x62610001, 0x61620001, 0x60630001,
+ 0x46640001, 0x45650001, 0x44660001, 0x43670001, 0x42680001,
+ 0x41690001, 0x406a0001, 0x266b0001, 0x256c0001, 0x246d0001,
+ 0x236e0001, 0x226f0001, 0x21700001, 0x20710001, 0x06720001,
+ 0x05730001, 0x04740001, 0x03750001, 0x02760001, 0x01770001,
+ 0x00780001, 0x00790001, 0x007a0001, 0x007b0001, 0x007c0001,
+ 0x007d0001, 0x007e0001, 0x007f0001, 0x3800001e, 0x3801001e,
+ 0x3802001e, 0x3803001e, 0x3804001e, 0x3805001e, 0x3806001e,
+ 0x3807001e, 0x3808001e, 0x3c09001e, 0x3e0a001e, 0x400b001e,
+ 0x440c001e, 0x480d001e, 0x4c0e001e, 0x500f001e, 0x5210001e,
+ 0x5611001e, 0x5a12001e, 0x5e13001e, 0x6014001e, 0x6015001e,
+ 0x6016001e, 0x6217001e, 0x6218001e, 0x6219001e, 0x621a001e,
+ 0x621b001e, 0x621c001e, 0x621d001e, 0x621e001e, 0x621f001e
+};
+
+static const struct rtwn_bb_prog rtl8188ru_bb_prog = {
+ nitems(rtl8188ru_bb_regs),
+ rtl8188ru_bb_regs,
+ rtl8188ru_bb_vals,
+ nitems(rtl8188ru_agc_vals),
+ rtl8188ru_agc_vals
+};
+
+/*
+ * RF initialization values.
+ */
+struct rtwn_rf_prog {
+ int count;
+ const uint8_t *regs;
+ const uint32_t *vals;
+};
+
+/*
+ * RTL8192CU and RTL8192CE-VAU.
+ */
+static const uint8_t rtl8192ce_rf1_regs[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+ 0x0f, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22,
+ 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2a, 0x2b,
+ 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b,
+ 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b,
+ 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a,
+ 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c,
+ 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b,
+ 0x2c, 0x2a, 0x10, 0x11, 0x10, 0x11, 0x10, 0x11, 0x10, 0x11, 0x10,
+ 0x11, 0x10, 0x11, 0x10, 0x11, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13,
+ 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14,
+ 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x00,
+ 0x18, 0xfe, 0xfe, 0x1f, 0xfe, 0xfe, 0x1e, 0x1f, 0x00
+};
+
+static const uint32_t rtl8192ce_rf1_vals[] = {
+ 0x30159, 0x31284, 0x98000, 0x18c63, 0x210e7, 0x2044f, 0x1adb1,
+ 0x54867, 0x8992e, 0x0e52c, 0x39ce7, 0x00451, 0x00000, 0x10255,
+ 0x60a00, 0xfc378, 0xa1250, 0x4445f, 0x80001, 0x0b614, 0x6c000,
+ 0x00000, 0x01558, 0x00060, 0x00483, 0x4f000, 0xec7d9, 0x577c0,
+ 0x04783, 0x00001, 0x21334, 0x00000, 0x00054, 0x00001, 0x00808,
+ 0x53333, 0x0000c, 0x00002, 0x00808, 0x5b333, 0x0000d, 0x00003,
+ 0x00808, 0x63333, 0x0000d, 0x00004, 0x00808, 0x6b333, 0x0000d,
+ 0x00005, 0x00808, 0x73333, 0x0000d, 0x00006, 0x00709, 0x5b333,
+ 0x0000d, 0x00007, 0x00709, 0x63333, 0x0000d, 0x00008, 0x0060a,
+ 0x4b333, 0x0000d, 0x00009, 0x0060a, 0x53333, 0x0000d, 0x0000a,
+ 0x0060a, 0x5b333, 0x0000d, 0x0000b, 0x0060a, 0x63333, 0x0000d,
+ 0x0000c, 0x0060a, 0x6b333, 0x0000d, 0x0000d, 0x0060a, 0x73333,
+ 0x0000d, 0x0000e, 0x0050b, 0x66666, 0x0001a, 0xe0000, 0x4000f,
+ 0xe31fc, 0x6000f, 0xff9f8, 0x2000f, 0x203f9, 0x3000f, 0xff500,
+ 0x00000, 0x00000, 0x8000f, 0x3f100, 0x9000f, 0x23100, 0x32000,
+ 0x71000, 0xb0000, 0xfc000, 0x287af, 0x244b7, 0x204ab, 0x1c49f,
+ 0x18493, 0x14297, 0x10295, 0x0c298, 0x0819c, 0x040a8, 0x0001c,
+ 0x1944c, 0x59444, 0x9944c, 0xd9444, 0x0f424, 0x4f424, 0x8f424,
+ 0xcf424, 0xe0330, 0xa0330, 0x60330, 0x20330, 0x10159, 0x0f401,
+ 0x00000, 0x00000, 0x80003, 0x00000, 0x00000, 0x44457, 0x80000,
+ 0x30159
+};
+
+static const uint8_t rtl8192ce_rf2_regs[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+ 0x0f, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
+ 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15,
+ 0x15, 0x15, 0x16, 0x16, 0x16, 0x16
+};
+
+static const uint32_t rtl8192ce_rf2_vals[] = {
+ 0x30159, 0x31284, 0x98000, 0x18c63, 0x210e7, 0x2044f, 0x1adb1,
+ 0x54867, 0x8992e, 0x0e52c, 0x39ce7, 0x00451, 0x32000, 0x71000,
+ 0xb0000, 0xfc000, 0x287af, 0x244b7, 0x204ab, 0x1c49f, 0x18493,
+ 0x14297, 0x10295, 0x0c298, 0x0819c, 0x040a8, 0x0001c, 0x1944c,
+ 0x59444, 0x9944c, 0xd9444, 0x0f424, 0x4f424, 0x8f424, 0xcf424,
+ 0xe0330, 0xa0330, 0x60330, 0x20330
+};
+
+static const struct rtwn_rf_prog rtl8192ce_rf_prog[] = {
+ {
+ nitems(rtl8192ce_rf1_regs),
+ rtl8192ce_rf1_regs,
+ rtl8192ce_rf1_vals
+ },
+ {
+ nitems(rtl8192ce_rf2_regs),
+ rtl8192ce_rf2_regs,
+ rtl8192ce_rf2_vals
+ }
+};
+
+/*
+ * RTL8188CE-VAU.
+ */
+static const uint32_t rtl8188ce_rf_vals[] = {
+ 0x30159, 0x31284, 0x98000, 0x18c63, 0x210e7, 0x2044f, 0x1adb1,
+ 0x54867, 0x8992e, 0x0e52c, 0x39ce7, 0x00451, 0x00000, 0x10255,
+ 0x60a00, 0xfc378, 0xa1250, 0x4445f, 0x80001, 0x0b614, 0x6c000,
+ 0x00000, 0x01558, 0x00060, 0x00483, 0x4f200, 0xec7d9, 0x577c0,
+ 0x04783, 0x00001, 0x21334, 0x00000, 0x00054, 0x00001, 0x00808,
+ 0x53333, 0x0000c, 0x00002, 0x00808, 0x5b333, 0x0000d, 0x00003,
+ 0x00808, 0x63333, 0x0000d, 0x00004, 0x00808, 0x6b333, 0x0000d,
+ 0x00005, 0x00808, 0x73333, 0x0000d, 0x00006, 0x00709, 0x5b333,
+ 0x0000d, 0x00007, 0x00709, 0x63333, 0x0000d, 0x00008, 0x0060a,
+ 0x4b333, 0x0000d, 0x00009, 0x0060a, 0x53333, 0x0000d, 0x0000a,
+ 0x0060a, 0x5b333, 0x0000d, 0x0000b, 0x0060a, 0x63333, 0x0000d,
+ 0x0000c, 0x0060a, 0x6b333, 0x0000d, 0x0000d, 0x0060a, 0x73333,
+ 0x0000d, 0x0000e, 0x0050b, 0x66666, 0x0001a, 0xe0000, 0x4000f,
+ 0xe31fc, 0x6000f, 0xff9f8, 0x2000f, 0x203f9, 0x3000f, 0xff500,
+ 0x00000, 0x00000, 0x8000f, 0x3f100, 0x9000f, 0x23100, 0x32000,
+ 0x71000, 0xb0000, 0xfc000, 0x287b3, 0x244b7, 0x204ab, 0x1c49f,
+ 0x18493, 0x1429b, 0x10299, 0x0c29c, 0x081a0, 0x040ac, 0x00020,
+ 0x1944c, 0x59444, 0x9944c, 0xd9444, 0x0f424, 0x4f424, 0x8f424,
+ 0xcf424, 0xe0330, 0xa0330, 0x60330, 0x20330, 0x10159, 0x0f401,
+ 0x00000, 0x00000, 0x80003, 0x00000, 0x00000, 0x44457, 0x80000,
+ 0x30159
+};
+
+static const struct rtwn_rf_prog rtl8188ce_rf_prog[] = {
+ {
+ nitems(rtl8192ce_rf1_regs),
+ rtl8192ce_rf1_regs,
+ rtl8188ce_rf_vals
+ }
+};
+
+
+/*
+ * RTL8188CU.
+ */
+static const uint32_t rtl8188cu_rf_vals[] = {
+ 0x30159, 0x31284, 0x98000, 0x18c63, 0x210e7, 0x2044f, 0x1adb1,
+ 0x54867, 0x8992e, 0x0e52c, 0x39ce7, 0x00451, 0x00000, 0x10255,
+ 0x60a00, 0xfc378, 0xa1250, 0x4445f, 0x80001, 0x0b614, 0x6c000,
+ 0x00000, 0x01558, 0x00060, 0x00483, 0x4f000, 0xec7d9, 0x577c0,
+ 0x04783, 0x00001, 0x21334, 0x00000, 0x00054, 0x00001, 0x00808,
+ 0x53333, 0x0000c, 0x00002, 0x00808, 0x5b333, 0x0000d, 0x00003,
+ 0x00808, 0x63333, 0x0000d, 0x00004, 0x00808, 0x6b333, 0x0000d,
+ 0x00005, 0x00808, 0x73333, 0x0000d, 0x00006, 0x00709, 0x5b333,
+ 0x0000d, 0x00007, 0x00709, 0x63333, 0x0000d, 0x00008, 0x0060a,
+ 0x4b333, 0x0000d, 0x00009, 0x0060a, 0x53333, 0x0000d, 0x0000a,
+ 0x0060a, 0x5b333, 0x0000d, 0x0000b, 0x0060a, 0x63333, 0x0000d,
+ 0x0000c, 0x0060a, 0x6b333, 0x0000d, 0x0000d, 0x0060a, 0x73333,
+ 0x0000d, 0x0000e, 0x0050b, 0x66666, 0x0001a, 0xe0000, 0x4000f,
+ 0xe31fc, 0x6000f, 0xff9f8, 0x2000f, 0x203f9, 0x3000f, 0xff500,
+ 0x00000, 0x00000, 0x8000f, 0x3f100, 0x9000f, 0x23100, 0x32000,
+ 0x71000, 0xb0000, 0xfc000, 0x287b3, 0x244b7, 0x204ab, 0x1c49f,
+ 0x18493, 0x1429b, 0x10299, 0x0c29c, 0x081a0, 0x040ac, 0x00020,
+ 0x1944c, 0x59444, 0x9944c, 0xd9444, 0x0f405, 0x4f405, 0x8f405,
+ 0xcf405, 0xe0330, 0xa0330, 0x60330, 0x20330, 0x10159, 0x0f401,
+ 0x00000, 0x00000, 0x80003, 0x00000, 0x00000, 0x44457, 0x80000,
+ 0x30159
+};
+
+static const struct rtwn_rf_prog rtl8188cu_rf_prog[] = {
+ {
+ nitems(rtl8192ce_rf1_regs),
+ rtl8192ce_rf1_regs,
+ rtl8188cu_rf_vals
+ }
+};
+
+/*
+ * RTL8188RU.
+ */
+static const uint32_t rtl8188ru_rf_vals[] = {
+ 0x30159, 0x31284, 0x98000, 0x18c63, 0x210e7, 0x2044f, 0x1adb0,
+ 0x54867, 0x8992e, 0x0e529, 0x39ce7, 0x00451, 0x00000, 0x00255,
+ 0x60a00, 0xfc378, 0xa1250, 0x4445f, 0x80001, 0x0b614, 0x6c000,
+ 0x0083c, 0x01558, 0x00060, 0x00483, 0x4f000, 0xec7d9, 0x977c0,
+ 0x04783, 0x00001, 0x21334, 0x00000, 0x00054, 0x00001, 0x00808,
+ 0x53333, 0x0000c, 0x00002, 0x00808, 0x5b333, 0x0000d, 0x00003,
+ 0x00808, 0x63333, 0x0000d, 0x00004, 0x00808, 0x6b333, 0x0000d,
+ 0x00005, 0x00808, 0x73333, 0x0000d, 0x00006, 0x00709, 0x5b333,
+ 0x0000d, 0x00007, 0x00709, 0x63333, 0x0000d, 0x00008, 0x0060a,
+ 0x4b333, 0x0000d, 0x00009, 0x0060a, 0x53333, 0x0000d, 0x0000a,
+ 0x0060a, 0x5b333, 0x0000d, 0x0000b, 0x0060a, 0x63333, 0x0000d,
+ 0x0000c, 0x0060a, 0x6b333, 0x0000d, 0x0000d, 0x0060a, 0x73333,
+ 0x0000d, 0x0000e, 0x0050b, 0x66666, 0x0001a, 0xe0000, 0x4000f,
+ 0xe31fc, 0x6000f, 0xff9f8, 0x2000f, 0x203f9, 0x3000f, 0xff500,
+ 0x00000, 0x00000, 0x8000f, 0x3f100, 0x9000f, 0x23100, 0xd8000,
+ 0x90000, 0x51000, 0x12000, 0x28fb4, 0x24fa8, 0x207a4, 0x1c798,
+ 0x183a4, 0x14398, 0x101a4, 0x0c198, 0x080a4, 0x04098, 0x00014,
+ 0x1944c, 0x59444, 0x9944c, 0xd9444, 0x0f405, 0x4f405, 0x8f405,
+ 0xcf405, 0xe0330, 0xa0330, 0x60330, 0x20330, 0x10159, 0x0f401,
+ 0x00000, 0x00000, 0x80003, 0x00000, 0x00000, 0x44457, 0x80000,
+ 0x30159
+};
+
+static const struct rtwn_rf_prog rtl8188ru_rf_prog[] = {
+ {
+ nitems(rtl8192ce_rf1_regs),
+ rtl8192ce_rf1_regs,
+ rtl8188ru_rf_vals
+ }
+};
+
+struct rtwn_txpwr {
+ uint8_t pwr[3][28];
+};
+
+/*
+ * Per RF chain/group/rate Tx gain values.
+ */
+static const struct rtwn_txpwr rtl8192cu_txagc[] = {
+ { { /* Chain 0. */
+ { /* Group 0. */
+ 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */
+ 0x0c, 0x0c, 0x0c, 0x0a, 0x08, 0x06, 0x04, 0x02, /* OFDM6~54. */
+ 0x0e, 0x0d, 0x0c, 0x0a, 0x08, 0x06, 0x04, 0x02, /* MCS0~7. */
+ 0x0e, 0x0d, 0x0c, 0x0a, 0x08, 0x06, 0x04, 0x02 /* MCS8~15. */
+ },
+ { /* Group 1. */
+ 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */
+ },
+ { /* Group 2. */
+ 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x00, /* OFDM6~54. */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */
+ }
+ } },
+ { { /* Chain 1. */
+ { /* Group 0. */
+ 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */
+ },
+ { /* Group 1. */
+ 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */
+ },
+ { /* Group 2. */
+ 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x00, /* OFDM6~54. */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */
+ }
+ } }
+};
+
+static const struct rtwn_txpwr rtl8188ru_txagc[] = {
+ { { /* Chain 0. */
+ { /* Group 0. */
+ 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */
+ 0x08, 0x08, 0x08, 0x06, 0x06, 0x04, 0x04, 0x00, /* OFDM6~54. */
+ 0x08, 0x06, 0x06, 0x04, 0x04, 0x02, 0x02, 0x00, /* MCS0~7. */
+ 0x08, 0x06, 0x06, 0x04, 0x04, 0x02, 0x02, 0x00 /* MCS8~15. */
+ },
+ { /* Group 1. */
+ 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */
+ },
+ { /* Group 2. */
+ 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */
+ }
+ } }
+};
+
+#define RTWN_LOCK_INIT(_sc) \
+ mtx_init(&(_sc)->sc_mtx, device_get_nameunit((_sc)->sc_dev), \
+ MTX_NETWORK_LOCK, MTX_DEF)
+#define RTWN_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
+#define RTWN_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED)
+#define RTWN_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
+#define RTWN_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx)
+
diff --git a/sys/dev/usb/net/if_axe.c b/sys/dev/usb/net/if_axe.c
index 1995497..aa1ce0e 100644
--- a/sys/dev/usb/net/if_axe.c
+++ b/sys/dev/usb/net/if_axe.c
@@ -175,6 +175,7 @@ static const STRUCT_USB_HOST_ID axe_devs[] = {
AXE_DEV(PLANEX3, GU1000T, AXE_FLAG_178),
AXE_DEV(SITECOM, LN029, 0),
AXE_DEV(SITECOMEU, LN028, AXE_FLAG_178),
+ AXE_DEV(SITECOMEU, LN031, AXE_FLAG_178),
AXE_DEV(SYSTEMTALKS, SGCX2UL, 0),
#undef AXE_DEV
};
diff --git a/sys/dev/usb/usbdevs b/sys/dev/usb/usbdevs
index 42ba9c1..2a55e7c 100644
--- a/sys/dev/usb/usbdevs
+++ b/sys/dev/usb/usbdevs
@@ -4203,6 +4203,7 @@ product SITECOMEU RTL8188CU_1 0x0052 RTL8188CU
product SITECOMEU RTL8188CU_2 0x005c RTL8188CU
product SITECOMEU RTL8192CU 0x0061 RTL8192CU
product SITECOMEU LN032 0x0072 LN-032
+product SITECOMEU LN031 0x0056 LN-031
product SITECOMEU LN028 0x061c LN-028
product SITECOMEU WL113 0x9071 WL-113
product SITECOMEU ZD1211B 0x9075 ZD1211B
diff --git a/sys/fs/nullfs/null_vnops.c b/sys/fs/nullfs/null_vnops.c
index 4762a3c..72b884f 100644
--- a/sys/fs/nullfs/null_vnops.c
+++ b/sys/fs/nullfs/null_vnops.c
@@ -568,14 +568,16 @@ static int
null_remove(struct vop_remove_args *ap)
{
int retval, vreleit;
- struct vnode *lvp;
+ struct vnode *lvp, *vp;
- if (vrefcnt(ap->a_vp) > 1) {
- lvp = NULLVPTOLOWERVP(ap->a_vp);
+ vp = ap->a_vp;
+ if (vrefcnt(vp) > 1) {
+ lvp = NULLVPTOLOWERVP(vp);
VREF(lvp);
vreleit = 1;
} else
vreleit = 0;
+ VTONULL(vp)->null_flags |= NULLV_DROP;
retval = null_bypass(&ap->a_gen);
if (vreleit != 0)
vrele(lvp);
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
index 1b3b7eb..0fad8aa 100644
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -311,6 +311,8 @@ SUBDIR= \
re \
reiserfs \
rl \
+ rtwn \
+ rtwnfw \
${_s3} \
${_safe} \
${_sbni} \
diff --git a/sys/modules/rtwnfw/Makefile b/sys/modules/rtwnfw/Makefile
new file mode 100644
index 0000000..7a679df
--- /dev/null
+++ b/sys/modules/rtwnfw/Makefile
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+SUBDIR= rtwnrtl8192cU rtwnrtl8192cUB
+
+.include <bsd.subdir.mk>
diff --git a/sys/modules/rtwnfw/Makefile.inc b/sys/modules/rtwnfw/Makefile.inc
new file mode 100644
index 0000000..ce5bcee
--- /dev/null
+++ b/sys/modules/rtwnfw/Makefile.inc
@@ -0,0 +1,15 @@
+# $FreeBSD$
+#
+# Common rules for building firmware. Note this gets auto-included
+# by the subdir Makefile's as a consequence of included bsd.kmod.mk.
+
+_FIRM= ${IMG}.fw
+
+CLEANFILES+= ${_FIRM}
+
+FIRMWS= ${_FIRM}:${KMOD}:111
+
+FIRMWARE_LICENSE= realtek
+
+${_FIRM}: ${.CURDIR}/../../../contrib/dev/rtwn/${_FIRM}.uu
+ uudecode -p $? > ${.TARGET}
diff --git a/sys/modules/rtwnfw/rtwnrtl8192cU/Makefile b/sys/modules/rtwnfw/rtwnrtl8192cU/Makefile
new file mode 100644
index 0000000..643a30f
--- /dev/null
+++ b/sys/modules/rtwnfw/rtwnrtl8192cU/Makefile
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+KMOD= rtwn-rtl8192cfwU
+IMG= rtwn-rtl8192cfwU
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/rtwnfw/rtwnrtl8192cUB/Makefile b/sys/modules/rtwnfw/rtwnrtl8192cUB/Makefile
new file mode 100644
index 0000000..eb878d4
--- /dev/null
+++ b/sys/modules/rtwnfw/rtwnrtl8192cUB/Makefile
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+KMOD= rtwn-rtl8192cfwU_B
+IMG= rtwn-rtl8192cfwU_B
+
+.include <bsd.kmod.mk>
diff --git a/sys/net/bpf.c b/sys/net/bpf.c
index 37edbe8..661a1cf 100644
--- a/sys/net/bpf.c
+++ b/sys/net/bpf.c
@@ -69,6 +69,7 @@ __FBSDID("$FreeBSD$");
#include <net/if.h>
#include <net/if_var.h>
+#include <net/if_dl.h>
#include <net/bpf.h>
#include <net/bpf_buffer.h>
#ifdef BPF_JITTER
@@ -76,6 +77,7 @@ __FBSDID("$FreeBSD$");
#endif
#include <net/bpf_zerocopy.h>
#include <net/bpfdesc.h>
+#include <net/route.h>
#include <net/vnet.h>
#include <netinet/in.h>
@@ -164,7 +166,7 @@ static void bpf_detachd(struct bpf_d *);
static void bpf_detachd_locked(struct bpf_d *);
static void bpf_freed(struct bpf_d *);
static int bpf_movein(struct uio *, int, struct ifnet *, struct mbuf **,
- struct sockaddr *, int *, struct bpf_insn *);
+ struct sockaddr *, int *, struct bpf_d *);
static int bpf_setif(struct bpf_d *, struct ifreq *);
static void bpf_timed_out(void *);
static __inline void
@@ -454,7 +456,7 @@ bpf_ioctl_setzbuf(struct thread *td, struct bpf_d *d, struct bpf_zbuf *bz)
*/
static int
bpf_movein(struct uio *uio, int linktype, struct ifnet *ifp, struct mbuf **mp,
- struct sockaddr *sockp, int *hdrlen, struct bpf_insn *wfilter)
+ struct sockaddr *sockp, int *hdrlen, struct bpf_d *d)
{
const struct ieee80211_bpf_params *p;
struct ether_header *eh;
@@ -549,7 +551,7 @@ bpf_movein(struct uio *uio, int linktype, struct ifnet *ifp, struct mbuf **mp,
if (error)
goto bad;
- slen = bpf_filter(wfilter, mtod(m, u_char *), len, len);
+ slen = bpf_filter(d->bd_wfilter, mtod(m, u_char *), len, len);
if (slen == 0) {
error = EPERM;
goto bad;
@@ -566,6 +568,10 @@ bpf_movein(struct uio *uio, int linktype, struct ifnet *ifp, struct mbuf **mp,
else
m->m_flags |= M_MCAST;
}
+ if (d->bd_hdrcmplt == 0) {
+ memcpy(eh->ether_shost, IF_LLADDR(ifp),
+ sizeof(eh->ether_shost));
+ }
break;
}
@@ -1088,6 +1094,7 @@ bpfwrite(struct cdev *dev, struct uio *uio, int ioflag)
struct ifnet *ifp;
struct mbuf *m, *mc;
struct sockaddr dst;
+ struct route ro;
int error, hlen;
error = devfs_get_cdevpriv((void **)&d);
@@ -1119,7 +1126,7 @@ bpfwrite(struct cdev *dev, struct uio *uio, int ioflag)
hlen = 0;
/* XXX: bpf_movein() can sleep */
error = bpf_movein(uio, (int)d->bd_bif->bif_dlt, ifp,
- &m, &dst, &hlen, d->bd_wfilter);
+ &m, &dst, &hlen, d);
if (error) {
d->bd_wdcount++;
return (error);
@@ -1151,7 +1158,14 @@ bpfwrite(struct cdev *dev, struct uio *uio, int ioflag)
BPFD_UNLOCK(d);
#endif
- error = (*ifp->if_output)(ifp, m, &dst, NULL);
+ bzero(&ro, sizeof(ro));
+ if (hlen != 0) {
+ ro.ro_prepend = (u_char *)&dst.sa_data;
+ ro.ro_plen = hlen;
+ ro.ro_flags = RT_HAS_HEADER;
+ }
+
+ error = (*ifp->if_output)(ifp, m, &dst, &ro);
if (error)
d->bd_wdcount++;
diff --git a/sys/net/flowtable.c b/sys/net/flowtable.c
index a165843..f45a687 100644
--- a/sys/net/flowtable.c
+++ b/sys/net/flowtable.c
@@ -665,6 +665,7 @@ int
flowtable_lookup(sa_family_t sa, struct mbuf *m, struct route *ro)
{
struct flentry *fle;
+ struct llentry *lle;
if (V_flowtable_enable == 0)
return (ENXIO);
@@ -693,8 +694,15 @@ flowtable_lookup(sa_family_t sa, struct mbuf *m, struct route *ro)
}
ro->ro_rt = fle->f_rt;
- ro->ro_lle = fle->f_lle;
ro->ro_flags |= RT_NORTREF;
+ lle = fle->f_lle;
+ if (lle != NULL && (lle->la_flags & LLE_VALID)) {
+ ro->ro_prepend = lle->r_linkdata;
+ ro->ro_plen = lle->r_hdrlen;
+ ro->ro_flags |= RT_MAY_LOOP;
+ if (lle->la_flags & LLE_IFADDR)
+ ro->ro_flags |= RT_L2_ME;
+ }
return (0);
}
diff --git a/sys/net/if.c b/sys/net/if.c
index 39656ef..b9e524c 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -161,6 +161,7 @@ static int ifconf(u_long, caddr_t);
static void if_freemulti(struct ifmultiaddr *);
static void if_grow(void);
static void if_input_default(struct ifnet *, struct mbuf *);
+static int if_requestencap_default(struct ifnet *, struct if_encap_req *);
static void if_route(struct ifnet *, int flag, int fam);
static int if_setflag(struct ifnet *, int, int, int *, int);
static int if_transmit(struct ifnet *ifp, struct mbuf *m);
@@ -673,6 +674,9 @@ if_attach_internal(struct ifnet *ifp, int vmove, struct if_clone *ifc)
if (ifp->if_input == NULL)
ifp->if_input = if_input_default;
+ if (ifp->if_requestencap == NULL)
+ ifp->if_requestencap = if_requestencap_default;
+
if (!vmove) {
#ifdef MAC
mac_ifnet_create(ifp);
@@ -3398,6 +3402,43 @@ if_setlladdr(struct ifnet *ifp, const u_char *lladdr, int len)
}
/*
+ * Compat function for handling basic encapsulation requests.
+ * Not converted stacks (FDDI, IB, ..) supports traditional
+ * output model: ARP (and other similar L2 protocols) are handled
+ * inside output routine, arpresolve/nd6_resolve() returns MAC
+ * address instead of full prepend.
+ *
+ * This function creates calculated header==MAC for IPv4/IPv6 and
+ * returns EAFNOSUPPORT (which is then handled in ARP code) for other
+ * address families.
+ */
+static int
+if_requestencap_default(struct ifnet *ifp, struct if_encap_req *req)
+{
+
+ if (req->rtype != IFENCAP_LL)
+ return (EOPNOTSUPP);
+
+ if (req->bufsize < req->lladdr_len)
+ return (ENOMEM);
+
+ switch (req->family) {
+ case AF_INET:
+ case AF_INET6:
+ break;
+ default:
+ return (EAFNOSUPPORT);
+ }
+
+ /* Copy lladdr to storage as is */
+ memmove(req->buf, req->lladdr, req->lladdr_len);
+ req->bufsize = req->lladdr_len;
+ req->lladdr_off = 0;
+
+ return (0);
+}
+
+/*
* The name argument must be a pointer to storage which will last as
* long as the interface does. For physical devices, the result of
* device_get_name(dev) is a good choice and for pseudo-devices a
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
index 71e28ea..5186406 100644
--- a/sys/net/if_ethersubr.c
+++ b/sys/net/if_ethersubr.c
@@ -113,6 +113,7 @@ static int ether_resolvemulti(struct ifnet *, struct sockaddr **,
#ifdef VIMAGE
static void ether_reassign(struct ifnet *, struct vnet *, char *);
#endif
+static int ether_requestencap(struct ifnet *, struct if_encap_req *);
#define ETHER_IS_BROADCAST(addr) \
(bcmp(etherbroadcastaddr, (addr), ETHER_ADDR_LEN) == 0)
@@ -136,6 +137,138 @@ update_mbuf_csumflags(struct mbuf *src, struct mbuf *dst)
}
/*
+ * Handle link-layer encapsulation requests.
+ */
+static int
+ether_requestencap(struct ifnet *ifp, struct if_encap_req *req)
+{
+ struct ether_header *eh;
+ struct arphdr *ah;
+ uint16_t etype;
+ const u_char *lladdr;
+
+ if (req->rtype != IFENCAP_LL)
+ return (EOPNOTSUPP);
+
+ if (req->bufsize < ETHER_HDR_LEN)
+ return (ENOMEM);
+
+ eh = (struct ether_header *)req->buf;
+ lladdr = req->lladdr;
+ req->lladdr_off = 0;
+
+ switch (req->family) {
+ case AF_INET:
+ etype = htons(ETHERTYPE_IP);
+ break;
+ case AF_INET6:
+ etype = htons(ETHERTYPE_IPV6);
+ break;
+ case AF_ARP:
+ ah = (struct arphdr *)req->hdata;
+ ah->ar_hrd = htons(ARPHRD_ETHER);
+
+ switch(ntohs(ah->ar_op)) {
+ case ARPOP_REVREQUEST:
+ case ARPOP_REVREPLY:
+ etype = htons(ETHERTYPE_REVARP);
+ break;
+ case ARPOP_REQUEST:
+ case ARPOP_REPLY:
+ default:
+ etype = htons(ETHERTYPE_ARP);
+ break;
+ }
+
+ if (req->flags & IFENCAP_FLAG_BROADCAST)
+ lladdr = ifp->if_broadcastaddr;
+ break;
+ default:
+ return (EAFNOSUPPORT);
+ }
+
+ memcpy(&eh->ether_type, &etype, sizeof(eh->ether_type));
+ memcpy(eh->ether_dhost, lladdr, ETHER_ADDR_LEN);
+ memcpy(eh->ether_shost, IF_LLADDR(ifp), ETHER_ADDR_LEN);
+ req->bufsize = sizeof(struct ether_header);
+
+ return (0);
+}
+
+
+static int
+ether_resolve_addr(struct ifnet *ifp, struct mbuf *m,
+ const struct sockaddr *dst, struct route *ro, u_char *phdr,
+ uint32_t *pflags)
+{
+ struct ether_header *eh;
+ struct rtentry *rt;
+ uint32_t lleflags = 0;
+ int error = 0;
+#if defined(INET) || defined(INET6)
+ uint16_t etype;
+#endif
+
+ eh = (struct ether_header *)phdr;
+
+ switch (dst->sa_family) {
+#ifdef INET
+ case AF_INET:
+ if ((m->m_flags & (M_BCAST | M_MCAST)) == 0)
+ error = arpresolve(ifp, 0, m, dst, phdr, &lleflags);
+ else {
+ if (m->m_flags & M_BCAST)
+ memcpy(eh->ether_dhost, ifp->if_broadcastaddr,
+ ETHER_ADDR_LEN);
+ else {
+ const struct in_addr *a;
+ a = &(((const struct sockaddr_in *)dst)->sin_addr);
+ ETHER_MAP_IP_MULTICAST(a, eh->ether_dhost);
+ }
+ etype = htons(ETHERTYPE_IP);
+ memcpy(&eh->ether_type, &etype, sizeof(etype));
+ memcpy(eh->ether_shost, IF_LLADDR(ifp), ETHER_ADDR_LEN);
+ }
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ if ((m->m_flags & M_MCAST) == 0)
+ error = nd6_resolve(ifp, 0, m, dst, phdr, &lleflags);
+ else {
+ const struct in6_addr *a6;
+ a6 = &(((const struct sockaddr_in6 *)dst)->sin6_addr);
+ ETHER_MAP_IPV6_MULTICAST(a6, eh->ether_dhost);
+ etype = htons(ETHERTYPE_IPV6);
+ memcpy(&eh->ether_type, &etype, sizeof(etype));
+ memcpy(eh->ether_shost, IF_LLADDR(ifp), ETHER_ADDR_LEN);
+ }
+ break;
+#endif
+ default:
+ if_printf(ifp, "can't handle af%d\n", dst->sa_family);
+ if (m != NULL)
+ m_freem(m);
+ return (EAFNOSUPPORT);
+ }
+
+ if (error == EHOSTDOWN) {
+ rt = (ro != NULL) ? ro->ro_rt : NULL;
+ if (rt != NULL && (rt->rt_flags & RTF_GATEWAY) != 0)
+ error = EHOSTUNREACH;
+ }
+
+ if (error != 0)
+ return (error);
+
+ *pflags = RT_MAY_LOOP;
+ if (lleflags & LLE_IFADDR)
+ *pflags |= RT_L2_ME;
+
+ return (0);
+}
+
+/*
* Ethernet output routine.
* Encapsulate a packet of type family for the local net.
* Use trailer local net encapsulation if enough data in first
@@ -145,27 +278,20 @@ int
ether_output(struct ifnet *ifp, struct mbuf *m,
const struct sockaddr *dst, struct route *ro)
{
- short type;
- int error = 0, hdrcmplt = 0;
- u_char edst[ETHER_ADDR_LEN];
- struct llentry *lle = NULL;
- struct rtentry *rt0 = NULL;
+ int error = 0;
+ char linkhdr[ETHER_HDR_LEN], *phdr;
struct ether_header *eh;
struct pf_mtag *t;
int loop_copy = 1;
int hlen; /* link layer header length */
- int is_gw = 0;
- uint32_t pflags = 0;
+ uint32_t pflags;
+ phdr = NULL;
+ pflags = 0;
if (ro != NULL) {
- if (!(m->m_flags & (M_BCAST | M_MCAST))) {
- lle = ro->ro_lle;
- if (lle != NULL)
- pflags = lle->la_flags;
- }
- rt0 = ro->ro_rt;
- if (rt0 != NULL && (rt0->rt_flags & RTF_GATEWAY) != 0)
- is_gw = 1;
+ phdr = ro->ro_prepend;
+ hlen = ro->ro_plen;
+ pflags = ro->ro_flags;
}
#ifdef MAC
error = mac_ifnet_check_transmit(ifp, m);
@@ -180,94 +306,31 @@ ether_output(struct ifnet *ifp, struct mbuf *m,
(ifp->if_drv_flags & IFF_DRV_RUNNING)))
senderr(ENETDOWN);
- hlen = ETHER_HDR_LEN;
- switch (dst->sa_family) {
-#ifdef INET
- case AF_INET:
- if (lle != NULL && (pflags & LLE_VALID) != 0)
- memcpy(edst, &lle->ll_addr.mac16, sizeof(edst));
- else
- error = arpresolve(ifp, is_gw, m, dst, edst, &pflags);
- if (error)
+ if (phdr == NULL) {
+ /* No prepend data supplied. Try to calculate ourselves. */
+ phdr = linkhdr;
+ hlen = ETHER_HDR_LEN;
+ error = ether_resolve_addr(ifp, m, dst, ro, phdr, &pflags);
+ if (error != 0)
return (error == EWOULDBLOCK ? 0 : error);
- type = htons(ETHERTYPE_IP);
- break;
- case AF_ARP:
- {
- struct arphdr *ah;
- ah = mtod(m, struct arphdr *);
- ah->ar_hrd = htons(ARPHRD_ETHER);
-
- loop_copy = 0; /* if this is for us, don't do it */
-
- switch(ntohs(ah->ar_op)) {
- case ARPOP_REVREQUEST:
- case ARPOP_REVREPLY:
- type = htons(ETHERTYPE_REVARP);
- break;
- case ARPOP_REQUEST:
- case ARPOP_REPLY:
- default:
- type = htons(ETHERTYPE_ARP);
- break;
- }
-
- if (m->m_flags & M_BCAST)
- bcopy(ifp->if_broadcastaddr, edst, ETHER_ADDR_LEN);
- else
- bcopy(ar_tha(ah), edst, ETHER_ADDR_LEN);
-
- }
- break;
-#endif
-#ifdef INET6
- case AF_INET6:
- if (lle != NULL && (pflags & LLE_VALID))
- memcpy(edst, &lle->ll_addr.mac16, sizeof(edst));
- else
- error = nd6_resolve(ifp, is_gw, m, dst, (u_char *)edst,
- &pflags);
- if (error)
- return (error == EWOULDBLOCK ? 0 : error);
- type = htons(ETHERTYPE_IPV6);
- break;
-#endif
- case pseudo_AF_HDRCMPLT:
- {
- const struct ether_header *eh;
-
- hdrcmplt = 1;
- /* FALLTHROUGH */
-
- case AF_UNSPEC:
- loop_copy = 0; /* if this is for us, don't do it */
- eh = (const struct ether_header *)dst->sa_data;
- (void)memcpy(edst, eh->ether_dhost, sizeof (edst));
- type = eh->ether_type;
- break;
- }
- default:
- if_printf(ifp, "can't handle af%d\n", dst->sa_family);
- senderr(EAFNOSUPPORT);
}
- if ((pflags & LLE_IFADDR) != 0) {
+ if ((pflags & RT_L2_ME) != 0) {
update_mbuf_csumflags(m, m);
return (if_simloop(ifp, m, dst->sa_family, 0));
}
+ loop_copy = pflags & RT_MAY_LOOP;
/*
* Add local net header. If no space in first mbuf,
* allocate another.
*/
- M_PREPEND(m, ETHER_HDR_LEN, M_NOWAIT);
+ M_PREPEND(m, hlen, M_NOWAIT);
if (m == NULL)
senderr(ENOBUFS);
- eh = mtod(m, struct ether_header *);
- if (hdrcmplt == 0) {
- memcpy(&eh->ether_type, &type, sizeof(eh->ether_type));
- memcpy(eh->ether_dhost, edst, sizeof (edst));
- memcpy(eh->ether_shost, IF_LLADDR(ifp),sizeof(eh->ether_shost));
+ if ((pflags & RT_HAS_HEADER) == 0) {
+ eh = mtod(m, struct ether_header *);
+ memcpy(eh, phdr, hlen);
}
/*
@@ -279,34 +342,27 @@ ether_output(struct ifnet *ifp, struct mbuf *m,
* on the wire). However, we don't do that here for security
* reasons and compatibility with the original behavior.
*/
- if ((ifp->if_flags & IFF_SIMPLEX) && loop_copy &&
+ if ((m->m_flags & M_BCAST) && loop_copy && (ifp->if_flags & IFF_SIMPLEX) &&
((t = pf_find_mtag(m)) == NULL || !t->routed)) {
- if (m->m_flags & M_BCAST) {
- struct mbuf *n;
+ struct mbuf *n;
- /*
- * Because if_simloop() modifies the packet, we need a
- * writable copy through m_dup() instead of a readonly
- * one as m_copy[m] would give us. The alternative would
- * be to modify if_simloop() to handle the readonly mbuf,
- * but performancewise it is mostly equivalent (trading
- * extra data copying vs. extra locking).
- *
- * XXX This is a local workaround. A number of less
- * often used kernel parts suffer from the same bug.
- * See PR kern/105943 for a proposed general solution.
- */
- if ((n = m_dup(m, M_NOWAIT)) != NULL) {
- update_mbuf_csumflags(m, n);
- (void)if_simloop(ifp, n, dst->sa_family, hlen);
- } else
- if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
- } else if (bcmp(eh->ether_dhost, eh->ether_shost,
- ETHER_ADDR_LEN) == 0) {
- update_mbuf_csumflags(m, m);
- (void) if_simloop(ifp, m, dst->sa_family, hlen);
- return (0); /* XXX */
- }
+ /*
+ * Because if_simloop() modifies the packet, we need a
+ * writable copy through m_dup() instead of a readonly
+ * one as m_copy[m] would give us. The alternative would
+ * be to modify if_simloop() to handle the readonly mbuf,
+ * but performancewise it is mostly equivalent (trading
+ * extra data copying vs. extra locking).
+ *
+ * XXX This is a local workaround. A number of less
+ * often used kernel parts suffer from the same bug.
+ * See PR kern/105943 for a proposed general solution.
+ */
+ if ((n = m_dup(m, M_NOWAIT)) != NULL) {
+ update_mbuf_csumflags(m, n);
+ (void)if_simloop(ifp, n, dst->sa_family, hlen);
+ } else
+ if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
}
/*
@@ -798,6 +854,7 @@ ether_ifattach(struct ifnet *ifp, const u_int8_t *lla)
ifp->if_output = ether_output;
ifp->if_input = ether_input;
ifp->if_resolvemulti = ether_resolvemulti;
+ ifp->if_requestencap = ether_requestencap;
#ifdef VIMAGE
ifp->if_reassign = ether_reassign;
#endif
diff --git a/sys/net/if_gif.c b/sys/net/if_gif.c
index 33d583c..1607af9 100644
--- a/sys/net/if_gif.c
+++ b/sys/net/if_gif.c
@@ -529,7 +529,6 @@ gif_input(struct mbuf *m, struct ifnet *ifp, int proto, uint8_t ecn)
struct gif_softc *sc;
struct ether_header *eh;
struct ifnet *oldifp;
- uint32_t gif_options;
int isr, n, af;
if (ifp == NULL) {
@@ -538,7 +537,6 @@ gif_input(struct mbuf *m, struct ifnet *ifp, int proto, uint8_t ecn)
return;
}
sc = ifp->if_softc;
- gif_options = sc->gif_options;
m->m_pkthdr.rcvif = ifp;
m_clrprotoflags(m);
switch (proto) {
diff --git a/sys/net/if_gre.c b/sys/net/if_gre.c
index 24ed971..9d4a976 100644
--- a/sys/net/if_gre.c
+++ b/sys/net/if_gre.c
@@ -682,7 +682,10 @@ gre_input(struct mbuf **mp, int *offp, int proto)
struct grehdr *gh;
struct ifnet *ifp;
struct mbuf *m;
- uint32_t *opts, key;
+ uint32_t *opts;
+#ifdef notyet
+ uint32_t key;
+#endif
uint16_t flags;
int hlen, isr, af;
@@ -715,17 +718,28 @@ gre_input(struct mbuf **mp, int *offp, int proto)
opts++;
}
if (flags & GRE_FLAGS_KP) {
+#ifdef notyet
+ /*
+ * XXX: The current implementation uses the key only for outgoing
+ * packets. But we can check the key value here, or even in the
+ * encapcheck function.
+ */
key = ntohl(*opts);
+#endif
hlen += sizeof(uint32_t);
opts++;
+ }
+#ifdef notyet
} else
key = 0;
- /*
+
if (sc->gre_key != 0 && (key != sc->gre_key || key != 0))
goto drop;
- */
+#endif
if (flags & GRE_FLAGS_SP) {
- /* seq = ntohl(*opts); */
+#ifdef notyet
+ seq = ntohl(*opts);
+#endif
hlen += sizeof(uint32_t);
}
switch (ntohs(gh->gre_proto)) {
diff --git a/sys/net/if_llatbl.c b/sys/net/if_llatbl.c
index b0450b3..beef6b4 100644
--- a/sys/net/if_llatbl.c
+++ b/sys/net/if_llatbl.c
@@ -278,10 +278,12 @@ lltable_drop_entry_queue(struct llentry *lle)
void
lltable_set_entry_addr(struct ifnet *ifp, struct llentry *lle,
- const char *lladdr)
+ const char *linkhdr, size_t linkhdrsize, int lladdr_off)
{
- bcopy(lladdr, &lle->ll_addr, ifp->if_addrlen);
+ memcpy(lle->r_linkdata, linkhdr, linkhdrsize);
+ lle->r_hdrlen = linkhdrsize;
+ lle->ll_addr = &lle->r_linkdata[lladdr_off];
lle->la_flags |= LLE_VALID;
lle->r_flags |= RLLE_VALID;
}
@@ -296,7 +298,7 @@ lltable_set_entry_addr(struct ifnet *ifp, struct llentry *lle,
*/
int
lltable_try_set_entry_addr(struct ifnet *ifp, struct llentry *lle,
- const char *lladdr)
+ const char *linkhdr, size_t linkhdrsize, int lladdr_off)
{
/* Perform real LLE update */
@@ -318,7 +320,7 @@ lltable_try_set_entry_addr(struct ifnet *ifp, struct llentry *lle,
}
/* Update data */
- lltable_set_entry_addr(ifp, lle, lladdr);
+ lltable_set_entry_addr(ifp, lle, linkhdr, linkhdrsize, lladdr_off);
IF_AFDATA_WUNLOCK(ifp);
@@ -327,6 +329,84 @@ lltable_try_set_entry_addr(struct ifnet *ifp, struct llentry *lle,
return (1);
}
+ /*
+ * Helper function used to pre-compute full/partial link-layer
+ * header data suitable for feeding into if_output().
+ */
+int
+lltable_calc_llheader(struct ifnet *ifp, int family, char *lladdr,
+ char *buf, size_t *bufsize, int *lladdr_off)
+{
+ struct if_encap_req ereq;
+ int error;
+
+ bzero(buf, *bufsize);
+ bzero(&ereq, sizeof(ereq));
+ ereq.buf = buf;
+ ereq.bufsize = *bufsize;
+ ereq.rtype = IFENCAP_LL;
+ ereq.family = family;
+ ereq.lladdr = lladdr;
+ ereq.lladdr_len = ifp->if_addrlen;
+ error = ifp->if_requestencap(ifp, &ereq);
+ if (error == 0) {
+ *bufsize = ereq.bufsize;
+ *lladdr_off = ereq.lladdr_off;
+ }
+
+ return (error);
+}
+
+/*
+ * Update link-layer header for given @lle after
+ * interface lladdr was changed.
+ */
+static int
+llentry_update_ifaddr(struct lltable *llt, struct llentry *lle, void *farg)
+{
+ struct ifnet *ifp;
+ u_char linkhdr[LLE_MAX_LINKHDR];
+ size_t linkhdrsize;
+ u_char *lladdr;
+ int lladdr_off;
+
+ ifp = (struct ifnet *)farg;
+
+ lladdr = lle->ll_addr;
+
+ LLE_WLOCK(lle);
+ if ((lle->la_flags & LLE_VALID) == 0) {
+ LLE_WUNLOCK(lle);
+ return (0);
+ }
+
+ if ((lle->la_flags & LLE_IFADDR) != 0)
+ lladdr = IF_LLADDR(ifp);
+
+ linkhdrsize = sizeof(linkhdr);
+ lltable_calc_llheader(ifp, llt->llt_af, lladdr, linkhdr, &linkhdrsize,
+ &lladdr_off);
+ memcpy(lle->r_linkdata, linkhdr, linkhdrsize);
+ LLE_WUNLOCK(lle);
+
+ return (0);
+}
+
+/*
+ * Update all calculated headers for given @llt
+ */
+void
+lltable_update_ifaddr(struct lltable *llt)
+{
+
+ if (llt->llt_ifp->if_flags & IFF_LOOPBACK)
+ return;
+
+ IF_AFDATA_WLOCK(llt->llt_ifp);
+ lltable_foreach_lle(llt, llentry_update_ifaddr, llt->llt_ifp);
+ IF_AFDATA_WUNLOCK(llt->llt_ifp);
+}
+
/*
*
* Performes generic cleanup routines and frees lle.
@@ -642,6 +722,9 @@ lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info)
struct ifnet *ifp;
struct lltable *llt;
struct llentry *lle, *lle_tmp;
+ uint8_t linkhdr[LLE_MAX_LINKHDR];
+ size_t linkhdrsize;
+ int lladdr_off;
u_int laflags = 0;
int error;
@@ -677,11 +760,14 @@ lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info)
if (lle == NULL)
return (ENOMEM);
- bcopy(LLADDR(dl), &lle->ll_addr, ifp->if_addrlen);
+ linkhdrsize = sizeof(linkhdr);
+ if (lltable_calc_llheader(ifp, dst->sa_family, LLADDR(dl),
+ linkhdr, &linkhdrsize, &lladdr_off) != 0)
+ return (EINVAL);
+ lltable_set_entry_addr(ifp, lle, linkhdr, linkhdrsize,
+ lladdr_off);
if ((rtm->rtm_flags & RTF_ANNOUNCE))
lle->la_flags |= LLE_PUB;
- lle->la_flags |= LLE_VALID;
- lle->r_flags |= RLLE_VALID;
lle->la_expire = rtm->rtm_rmx.rmx_expire;
laflags = lle->la_flags;
@@ -767,7 +853,7 @@ llatbl_lle_show(struct llentry_sa *la)
db_printf(" ln_router=%u\n", lle->ln_router);
db_printf(" ln_ntick=%ju\n", (uintmax_t)lle->ln_ntick);
db_printf(" lle_refcnt=%d\n", lle->lle_refcnt);
- bcopy(&lle->ll_addr.mac16, octet, sizeof(octet));
+ bcopy(lle->ll_addr, octet, sizeof(octet));
db_printf(" ll_addr=%02x:%02x:%02x:%02x:%02x:%02x\n",
octet[0], octet[1], octet[2], octet[3], octet[4], octet[5]);
db_printf(" lle_timer=%p\n", &lle->lle_timer);
diff --git a/sys/net/if_llatbl.h b/sys/net/if_llatbl.h
index 8a300c3..b6111c6 100644
--- a/sys/net/if_llatbl.h
+++ b/sys/net/if_llatbl.h
@@ -48,6 +48,7 @@ extern struct rwlock lltable_rwlock;
#define LLTABLE_WUNLOCK() rw_wunlock(&lltable_rwlock)
#define LLTABLE_LOCK_ASSERT() rw_assert(&lltable_rwlock, RA_LOCKED)
+#define LLE_MAX_LINKHDR 24 /* Full IB header */
/*
* Code referencing llentry must at least hold
* a shared lock
@@ -58,14 +59,11 @@ struct llentry {
struct in_addr addr4;
struct in6_addr addr6;
} r_l3addr;
- union {
- uint64_t mac_aligned;
- uint16_t mac16[3];
- uint8_t mac8[20]; /* IB needs 20 bytes. */
- } ll_addr;
+ char r_linkdata[LLE_MAX_LINKHDR]; /* L2 data */
+ uint8_t r_hdrlen; /* length for LL header */
+ uint8_t spare0[3];
uint16_t r_flags; /* LLE runtime flags */
uint16_t r_skip_req; /* feedback from fast path */
- uint64_t spare1;
struct lltable *lle_tbl;
struct llentries *lle_head;
@@ -82,6 +80,7 @@ struct llentry {
time_t lle_remtime; /* Real time remaining */
time_t lle_hittime; /* Time when r_skip_req was unset */
int lle_refcnt;
+ char *ll_addr; /* link-layer address */
LIST_ENTRY(llentry) lle_chain; /* chain of deleted items */
struct callout lle_timer;
@@ -198,6 +197,8 @@ MALLOC_DECLARE(M_LLTABLE);
/* LLE request flags */
#define LLE_EXCLUSIVE 0x2000 /* return lle xlocked */
#define LLE_UNLOCKED 0x4000 /* return lle unlocked */
+#define LLE_ADDRONLY 0x4000 /* return lladdr instead of full header */
+#define LLE_CREATE 0x8000 /* hint to avoid lle lookup */
/* LLE flags used by fastpath code */
#define RLLE_VALID 0x0001 /* entry is valid */
@@ -223,10 +224,13 @@ struct llentry *llentry_alloc(struct ifnet *, struct lltable *,
/* helper functions */
size_t lltable_drop_entry_queue(struct llentry *);
void lltable_set_entry_addr(struct ifnet *ifp, struct llentry *lle,
- const char *lladdr);
+ const char *linkhdr, size_t linkhdrsize, int lladdr_off);
int lltable_try_set_entry_addr(struct ifnet *ifp, struct llentry *lle,
- const char *lladdr);
+ const char *linkhdr, size_t linkhdrsize, int lladdr_off);
+int lltable_calc_llheader(struct ifnet *ifp, int family, char *lladdr,
+ char *buf, size_t *bufsize, int *lladdr_off);
+void lltable_update_ifaddr(struct lltable *llt);
struct llentry *lltable_alloc_entry(struct lltable *llt, u_int flags,
const struct sockaddr *l4addr);
void lltable_free_entry(struct lltable *llt, struct llentry *lle);
diff --git a/sys/net/if_var.h b/sys/net/if_var.h
index 5911cec..54de567 100644
--- a/sys/net/if_var.h
+++ b/sys/net/if_var.h
@@ -134,6 +134,48 @@ struct ifnet_hw_tsomax {
u_int tsomaxsegsize; /* TSO maximum segment size in bytes */
};
+/* Interface encap request types */
+typedef enum {
+ IFENCAP_LL = 1 /* pre-calculate link-layer header */
+} ife_type;
+
+/*
+ * The structure below allows to request various pre-calculated L2/L3 headers
+ * for different media. Requests varies by type (rtype field).
+ *
+ * IFENCAP_LL type: pre-calculates link header based on address family
+ * and destination lladdr.
+ *
+ * Input data fields:
+ * buf: pointer to destination buffer
+ * bufsize: buffer size
+ * flags: IFENCAP_FLAG_BROADCAST if destination is broadcast
+ * family: address family defined by AF_ constant.
+ * lladdr: pointer to link-layer address
+ * lladdr_len: length of link-layer address
+ * hdata: pointer to L3 header (optional, used for ARP requests).
+ * Output data fields:
+ * buf: encap data is stored here
+ * bufsize: resulting encap length is stored here
+ * lladdr_off: offset of link-layer address from encap hdr start
+ * hdata: L3 header may be altered if necessary
+ */
+
+struct if_encap_req {
+ u_char *buf; /* Destination buffer (w) */
+ size_t bufsize; /* size of provided buffer (r) */
+ ife_type rtype; /* request type (r) */
+ uint32_t flags; /* Request flags (r) */
+ int family; /* Address family AF_* (r) */
+ int lladdr_off; /* offset from header start (w) */
+ int lladdr_len; /* lladdr length (r) */
+ char *lladdr; /* link-level address pointer (r) */
+ char *hdata; /* Upper layer header data (rw) */
+};
+
+#define IFENCAP_FLAG_BROADCAST 0x02 /* Destination is broadcast */
+
+
/*
* Structure defining a network interface.
*
@@ -235,6 +277,8 @@ struct ifnet {
void (*if_reassign) /* reassign to vnet routine */
(struct ifnet *, struct vnet *, char *);
if_get_counter_t if_get_counter; /* get counter values */
+ int (*if_requestencap) /* make link header from request */
+ (struct ifnet *, struct if_encap_req *);
/* Statistics. */
counter_u64_t if_counters[IFCOUNTERS];
diff --git a/sys/net/route.h b/sys/net/route.h
index 66f4d77..743c830 100644
--- a/sys/net/route.h
+++ b/sys/net/route.h
@@ -51,14 +51,21 @@
*/
struct route {
struct rtentry *ro_rt;
- struct llentry *ro_lle;
- struct in_ifaddr *ro_ia;
- int ro_flags;
+ char *ro_prepend;
+ uint16_t ro_plen;
+ uint16_t ro_flags;
struct sockaddr ro_dst;
};
+#define RT_L2_ME_BIT 2 /* dst L2 addr is our address */
+#define RT_MAY_LOOP_BIT 3 /* dst may require loop copy */
+#define RT_HAS_HEADER_BIT 4 /* mbuf already have its header prepended */
+
#define RT_CACHING_CONTEXT 0x1 /* XXX: not used anywhere */
#define RT_NORTREF 0x2 /* doesn't hold reference on ro_rt */
+#define RT_L2_ME (1 << RT_L2_ME_BIT)
+#define RT_MAY_LOOP (1 << RT_MAY_LOOP_BIT)
+#define RT_HAS_HEADER (1 << RT_HAS_HEADER_BIT)
struct rt_metrics {
u_long rmx_locks; /* Kernel must leave these values alone */
diff --git a/sys/netinet/if_ether.c b/sys/netinet/if_ether.c
index 4c0c586b..0bf5cec 100644
--- a/sys/netinet/if_ether.c
+++ b/sys/netinet/if_ether.c
@@ -282,6 +282,37 @@ arptimer(void *arg)
}
/*
+ * Stores link-layer header for @ifp in format suitable for if_output()
+ * into buffer @buf. Resulting header length is stored in @bufsize.
+ *
+ * Returns 0 on success.
+ */
+static int
+arp_fillheader(struct ifnet *ifp, struct arphdr *ah, int bcast, u_char *buf,
+ size_t *bufsize)
+{
+ struct if_encap_req ereq;
+ int error;
+
+ bzero(buf, *bufsize);
+ bzero(&ereq, sizeof(ereq));
+ ereq.buf = buf;
+ ereq.bufsize = *bufsize;
+ ereq.rtype = IFENCAP_LL;
+ ereq.family = AF_ARP;
+ ereq.lladdr = ar_tha(ah);
+ ereq.hdata = (u_char *)ah;
+ if (bcast)
+ ereq.flags = IFENCAP_FLAG_BROADCAST;
+ error = ifp->if_requestencap(ifp, &ereq);
+ if (error == 0)
+ *bufsize = ereq.bufsize;
+
+ return (error);
+}
+
+
+/*
* Broadcast an ARP request. Caller specifies:
* - arp header source ip address
* - arp header target ip address
@@ -295,6 +326,10 @@ arprequest(struct ifnet *ifp, const struct in_addr *sip,
struct arphdr *ah;
struct sockaddr sa;
u_char *carpaddr = NULL;
+ uint8_t linkhdr[LLE_MAX_LINKHDR];
+ size_t linkhdrsize;
+ struct route ro;
+ int error;
if (sip == NULL) {
/*
@@ -350,12 +385,28 @@ arprequest(struct ifnet *ifp, const struct in_addr *sip,
bcopy(tip, ar_tpa(ah), ah->ar_pln);
sa.sa_family = AF_ARP;
sa.sa_len = 2;
+
+ /* Calculate link header for sending frame */
+ bzero(&ro, sizeof(ro));
+ linkhdrsize = sizeof(linkhdr);
+ error = arp_fillheader(ifp, ah, 1, linkhdr, &linkhdrsize);
+ if (error != 0 && error != EAFNOSUPPORT) {
+ ARP_LOG(LOG_ERR, "Failed to calculate ARP header on %s: %d\n",
+ if_name(ifp), error);
+ return;
+ }
+
+ ro.ro_prepend = linkhdr;
+ ro.ro_plen = linkhdrsize;
+ ro.ro_flags = 0;
+
m->m_flags |= M_BCAST;
m_clrprotoflags(m); /* Avoid confusing lower layers. */
- (*ifp->if_output)(ifp, m, &sa, NULL);
+ (*ifp->if_output)(ifp, m, &sa, &ro);
ARPSTAT_INC(txrequests);
}
+
/*
* Resolve an IP address into an ethernet address - heavy version.
* Used internally by arpresolve().
@@ -368,18 +419,20 @@ arprequest(struct ifnet *ifp, const struct in_addr *sip,
* Note that m_freem() handles NULL.
*/
static int
-arpresolve_full(struct ifnet *ifp, int is_gw, int create, struct mbuf *m,
+arpresolve_full(struct ifnet *ifp, int is_gw, int flags, struct mbuf *m,
const struct sockaddr *dst, u_char *desten, uint32_t *pflags)
{
struct llentry *la = NULL, *la_tmp;
struct mbuf *curr = NULL;
struct mbuf *next = NULL;
int error, renew;
+ char *lladdr;
+ int ll_len;
if (pflags != NULL)
*pflags = 0;
- if (create == 0) {
+ if ((flags & LLE_CREATE) == 0) {
IF_AFDATA_RLOCK(ifp);
la = lla_lookup(LLTABLE(ifp), LLE_EXCLUSIVE, dst);
IF_AFDATA_RUNLOCK(ifp);
@@ -413,7 +466,14 @@ arpresolve_full(struct ifnet *ifp, int is_gw, int create, struct mbuf *m,
if ((la->la_flags & LLE_VALID) &&
((la->la_flags & LLE_STATIC) || la->la_expire > time_uptime)) {
- bcopy(&la->ll_addr, desten, ifp->if_addrlen);
+ if (flags & LLE_ADDRONLY) {
+ lladdr = la->ll_addr;
+ ll_len = ifp->if_addrlen;
+ } else {
+ lladdr = la->r_linkdata;
+ ll_len = la->r_hdrlen;
+ }
+ bcopy(lladdr, desten, ll_len);
/* Check if we have feedback request from arptimer() */
if (la->r_skip_req != 0) {
@@ -485,15 +545,31 @@ arpresolve_full(struct ifnet *ifp, int is_gw, int create, struct mbuf *m,
/*
* Resolve an IP address into an ethernet address.
+ */
+int
+arpresolve_addr(struct ifnet *ifp, int flags, const struct sockaddr *dst,
+ char *desten, uint32_t *pflags)
+{
+ int error;
+
+ flags |= LLE_ADDRONLY;
+ error = arpresolve_full(ifp, 0, flags, NULL, dst, desten, pflags);
+ return (error);
+}
+
+
+/*
+ * Lookups link header based on an IP address.
* On input:
* ifp is the interface we use
* is_gw != 0 if @dst represents gateway to some destination
* m is the mbuf. May be NULL if we don't have a packet.
* dst is the next hop,
- * desten is the storage to put LL address.
+ * desten is the storage to put LL header.
* flags returns subset of lle flags: LLE_VALID | LLE_IFADDR
*
- * On success, desten and flags are filled in and the function returns 0;
+ * On success, full/partial link header and flags are filled in and
+ * the function returns 0.
* If the packet must be held pending resolution, we return EWOULDBLOCK
* On other errors, we return the corresponding error code.
* Note that m_freem() handles NULL.
@@ -525,7 +601,7 @@ arpresolve(struct ifnet *ifp, int is_gw, struct mbuf *m,
la = lla_lookup(LLTABLE(ifp), LLE_UNLOCKED, dst);
if (la != NULL && (la->r_flags & RLLE_VALID) != 0) {
/* Entry found, let's copy lle info */
- bcopy(&la->ll_addr, desten, ifp->if_addrlen);
+ bcopy(la->r_linkdata, desten, la->r_hdrlen);
if (pflags != NULL)
*pflags = LLE_VALID | (la->r_flags & RLLE_IFADDR);
/* Check if we have feedback request from arptimer() */
@@ -539,7 +615,8 @@ arpresolve(struct ifnet *ifp, int is_gw, struct mbuf *m,
}
IF_AFDATA_RUNLOCK(ifp);
- return (arpresolve_full(ifp, is_gw, 1, m, dst, desten, pflags));
+ return (arpresolve_full(ifp, is_gw, la == NULL ? LLE_CREATE : 0, m, dst,
+ desten, pflags));
}
/*
@@ -683,6 +760,11 @@ in_arpinput(struct mbuf *m)
struct sockaddr_in sin;
struct sockaddr *dst;
struct nhop4_basic nh4;
+ uint8_t linkhdr[LLE_MAX_LINKHDR];
+ struct route ro;
+ size_t linkhdrsize;
+ int lladdr_off;
+ int error;
sin.sin_len = sizeof(struct sockaddr_in);
sin.sin_family = AF_INET;
@@ -850,8 +932,14 @@ match:
else if (itaddr.s_addr == myaddr.s_addr) {
/*
* Request/reply to our address, but no lle exists yet.
- * Try to create new llentry.
+ * Calculate full link prepend to use in lle.
*/
+ linkhdrsize = sizeof(linkhdr);
+ if (lltable_calc_llheader(ifp, AF_INET, ar_sha(ah), linkhdr,
+ &linkhdrsize, &lladdr_off) != 0)
+ goto reply;
+
+ /* Allocate new entry */
la = lltable_alloc_entry(LLTABLE(ifp), 0, dst);
if (la == NULL) {
@@ -863,7 +951,8 @@ match:
*/
goto reply;
}
- lltable_set_entry_addr(ifp, la, ar_sha(ah));
+ lltable_set_entry_addr(ifp, la, linkhdr, linkhdrsize,
+ lladdr_off);
IF_AFDATA_WLOCK(ifp);
LLE_WLOCK(la);
@@ -921,7 +1010,7 @@ reply:
if ((lle != NULL) && (lle->la_flags & LLE_PUB)) {
(void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln);
- (void)memcpy(ar_sha(ah), &lle->ll_addr, ah->ar_hln);
+ (void)memcpy(ar_sha(ah), lle->ll_addr, ah->ar_hln);
LLE_RUNLOCK(lle);
} else {
@@ -991,8 +1080,29 @@ reply:
m->m_pkthdr.rcvif = NULL;
sa.sa_family = AF_ARP;
sa.sa_len = 2;
+
+ /* Calculate link header for sending frame */
+ bzero(&ro, sizeof(ro));
+ linkhdrsize = sizeof(linkhdr);
+ error = arp_fillheader(ifp, ah, 0, linkhdr, &linkhdrsize);
+
+ /*
+ * arp_fillheader() may fail due to lack of support inside encap request
+ * routing. This is not necessary an error, AF_ARP can/should be handled
+ * by if_output().
+ */
+ if (error != 0 && error != EAFNOSUPPORT) {
+ ARP_LOG(LOG_ERR, "Failed to calculate ARP header on %s: %d\n",
+ if_name(ifp), error);
+ return;
+ }
+
+ ro.ro_prepend = linkhdr;
+ ro.ro_plen = linkhdrsize;
+ ro.ro_flags = 0;
+
m_clrprotoflags(m); /* Avoid confusing lower layers. */
- (*ifp->if_output)(ifp, m, &sa, NULL);
+ (*ifp->if_output)(ifp, m, &sa, &ro);
ARPSTAT_INC(txreplies);
return;
@@ -1011,6 +1121,9 @@ arp_check_update_lle(struct arphdr *ah, struct in_addr isaddr, struct ifnet *ifp
{
struct sockaddr sa;
struct mbuf *m_hold, *m_hold_next;
+ uint8_t linkhdr[LLE_MAX_LINKHDR];
+ size_t linkhdrsize;
+ int lladdr_off;
LLE_WLOCK_ASSERT(la);
@@ -1027,7 +1140,7 @@ arp_check_update_lle(struct arphdr *ah, struct in_addr isaddr, struct ifnet *ifp
return;
}
if ((la->la_flags & LLE_VALID) &&
- bcmp(ar_sha(ah), &la->ll_addr, ifp->if_addrlen)) {
+ bcmp(ar_sha(ah), la->ll_addr, ifp->if_addrlen)) {
if (la->la_flags & LLE_STATIC) {
LLE_WUNLOCK(la);
if (log_arp_permanent_modify)
@@ -1050,31 +1163,19 @@ arp_check_update_lle(struct arphdr *ah, struct in_addr isaddr, struct ifnet *ifp
}
}
+ /* Calculate full link prepend to use in lle */
+ linkhdrsize = sizeof(linkhdr);
+ if (lltable_calc_llheader(ifp, AF_INET, ar_sha(ah), linkhdr,
+ &linkhdrsize, &lladdr_off) != 0)
+ return;
+
/* Check if something has changed */
- if (memcmp(&la->ll_addr, ar_sha(ah), ifp->if_addrlen) != 0 ||
+ if (memcmp(la->r_linkdata, linkhdr, linkhdrsize) != 0 ||
(la->la_flags & LLE_VALID) == 0) {
- /* Perform real LLE update */
- /* use afdata WLOCK to update fields */
- LLE_ADDREF(la);
- LLE_WUNLOCK(la);
- IF_AFDATA_WLOCK(ifp);
- LLE_WLOCK(la);
-
- /*
- * Since we droppped LLE lock, other thread might have deleted
- * this lle. Check and return
- */
- if ((la->la_flags & LLE_DELETED) != 0) {
- IF_AFDATA_WUNLOCK(ifp);
- LLE_FREE_LOCKED(la);
+ /* Try to perform LLE update */
+ if (lltable_try_set_entry_addr(ifp, la, linkhdr, linkhdrsize,
+ lladdr_off) == 0)
return;
- }
-
- /* Update data */
- lltable_set_entry_addr(ifp, la, ar_sha(ah));
-
- IF_AFDATA_WUNLOCK(ifp);
- LLE_REMREF(la);
/* Clear fast path feedback request if set */
la->r_skip_req = 0;
@@ -1215,10 +1316,12 @@ arp_handle_ifllchange(struct ifnet *ifp)
/*
* A handler for interface link layer address change event.
*/
-static __noinline void
+static void
arp_iflladdr(void *arg __unused, struct ifnet *ifp)
{
+ lltable_update_ifaddr(LLTABLE(ifp));
+
if ((ifp->if_flags & IFF_UP) != 0)
arp_handle_ifllchange(ifp);
}
@@ -1231,5 +1334,8 @@ arp_init(void)
if (IS_DEFAULT_VNET(curvnet))
iflladdr_tag = EVENTHANDLER_REGISTER(iflladdr_event,
arp_iflladdr, NULL, EVENTHANDLER_PRI_ANY);
+ if (IS_DEFAULT_VNET(curvnet))
+ iflladdr_tag = EVENTHANDLER_REGISTER(iflladdr_event,
+ arp_iflladdr, NULL, EVENTHANDLER_PRI_ANY);
}
SYSINIT(arp, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY, arp_init, 0);
diff --git a/sys/netinet/if_ether.h b/sys/netinet/if_ether.h
index 1583ca5..06ec210 100644
--- a/sys/netinet/if_ether.h
+++ b/sys/netinet/if_ether.h
@@ -114,6 +114,8 @@ extern u_char ether_ipmulticast_max[ETHER_ADDR_LEN];
struct ifaddr;
+int arpresolve_addr(struct ifnet *ifp, int flags,
+ const struct sockaddr *dst, char *desten, uint32_t *pflags);
int arpresolve(struct ifnet *ifp, int is_gw, struct mbuf *m,
const struct sockaddr *dst, u_char *desten, uint32_t *pflags);
void arprequest(struct ifnet *, const struct in_addr *,
diff --git a/sys/netinet/in.c b/sys/netinet/in.c
index 7504c8f..c30c1f3 100644
--- a/sys/netinet/in.c
+++ b/sys/netinet/in.c
@@ -1240,6 +1240,9 @@ in_lltable_alloc(struct lltable *llt, u_int flags, const struct sockaddr *l3addr
const struct sockaddr_in *sin = (const struct sockaddr_in *)l3addr;
struct ifnet *ifp = llt->llt_ifp;
struct llentry *lle;
+ char linkhdr[LLE_MAX_LINKHDR];
+ size_t linkhdrsize;
+ int lladdr_off;
KASSERT(l3addr->sa_family == AF_INET,
("sin_family %d", l3addr->sa_family));
@@ -1262,7 +1265,12 @@ in_lltable_alloc(struct lltable *llt, u_int flags, const struct sockaddr *l3addr
if (flags & LLE_STATIC)
lle->r_flags |= RLLE_VALID;
if ((flags & LLE_IFADDR) == LLE_IFADDR) {
- lltable_set_entry_addr(ifp, lle, IF_LLADDR(ifp));
+ linkhdrsize = LLE_MAX_LINKHDR;
+ if (lltable_calc_llheader(ifp, AF_INET, IF_LLADDR(ifp),
+ linkhdr, &linkhdrsize, &lladdr_off) != 0)
+ return (NULL);
+ lltable_set_entry_addr(ifp, lle, linkhdr, linkhdrsize,
+ lladdr_off);
lle->la_flags |= LLE_STATIC;
lle->r_flags |= (RLLE_VALID | RLLE_IFADDR);
}
@@ -1349,7 +1357,7 @@ in_lltable_dump_entry(struct lltable *llt, struct llentry *lle,
sdl->sdl_type = ifp->if_type;
if ((lle->la_flags & LLE_VALID) == LLE_VALID) {
sdl->sdl_alen = ifp->if_addrlen;
- bcopy(&lle->ll_addr, LLADDR(sdl), ifp->if_addrlen);
+ bcopy(lle->ll_addr, LLADDR(sdl), ifp->if_addrlen);
} else {
sdl->sdl_alen = 0;
bzero(LLADDR(sdl), ifp->if_addrlen);
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index 557458a..7ad43a2 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -567,7 +567,7 @@ sendit:
RO_RTFREE(ro);
if (have_ia_ref)
ifa_free(&ia->ia_ifa);
- ro->ro_lle = NULL;
+ ro->ro_prepend = NULL;
rte = NULL;
gw = dst;
ip = mtod(m, struct ip *);
diff --git a/sys/netinet/toecore.c b/sys/netinet/toecore.c
index ef82f8a..6ed8eb0 100644
--- a/sys/netinet/toecore.c
+++ b/sys/netinet/toecore.c
@@ -428,7 +428,7 @@ toe_lle_event(void *arg __unused, struct llentry *lle, int evt)
KASSERT(lle->la_flags & LLE_VALID,
("%s: %p resolved but not valid?", __func__, lle));
- lladdr = (uint8_t *)&lle->ll_addr;
+ lladdr = (uint8_t *)lle->ll_addr;
#ifdef VLAN_TAG
VLAN_TAG(ifp, &vtag);
#endif
diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c
index f0c5371..a7bbac0 100644
--- a/sys/netinet6/icmp6.c
+++ b/sys/netinet6/icmp6.c
@@ -2632,7 +2632,7 @@ icmp6_redirect_output(struct mbuf *m0, struct rtentry *rt)
nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
nd_opt->nd_opt_len = len >> 3;
lladdr = (char *)(nd_opt + 1);
- bcopy(&ln->ll_addr, lladdr, ifp->if_addrlen);
+ bcopy(ln->ll_addr, lladdr, ifp->if_addrlen);
p += len;
}
}
diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c
index 0f8fb67..0d47d4b 100644
--- a/sys/netinet6/in6.c
+++ b/sys/netinet6/in6.c
@@ -1552,7 +1552,7 @@ in6ifa_llaonifp(struct ifnet *ifp)
if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)
return (NULL);
- if_addr_rlock(ifp);
+ IF_ADDR_RLOCK(ifp);
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
@@ -1562,7 +1562,7 @@ in6ifa_llaonifp(struct ifnet *ifp)
IN6_IS_ADDR_MC_NODELOCAL(&sin6->sin6_addr))
break;
}
- if_addr_runlock(ifp);
+ IF_ADDR_RUNLOCK(ifp);
return ((struct in6_ifaddr *)ifa);
}
@@ -2245,6 +2245,9 @@ in6_lltable_alloc(struct lltable *llt, u_int flags,
const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)l3addr;
struct ifnet *ifp = llt->llt_ifp;
struct llentry *lle;
+ char linkhdr[LLE_MAX_LINKHDR];
+ size_t linkhdrsize;
+ int lladdr_off;
KASSERT(l3addr->sa_family == AF_INET6,
("sin_family %d", l3addr->sa_family));
@@ -2265,7 +2268,12 @@ in6_lltable_alloc(struct lltable *llt, u_int flags,
}
lle->la_flags = flags;
if ((flags & LLE_IFADDR) == LLE_IFADDR) {
- lltable_set_entry_addr(ifp, lle, IF_LLADDR(ifp));
+ linkhdrsize = LLE_MAX_LINKHDR;
+ if (lltable_calc_llheader(ifp, AF_INET6, IF_LLADDR(ifp),
+ linkhdr, &linkhdrsize, &lladdr_off) != 0)
+ return (NULL);
+ lltable_set_entry_addr(ifp, lle, linkhdr, linkhdrsize,
+ lladdr_off);
lle->la_flags |= LLE_STATIC;
}
diff --git a/sys/netinet6/in6.h b/sys/netinet6/in6.h
index 8f08c8f..9bc142a 100644
--- a/sys/netinet6/in6.h
+++ b/sys/netinet6/in6.h
@@ -375,9 +375,9 @@ extern const struct in6_addr in6addr_linklocal_allv2routers;
#if __BSD_VISIBLE
struct route_in6 {
struct rtentry *ro_rt;
- struct llentry *ro_lle;
- struct in6_addr *ro_ia6;
- int ro_flags;
+ char *ro_prepend;
+ uint16_t ro_plen;
+ uint16_t ro_flags;
struct sockaddr_in6 ro_dst;
};
#endif
diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c
index 778f39d..af9fdba 100644
--- a/sys/netinet6/ip6_output.c
+++ b/sys/netinet6/ip6_output.c
@@ -1830,6 +1830,7 @@ do { \
case IPV6_RSSBUCKETID:
case IPV6_RECVRSSBUCKETID:
#endif
+ case IPV6_BINDMULTI:
switch (optname) {
case IPV6_RECVHOPOPTS:
diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c
index 7ca172c..fbbf421 100644
--- a/sys/netinet6/nd6.c
+++ b/sys/netinet6/nd6.c
@@ -111,7 +111,7 @@ VNET_DEFINE(int, nd6_debug) = 1;
VNET_DEFINE(int, nd6_debug) = 0;
#endif
-static eventhandler_tag lle_event_eh;
+static eventhandler_tag lle_event_eh, iflladdr_event_eh;
/* for debugging? */
#if 0
@@ -137,7 +137,7 @@ static void nd6_llinfo_timer(void *);
static void nd6_llinfo_settimer_locked(struct llentry *, long);
static void clear_llinfo_pqueue(struct llentry *);
static void nd6_rtrequest(int, struct rtentry *, struct rt_addrinfo *);
-static int nd6_resolve_slow(struct ifnet *, struct mbuf *,
+static int nd6_resolve_slow(struct ifnet *, int, struct mbuf *,
const struct sockaddr_in6 *, u_char *, uint32_t *);
static int nd6_need_cache(struct ifnet *);
@@ -188,7 +188,7 @@ nd6_lle_event(void *arg __unused, struct llentry *lle, int evt)
gw.sdl_index = ifp->if_index;
gw.sdl_type = ifp->if_type;
if (evt == LLENTRY_RESOLVED)
- bcopy(&lle->ll_addr, gw.sdl_data, ifp->if_addrlen);
+ bcopy(lle->ll_addr, gw.sdl_data, ifp->if_addrlen);
rtinfo.rti_info[RTAX_DST] = (struct sockaddr *)&dst;
rtinfo.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&gw;
rtinfo.rti_addrs = RTA_DST | RTA_GATEWAY;
@@ -196,6 +196,16 @@ nd6_lle_event(void *arg __unused, struct llentry *lle, int evt)
type == RTM_ADD ? RTF_UP: 0), 0, RT_DEFAULT_FIB);
}
+/*
+ * A handler for interface link layer address change event.
+ */
+static void
+nd6_iflladdr(void *arg __unused, struct ifnet *ifp)
+{
+
+ lltable_update_ifaddr(LLTABLE6(ifp));
+}
+
void
nd6_init(void)
{
@@ -211,9 +221,12 @@ nd6_init(void)
nd6_slowtimo, curvnet);
nd6_dad_init();
- if (IS_DEFAULT_VNET(curvnet))
+ if (IS_DEFAULT_VNET(curvnet)) {
lle_event_eh = EVENTHANDLER_REGISTER(lle_event, nd6_lle_event,
NULL, EVENTHANDLER_PRI_ANY);
+ iflladdr_event_eh = EVENTHANDLER_REGISTER(iflladdr_event,
+ nd6_iflladdr, NULL, EVENTHANDLER_PRI_ANY);
+ }
}
#ifdef VIMAGE
@@ -223,8 +236,10 @@ nd6_destroy()
callout_drain(&V_nd6_slowtimo_ch);
callout_drain(&V_nd6_timer_ch);
- if (IS_DEFAULT_VNET(curvnet))
+ if (IS_DEFAULT_VNET(curvnet)) {
EVENTHANDLER_DEREGISTER(lle_event, lle_event_eh);
+ EVENTHANDLER_DEREGISTER(iflladdr_event, iflladdr_event_eh);
+ }
}
#endif
@@ -1844,6 +1859,9 @@ nd6_cache_lladdr(struct ifnet *ifp, struct in6_addr *from, char *lladdr,
uint16_t router = 0;
struct sockaddr_in6 sin6;
struct mbuf *chain = NULL;
+ u_char linkhdr[LLE_MAX_LINKHDR];
+ size_t linkhdrsize;
+ int lladdr_off;
IF_AFDATA_UNLOCK_ASSERT(ifp);
@@ -1878,8 +1896,15 @@ nd6_cache_lladdr(struct ifnet *ifp, struct in6_addr *from, char *lladdr,
* Since we already know all the data for the new entry,
* fill it before insertion.
*/
- if (lladdr != NULL)
- lltable_set_entry_addr(ifp, ln, lladdr);
+ if (lladdr != NULL) {
+ linkhdrsize = sizeof(linkhdr);
+ if (lltable_calc_llheader(ifp, AF_INET6, lladdr,
+ linkhdr, &linkhdrsize, &lladdr_off) != 0)
+ return;
+ lltable_set_entry_addr(ifp, ln, linkhdr, linkhdrsize,
+ lladdr_off);
+ }
+
IF_AFDATA_WLOCK(ifp);
LLE_WLOCK(ln);
/* Prefer any existing lle over newly-created one */
@@ -1911,7 +1936,7 @@ nd6_cache_lladdr(struct ifnet *ifp, struct in6_addr *from, char *lladdr,
olladdr = (ln->la_flags & LLE_VALID) ? 1 : 0;
if (olladdr && lladdr) {
- llchange = bcmp(lladdr, &ln->ll_addr,
+ llchange = bcmp(lladdr, ln->ll_addr,
ifp->if_addrlen);
} else if (!olladdr && lladdr)
llchange = 1;
@@ -1937,7 +1962,13 @@ nd6_cache_lladdr(struct ifnet *ifp, struct in6_addr *from, char *lladdr,
* Record source link-layer address
* XXX is it dependent to ifp->if_type?
*/
- if (lltable_try_set_entry_addr(ifp, ln, lladdr) == 0) {
+ linkhdrsize = sizeof(linkhdr);
+ if (lltable_calc_llheader(ifp, AF_INET6, lladdr,
+ linkhdr, &linkhdrsize, &lladdr_off) != 0)
+ return;
+
+ if (lltable_try_set_entry_addr(ifp, ln, linkhdr, linkhdrsize,
+ lladdr_off) == 0) {
/* Entry was deleted */
return;
}
@@ -2093,8 +2124,8 @@ nd6_output_ifp(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m,
}
/*
- * Do L2 address resolution for @sa_dst address. Stores found
- * address in @desten buffer. Copy of lle ln_flags can be also
+ * Lookup link headerfor @sa_dst address. Stores found
+ * data in @desten buffer. Copy of lle ln_flags can be also
* saved in @pflags if @pflags is non-NULL.
*
* If destination LLE does not exists or lle state modification
@@ -2144,7 +2175,7 @@ nd6_resolve(struct ifnet *ifp, int is_gw, struct mbuf *m,
ln = nd6_lookup(&dst6->sin6_addr, LLE_UNLOCKED, ifp);
if (ln != NULL && (ln->r_flags & RLLE_VALID) != 0) {
/* Entry found, let's copy lle info */
- bcopy(&ln->ll_addr, desten, ifp->if_addrlen);
+ bcopy(ln->r_linkdata, desten, ln->r_hdrlen);
if (pflags != NULL)
*pflags = LLE_VALID | (ln->r_flags & RLLE_IFADDR);
/* Check if we have feedback request from nd6 timer */
@@ -2159,7 +2190,7 @@ nd6_resolve(struct ifnet *ifp, int is_gw, struct mbuf *m,
}
IF_AFDATA_RUNLOCK(ifp);
- return (nd6_resolve_slow(ifp, m, dst6, desten, pflags));
+ return (nd6_resolve_slow(ifp, 0, m, dst6, desten, pflags));
}
@@ -2175,12 +2206,13 @@ nd6_resolve(struct ifnet *ifp, int is_gw, struct mbuf *m,
* Set noinline to be dtrace-friendly
*/
static __noinline int
-nd6_resolve_slow(struct ifnet *ifp, struct mbuf *m,
+nd6_resolve_slow(struct ifnet *ifp, int flags, struct mbuf *m,
const struct sockaddr_in6 *dst, u_char *desten, uint32_t *pflags)
{
struct llentry *lle = NULL, *lle_tmp;
struct in6_addr *psrc, src;
- int send_ns;
+ int send_ns, ll_len;
+ char *lladdr;
/*
* Address resolution or Neighbor Unreachability Detection
@@ -2252,7 +2284,14 @@ nd6_resolve_slow(struct ifnet *ifp, struct mbuf *m,
* send the packet.
*/
if (lle->ln_state > ND6_LLINFO_INCOMPLETE) {
- bcopy(&lle->ll_addr, desten, ifp->if_addrlen);
+ if (flags & LLE_ADDRONLY) {
+ lladdr = lle->ll_addr;
+ ll_len = ifp->if_addrlen;
+ } else {
+ lladdr = lle->r_linkdata;
+ ll_len = lle->r_hdrlen;
+ }
+ bcopy(lladdr, desten, ll_len);
if (pflags != NULL)
*pflags = lle->la_flags;
LLE_WUNLOCK(lle);
@@ -2312,6 +2351,27 @@ nd6_resolve_slow(struct ifnet *ifp, struct mbuf *m,
return (EWOULDBLOCK);
}
+/*
+ * Do L2 address resolution for @sa_dst address. Stores found
+ * address in @desten buffer. Copy of lle ln_flags can be also
+ * saved in @pflags if @pflags is non-NULL.
+ *
+ * Return values:
+ * - 0 on success (address copied to buffer).
+ * - EWOULDBLOCK (no local error, but address is still unresolved)
+ * - other errors (alloc failure, etc)
+ */
+int
+nd6_resolve_addr(struct ifnet *ifp, int flags, const struct sockaddr *dst,
+ char *desten, uint32_t *pflags)
+{
+ int error;
+
+ flags |= LLE_ADDRONLY;
+ error = nd6_resolve_slow(ifp, flags, NULL,
+ (const struct sockaddr_in6 *)dst, desten, pflags);
+ return (error);
+}
int
nd6_flush_holdchain(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *chain,
diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h
index 8a0a56e..6ff4cac 100644
--- a/sys/netinet6/nd6.h
+++ b/sys/netinet6/nd6.h
@@ -410,6 +410,8 @@ void nd6_setmtu(struct ifnet *);
void nd6_llinfo_setstate(struct llentry *lle, int newstate);
void nd6_timer(void *);
void nd6_purge(struct ifnet *);
+int nd6_resolve_addr(struct ifnet *ifp, int flags, const struct sockaddr *dst,
+ char *desten, uint32_t *pflags);
int nd6_resolve(struct ifnet *, int, struct mbuf *,
const struct sockaddr *, u_char *, uint32_t *);
int nd6_ioctl(u_long, caddr_t, struct ifnet *);
diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c
index bf43fb6..a5ce2ec 100644
--- a/sys/netinet6/nd6_nbr.c
+++ b/sys/netinet6/nd6_nbr.c
@@ -643,6 +643,9 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len)
union nd_opts ndopts;
struct mbuf *chain = NULL;
struct sockaddr_in6 sin6;
+ u_char linkhdr[LLE_MAX_LINKHDR];
+ size_t linkhdrsize;
+ int lladdr_off;
char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
if (ip6->ip6_hlim != 255) {
@@ -765,7 +768,13 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len)
/*
* Record link-layer address, and update the state.
*/
- if (lltable_try_set_entry_addr(ifp, ln, lladdr) == 0) {
+ linkhdrsize = sizeof(linkhdr);
+ if (lltable_calc_llheader(ifp, AF_INET6, lladdr,
+ linkhdr, &linkhdrsize, &lladdr_off) != 0)
+ return;
+
+ if (lltable_try_set_entry_addr(ifp, ln, linkhdr, linkhdrsize,
+ lladdr_off) == 0) {
ln = NULL;
goto freeit;
}
@@ -792,7 +801,7 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len)
llchange = 0;
else {
if (ln->la_flags & LLE_VALID) {
- if (bcmp(lladdr, &ln->ll_addr, ifp->if_addrlen))
+ if (bcmp(lladdr, ln->ll_addr, ifp->if_addrlen))
llchange = 1;
else
llchange = 0;
@@ -834,9 +843,12 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len)
* Update link-local address, if any.
*/
if (lladdr != NULL) {
- int ret;
- ret = lltable_try_set_entry_addr(ifp, ln,lladdr);
- if (ret == 0) {
+ linkhdrsize = sizeof(linkhdr);
+ if (lltable_calc_llheader(ifp, AF_INET6, lladdr,
+ linkhdr, &linkhdrsize, &lladdr_off) != 0)
+ goto freeit;
+ if (lltable_try_set_entry_addr(ifp, ln, linkhdr,
+ linkhdrsize, lladdr_off) == 0) {
ln = NULL;
goto freeit;
}
diff --git a/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c b/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 1077b40..e1f2dc0 100644
--- a/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -1257,15 +1257,15 @@ ipoib_output(struct ifnet *ifp, struct mbuf *m,
const struct sockaddr *dst, struct route *ro)
{
u_char edst[INFINIBAND_ALEN];
+#if defined(INET) || defined(INET6)
struct llentry *lle = NULL;
+#endif
struct rtentry *rt0 = NULL;
struct ipoib_header *eh;
int error = 0, is_gw = 0;
short type;
if (ro != NULL) {
- if (!(m->m_flags & (M_BCAST | M_MCAST)))
- lle = ro->ro_lle;
rt0 = ro->ro_rt;
if (rt0 != NULL && (rt0->rt_flags & RTF_GATEWAY) != 0)
is_gw = 1;
@@ -1291,7 +1291,7 @@ ipoib_output(struct ifnet *ifp, struct mbuf *m,
#ifdef INET
case AF_INET:
if (lle != NULL && (lle->la_flags & LLE_VALID))
- memcpy(edst, &lle->ll_addr.mac8, sizeof(edst));
+ memcpy(edst, lle->ll_addr, sizeof(edst));
else if (m->m_flags & M_MCAST)
ip_ib_mc_map(((struct sockaddr_in *)dst)->sin_addr.s_addr, ifp->if_broadcastaddr, edst);
else
@@ -1329,7 +1329,7 @@ ipoib_output(struct ifnet *ifp, struct mbuf *m,
#ifdef INET6
case AF_INET6:
if (lle != NULL && (lle->la_flags & LLE_VALID))
- memcpy(edst, &lle->ll_addr.mac8, sizeof(edst));
+ memcpy(edst, lle->ll_addr, sizeof(edst));
else if (m->m_flags & M_MCAST)
ipv6_ib_mc_map(&((struct sockaddr_in6 *)dst)->sin6_addr, ifp->if_broadcastaddr, edst);
else
diff --git a/sys/opencrypto/skipjack.h b/sys/opencrypto/skipjack.h
index 3e88418..80367ea 100644
--- a/sys/opencrypto/skipjack.h
+++ b/sys/opencrypto/skipjack.h
@@ -14,6 +14,11 @@
* 29 May 1998
*/
+#ifndef _SKIPJACK_H_
+#define _SKIPJACK_H_
+
extern void skipjack_forwards(u_int8_t *plain, u_int8_t *cipher, u_int8_t **key);
extern void skipjack_backwards(u_int8_t *cipher, u_int8_t *plain, u_int8_t **key);
extern void subkey_table_gen(u_int8_t *key, u_int8_t **key_tables);
+
+#endif
diff --git a/sys/opencrypto/xform.c b/sys/opencrypto/xform.c
index 3dee366..ee9f0b6 100644
--- a/sys/opencrypto/xform.c
+++ b/sys/opencrypto/xform.c
@@ -75,196 +75,9 @@ __FBSDID("$FreeBSD$");
#include <opencrypto/cryptodev.h>
#include <opencrypto/xform.h>
-static int null_setkey(u_int8_t **, u_int8_t *, int);
-static int des1_setkey(u_int8_t **, u_int8_t *, int);
-static int des3_setkey(u_int8_t **, u_int8_t *, int);
-static int blf_setkey(u_int8_t **, u_int8_t *, int);
-static int cast5_setkey(u_int8_t **, u_int8_t *, int);
-static int skipjack_setkey(u_int8_t **, u_int8_t *, int);
-static int rijndael128_setkey(u_int8_t **, u_int8_t *, int);
-static int aes_icm_setkey(u_int8_t **, u_int8_t *, int);
-static int aes_xts_setkey(u_int8_t **, u_int8_t *, int);
-static int cml_setkey(u_int8_t **, u_int8_t *, int);
-
-static void null_encrypt(caddr_t, u_int8_t *);
-static void des1_encrypt(caddr_t, u_int8_t *);
-static void des3_encrypt(caddr_t, u_int8_t *);
-static void blf_encrypt(caddr_t, u_int8_t *);
-static void cast5_encrypt(caddr_t, u_int8_t *);
-static void skipjack_encrypt(caddr_t, u_int8_t *);
-static void rijndael128_encrypt(caddr_t, u_int8_t *);
-static void aes_xts_encrypt(caddr_t, u_int8_t *);
-static void cml_encrypt(caddr_t, u_int8_t *);
-
-static void null_decrypt(caddr_t, u_int8_t *);
-static void des1_decrypt(caddr_t, u_int8_t *);
-static void des3_decrypt(caddr_t, u_int8_t *);
-static void blf_decrypt(caddr_t, u_int8_t *);
-static void cast5_decrypt(caddr_t, u_int8_t *);
-static void skipjack_decrypt(caddr_t, u_int8_t *);
-static void rijndael128_decrypt(caddr_t, u_int8_t *);
-static void aes_xts_decrypt(caddr_t, u_int8_t *);
-static void cml_decrypt(caddr_t, u_int8_t *);
-
-static void aes_icm_crypt(caddr_t, u_int8_t *);
-
-static void null_zerokey(u_int8_t **);
-static void des1_zerokey(u_int8_t **);
-static void des3_zerokey(u_int8_t **);
-static void blf_zerokey(u_int8_t **);
-static void cast5_zerokey(u_int8_t **);
-static void skipjack_zerokey(u_int8_t **);
-static void rijndael128_zerokey(u_int8_t **);
-static void aes_icm_zerokey(u_int8_t **);
-static void aes_xts_zerokey(u_int8_t **);
-static void cml_zerokey(u_int8_t **);
-
-static void aes_icm_reinit(caddr_t, u_int8_t *);
-static void aes_xts_reinit(caddr_t, u_int8_t *);
-static void aes_gcm_reinit(caddr_t, u_int8_t *);
-
-static void null_init(void *);
-static void null_reinit(void *ctx, const u_int8_t *buf, u_int16_t len);
-static int null_update(void *, const u_int8_t *, u_int16_t);
-static void null_final(u_int8_t *, void *);
-static int MD5Update_int(void *, const u_int8_t *, u_int16_t);
-static void SHA1Init_int(void *);
-static int SHA1Update_int(void *, const u_int8_t *, u_int16_t);
-static void SHA1Final_int(u_int8_t *, void *);
-static int RMD160Update_int(void *, const u_int8_t *, u_int16_t);
-static int SHA256Update_int(void *, const u_int8_t *, u_int16_t);
-static int SHA384Update_int(void *, const u_int8_t *, u_int16_t);
-static int SHA512Update_int(void *, const u_int8_t *, u_int16_t);
-
-static u_int32_t deflate_compress(u_int8_t *, u_int32_t, u_int8_t **);
-static u_int32_t deflate_decompress(u_int8_t *, u_int32_t, u_int8_t **);
-
-#define AESICM_BLOCKSIZE AES_BLOCK_LEN
-
-struct aes_icm_ctx {
- u_int32_t ac_ek[4*(RIJNDAEL_MAXNR + 1)];
- /* ac_block is initalized to IV */
- u_int8_t ac_block[AESICM_BLOCKSIZE];
- int ac_nr;
-};
-
MALLOC_DEFINE(M_XDATA, "xform", "xform data buffers");
/* Encryption instances */
-struct enc_xform enc_xform_null = {
- CRYPTO_NULL_CBC, "NULL",
- /* NB: blocksize of 4 is to generate a properly aligned ESP header */
- NULL_BLOCK_LEN, 0, NULL_MIN_KEY, NULL_MAX_KEY,
- null_encrypt,
- null_decrypt,
- null_setkey,
- null_zerokey,
- NULL,
-};
-
-struct enc_xform enc_xform_des = {
- CRYPTO_DES_CBC, "DES",
- DES_BLOCK_LEN, DES_BLOCK_LEN, DES_MIN_KEY, DES_MAX_KEY,
- des1_encrypt,
- des1_decrypt,
- des1_setkey,
- des1_zerokey,
- NULL,
-};
-
-struct enc_xform enc_xform_3des = {
- CRYPTO_3DES_CBC, "3DES",
- DES3_BLOCK_LEN, DES3_BLOCK_LEN, TRIPLE_DES_MIN_KEY,
- TRIPLE_DES_MAX_KEY,
- des3_encrypt,
- des3_decrypt,
- des3_setkey,
- des3_zerokey,
- NULL,
-};
-
-struct enc_xform enc_xform_blf = {
- CRYPTO_BLF_CBC, "Blowfish",
- BLOWFISH_BLOCK_LEN, BLOWFISH_BLOCK_LEN, BLOWFISH_MIN_KEY,
- BLOWFISH_MAX_KEY,
- blf_encrypt,
- blf_decrypt,
- blf_setkey,
- blf_zerokey,
- NULL,
-};
-
-struct enc_xform enc_xform_cast5 = {
- CRYPTO_CAST_CBC, "CAST-128",
- CAST128_BLOCK_LEN, CAST128_BLOCK_LEN, CAST_MIN_KEY, CAST_MAX_KEY,
- cast5_encrypt,
- cast5_decrypt,
- cast5_setkey,
- cast5_zerokey,
- NULL,
-};
-
-struct enc_xform enc_xform_skipjack = {
- CRYPTO_SKIPJACK_CBC, "Skipjack",
- SKIPJACK_BLOCK_LEN, SKIPJACK_BLOCK_LEN, SKIPJACK_MIN_KEY,
- SKIPJACK_MAX_KEY,
- skipjack_encrypt,
- skipjack_decrypt, skipjack_setkey,
- skipjack_zerokey,
- NULL,
-};
-
-struct enc_xform enc_xform_rijndael128 = {
- CRYPTO_RIJNDAEL128_CBC, "Rijndael-128/AES",
- RIJNDAEL128_BLOCK_LEN, RIJNDAEL128_BLOCK_LEN, RIJNDAEL_MIN_KEY,
- RIJNDAEL_MAX_KEY,
- rijndael128_encrypt,
- rijndael128_decrypt,
- rijndael128_setkey,
- rijndael128_zerokey,
- NULL,
-};
-
-struct enc_xform enc_xform_aes_icm = {
- CRYPTO_AES_ICM, "AES-ICM",
- AES_BLOCK_LEN, AES_BLOCK_LEN, AES_MIN_KEY, AES_MAX_KEY,
- aes_icm_crypt,
- aes_icm_crypt,
- aes_icm_setkey,
- rijndael128_zerokey,
- aes_icm_reinit,
-};
-
-struct enc_xform enc_xform_aes_nist_gcm = {
- CRYPTO_AES_NIST_GCM_16, "AES-GCM",
- AES_ICM_BLOCK_LEN, AES_GCM_IV_LEN, AES_MIN_KEY, AES_MAX_KEY,
- aes_icm_crypt,
- aes_icm_crypt,
- aes_icm_setkey,
- aes_icm_zerokey,
- aes_gcm_reinit,
-};
-
-struct enc_xform enc_xform_aes_nist_gmac = {
- CRYPTO_AES_NIST_GMAC, "AES-GMAC",
- AES_ICM_BLOCK_LEN, AES_GCM_IV_LEN, AES_MIN_KEY, AES_MAX_KEY,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
-};
-
-struct enc_xform enc_xform_aes_xts = {
- CRYPTO_AES_XTS, "AES-XTS",
- AES_BLOCK_LEN, AES_XTS_IV_LEN, AES_XTS_MIN_KEY, AES_XTS_MAX_KEY,
- aes_xts_encrypt,
- aes_xts_decrypt,
- aes_xts_setkey,
- aes_xts_zerokey,
- aes_xts_reinit
-};
-
struct enc_xform enc_xform_arc4 = {
CRYPTO_ARC4, "ARC4",
ARC4_BLOCK_LEN, ARC4_IV_LEN, ARC4_MIN_KEY, ARC4_MAX_KEY,
@@ -275,711 +88,26 @@ struct enc_xform enc_xform_arc4 = {
NULL,
};
-struct enc_xform enc_xform_camellia = {
- CRYPTO_CAMELLIA_CBC, "Camellia",
- CAMELLIA_BLOCK_LEN, CAMELLIA_BLOCK_LEN, CAMELLIA_MIN_KEY,
- CAMELLIA_MAX_KEY,
- cml_encrypt,
- cml_decrypt,
- cml_setkey,
- cml_zerokey,
- NULL,
-};
-
-/* Authentication instances */
-struct auth_hash auth_hash_null = { /* NB: context isn't used */
- CRYPTO_NULL_HMAC, "NULL-HMAC",
- NULL_HMAC_KEY_LEN, NULL_HASH_LEN, sizeof(int), NULL_HMAC_BLOCK_LEN,
- null_init, null_reinit, null_reinit, null_update, null_final
-};
-
-struct auth_hash auth_hash_hmac_md5 = {
- CRYPTO_MD5_HMAC, "HMAC-MD5",
- MD5_HMAC_KEY_LEN, MD5_HASH_LEN, sizeof(MD5_CTX), MD5_HMAC_BLOCK_LEN,
- (void (*) (void *)) MD5Init, NULL, NULL, MD5Update_int,
- (void (*) (u_int8_t *, void *)) MD5Final
-};
-
-struct auth_hash auth_hash_hmac_sha1 = {
- CRYPTO_SHA1_HMAC, "HMAC-SHA1",
- SHA1_HMAC_KEY_LEN, SHA1_HASH_LEN, sizeof(SHA1_CTX), SHA1_HMAC_BLOCK_LEN,
- SHA1Init_int, NULL, NULL, SHA1Update_int, SHA1Final_int
-};
-
-struct auth_hash auth_hash_hmac_ripemd_160 = {
- CRYPTO_RIPEMD160_HMAC, "HMAC-RIPEMD-160",
- RIPEMD160_HMAC_KEY_LEN, RIPEMD160_HASH_LEN, sizeof(RMD160_CTX),
- RIPEMD160_HMAC_BLOCK_LEN,
- (void (*)(void *)) RMD160Init, NULL, NULL, RMD160Update_int,
- (void (*)(u_int8_t *, void *)) RMD160Final
-};
-
-struct auth_hash auth_hash_key_md5 = {
- CRYPTO_MD5_KPDK, "Keyed MD5",
- NULL_HMAC_KEY_LEN, MD5_KPDK_HASH_LEN, sizeof(MD5_CTX), 0,
- (void (*)(void *)) MD5Init, NULL, NULL, MD5Update_int,
- (void (*)(u_int8_t *, void *)) MD5Final
-};
-
-struct auth_hash auth_hash_key_sha1 = {
- CRYPTO_SHA1_KPDK, "Keyed SHA1",
- NULL_HMAC_KEY_LEN, SHA1_KPDK_HASH_LEN, sizeof(SHA1_CTX), 0,
- SHA1Init_int, NULL, NULL, SHA1Update_int, SHA1Final_int
-};
-
-struct auth_hash auth_hash_hmac_sha2_256 = {
- CRYPTO_SHA2_256_HMAC, "HMAC-SHA2-256",
- SHA2_256_HMAC_KEY_LEN, SHA2_256_HASH_LEN, sizeof(SHA256_CTX),
- SHA2_256_HMAC_BLOCK_LEN,
- (void (*)(void *)) SHA256_Init, NULL, NULL, SHA256Update_int,
- (void (*)(u_int8_t *, void *)) SHA256_Final
-};
-
-struct auth_hash auth_hash_hmac_sha2_384 = {
- CRYPTO_SHA2_384_HMAC, "HMAC-SHA2-384",
- SHA2_384_HMAC_KEY_LEN, SHA2_384_HASH_LEN, sizeof(SHA384_CTX),
- SHA2_384_HMAC_BLOCK_LEN,
- (void (*)(void *)) SHA384_Init, NULL, NULL, SHA384Update_int,
- (void (*)(u_int8_t *, void *)) SHA384_Final
-};
-
-struct auth_hash auth_hash_hmac_sha2_512 = {
- CRYPTO_SHA2_512_HMAC, "HMAC-SHA2-512",
- SHA2_512_HMAC_KEY_LEN, SHA2_512_HASH_LEN, sizeof(SHA512_CTX),
- SHA2_512_HMAC_BLOCK_LEN,
- (void (*)(void *)) SHA512_Init, NULL, NULL, SHA512Update_int,
- (void (*)(u_int8_t *, void *)) SHA512_Final
-};
-
-struct auth_hash auth_hash_nist_gmac_aes_128 = {
- CRYPTO_AES_128_NIST_GMAC, "GMAC-AES-128",
- AES_128_GMAC_KEY_LEN, AES_GMAC_HASH_LEN, sizeof(struct aes_gmac_ctx),
- GMAC_BLOCK_LEN,
- (void (*)(void *)) AES_GMAC_Init,
- (void (*)(void *, const u_int8_t *, u_int16_t)) AES_GMAC_Setkey,
- (void (*)(void *, const u_int8_t *, u_int16_t)) AES_GMAC_Reinit,
- (int (*)(void *, const u_int8_t *, u_int16_t)) AES_GMAC_Update,
- (void (*)(u_int8_t *, void *)) AES_GMAC_Final
-};
-
-struct auth_hash auth_hash_nist_gmac_aes_192 = {
- CRYPTO_AES_192_NIST_GMAC, "GMAC-AES-192",
- AES_192_GMAC_KEY_LEN, AES_GMAC_HASH_LEN, sizeof(struct aes_gmac_ctx),
- GMAC_BLOCK_LEN,
- (void (*)(void *)) AES_GMAC_Init,
- (void (*)(void *, const u_int8_t *, u_int16_t)) AES_GMAC_Setkey,
- (void (*)(void *, const u_int8_t *, u_int16_t)) AES_GMAC_Reinit,
- (int (*)(void *, const u_int8_t *, u_int16_t)) AES_GMAC_Update,
- (void (*)(u_int8_t *, void *)) AES_GMAC_Final
-};
-
-struct auth_hash auth_hash_nist_gmac_aes_256 = {
- CRYPTO_AES_256_NIST_GMAC, "GMAC-AES-256",
- AES_256_GMAC_KEY_LEN, AES_GMAC_HASH_LEN, sizeof(struct aes_gmac_ctx),
- GMAC_BLOCK_LEN,
- (void (*)(void *)) AES_GMAC_Init,
- (void (*)(void *, const u_int8_t *, u_int16_t)) AES_GMAC_Setkey,
- (void (*)(void *, const u_int8_t *, u_int16_t)) AES_GMAC_Reinit,
- (int (*)(void *, const u_int8_t *, u_int16_t)) AES_GMAC_Update,
- (void (*)(u_int8_t *, void *)) AES_GMAC_Final
-};
-
-/* Compression instance */
-struct comp_algo comp_algo_deflate = {
- CRYPTO_DEFLATE_COMP, "Deflate",
- 90, deflate_compress,
- deflate_decompress
-};
-
-/*
- * Encryption wrapper routines.
- */
-static void
-null_encrypt(caddr_t key, u_int8_t *blk)
-{
-}
-static void
-null_decrypt(caddr_t key, u_int8_t *blk)
-{
-}
-static int
-null_setkey(u_int8_t **sched, u_int8_t *key, int len)
-{
- *sched = NULL;
- return 0;
-}
-static void
-null_zerokey(u_int8_t **sched)
-{
- *sched = NULL;
-}
-
-static void
-des1_encrypt(caddr_t key, u_int8_t *blk)
-{
- des_cblock *cb = (des_cblock *) blk;
- des_key_schedule *p = (des_key_schedule *) key;
-
- des_ecb_encrypt(cb, cb, p[0], DES_ENCRYPT);
-}
-
-static void
-des1_decrypt(caddr_t key, u_int8_t *blk)
-{
- des_cblock *cb = (des_cblock *) blk;
- des_key_schedule *p = (des_key_schedule *) key;
-
- des_ecb_encrypt(cb, cb, p[0], DES_DECRYPT);
-}
-
-static int
-des1_setkey(u_int8_t **sched, u_int8_t *key, int len)
-{
- des_key_schedule *p;
- int err;
-
- p = malloc(sizeof (des_key_schedule),
- M_CRYPTO_DATA, M_NOWAIT|M_ZERO);
- if (p != NULL) {
- des_set_key((des_cblock *) key, p[0]);
- err = 0;
- } else
- err = ENOMEM;
- *sched = (u_int8_t *) p;
- return err;
-}
-
-static void
-des1_zerokey(u_int8_t **sched)
-{
- bzero(*sched, sizeof (des_key_schedule));
- free(*sched, M_CRYPTO_DATA);
- *sched = NULL;
-}
-
-static void
-des3_encrypt(caddr_t key, u_int8_t *blk)
-{
- des_cblock *cb = (des_cblock *) blk;
- des_key_schedule *p = (des_key_schedule *) key;
-
- des_ecb3_encrypt(cb, cb, p[0], p[1], p[2], DES_ENCRYPT);
-}
-
-static void
-des3_decrypt(caddr_t key, u_int8_t *blk)
-{
- des_cblock *cb = (des_cblock *) blk;
- des_key_schedule *p = (des_key_schedule *) key;
-
- des_ecb3_encrypt(cb, cb, p[0], p[1], p[2], DES_DECRYPT);
-}
-
-static int
-des3_setkey(u_int8_t **sched, u_int8_t *key, int len)
-{
- des_key_schedule *p;
- int err;
-
- p = malloc(3*sizeof (des_key_schedule),
- M_CRYPTO_DATA, M_NOWAIT|M_ZERO);
- if (p != NULL) {
- des_set_key((des_cblock *)(key + 0), p[0]);
- des_set_key((des_cblock *)(key + 8), p[1]);
- des_set_key((des_cblock *)(key + 16), p[2]);
- err = 0;
- } else
- err = ENOMEM;
- *sched = (u_int8_t *) p;
- return err;
-}
-
-static void
-des3_zerokey(u_int8_t **sched)
-{
- bzero(*sched, 3*sizeof (des_key_schedule));
- free(*sched, M_CRYPTO_DATA);
- *sched = NULL;
-}
-
-static void
-blf_encrypt(caddr_t key, u_int8_t *blk)
-{
- BF_LONG t[2];
-
- memcpy(t, blk, sizeof (t));
- t[0] = ntohl(t[0]);
- t[1] = ntohl(t[1]);
- /* NB: BF_encrypt expects the block in host order! */
- BF_encrypt(t, (BF_KEY *) key);
- t[0] = htonl(t[0]);
- t[1] = htonl(t[1]);
- memcpy(blk, t, sizeof (t));
-}
-
-static void
-blf_decrypt(caddr_t key, u_int8_t *blk)
-{
- BF_LONG t[2];
-
- memcpy(t, blk, sizeof (t));
- t[0] = ntohl(t[0]);
- t[1] = ntohl(t[1]);
- /* NB: BF_decrypt expects the block in host order! */
- BF_decrypt(t, (BF_KEY *) key);
- t[0] = htonl(t[0]);
- t[1] = htonl(t[1]);
- memcpy(blk, t, sizeof (t));
-}
-
-static int
-blf_setkey(u_int8_t **sched, u_int8_t *key, int len)
-{
- int err;
-
- *sched = malloc(sizeof(BF_KEY),
- M_CRYPTO_DATA, M_NOWAIT|M_ZERO);
- if (*sched != NULL) {
- BF_set_key((BF_KEY *) *sched, len, key);
- err = 0;
- } else
- err = ENOMEM;
- return err;
-}
-
-static void
-blf_zerokey(u_int8_t **sched)
-{
- bzero(*sched, sizeof(BF_KEY));
- free(*sched, M_CRYPTO_DATA);
- *sched = NULL;
-}
-
-static void
-cast5_encrypt(caddr_t key, u_int8_t *blk)
-{
- cast_encrypt((cast_key *) key, blk, blk);
-}
-
-static void
-cast5_decrypt(caddr_t key, u_int8_t *blk)
-{
- cast_decrypt((cast_key *) key, blk, blk);
-}
-
-static int
-cast5_setkey(u_int8_t **sched, u_int8_t *key, int len)
-{
- int err;
-
- *sched = malloc(sizeof(cast_key), M_CRYPTO_DATA, M_NOWAIT|M_ZERO);
- if (*sched != NULL) {
- cast_setkey((cast_key *)*sched, key, len);
- err = 0;
- } else
- err = ENOMEM;
- return err;
-}
-
-static void
-cast5_zerokey(u_int8_t **sched)
-{
- bzero(*sched, sizeof(cast_key));
- free(*sched, M_CRYPTO_DATA);
- *sched = NULL;
-}
-
-static void
-skipjack_encrypt(caddr_t key, u_int8_t *blk)
-{
- skipjack_forwards(blk, blk, (u_int8_t **) key);
-}
-
-static void
-skipjack_decrypt(caddr_t key, u_int8_t *blk)
-{
- skipjack_backwards(blk, blk, (u_int8_t **) key);
-}
-
-static int
-skipjack_setkey(u_int8_t **sched, u_int8_t *key, int len)
-{
- int err;
-
- /* NB: allocate all the memory that's needed at once */
- *sched = malloc(10 * (sizeof(u_int8_t *) + 0x100),
- M_CRYPTO_DATA, M_NOWAIT|M_ZERO);
- if (*sched != NULL) {
- u_int8_t** key_tables = (u_int8_t**) *sched;
- u_int8_t* table = (u_int8_t*) &key_tables[10];
- int k;
-
- for (k = 0; k < 10; k++) {
- key_tables[k] = table;
- table += 0x100;
- }
- subkey_table_gen(key, (u_int8_t **) *sched);
- err = 0;
- } else
- err = ENOMEM;
- return err;
-}
-
-static void
-skipjack_zerokey(u_int8_t **sched)
-{
- bzero(*sched, 10 * (sizeof(u_int8_t *) + 0x100));
- free(*sched, M_CRYPTO_DATA);
- *sched = NULL;
-}
-
-static void
-rijndael128_encrypt(caddr_t key, u_int8_t *blk)
-{
- rijndael_encrypt((rijndael_ctx *) key, (u_char *) blk, (u_char *) blk);
-}
-
-static void
-rijndael128_decrypt(caddr_t key, u_int8_t *blk)
-{
- rijndael_decrypt(((rijndael_ctx *) key), (u_char *) blk,
- (u_char *) blk);
-}
-
-static int
-rijndael128_setkey(u_int8_t **sched, u_int8_t *key, int len)
-{
- int err;
-
- if (len != 16 && len != 24 && len != 32)
- return (EINVAL);
- *sched = malloc(sizeof(rijndael_ctx), M_CRYPTO_DATA,
- M_NOWAIT|M_ZERO);
- if (*sched != NULL) {
- rijndael_set_key((rijndael_ctx *) *sched, (u_char *) key,
- len * 8);
- err = 0;
- } else
- err = ENOMEM;
- return err;
-}
-
-static void
-rijndael128_zerokey(u_int8_t **sched)
-{
- bzero(*sched, sizeof(rijndael_ctx));
- free(*sched, M_CRYPTO_DATA);
- *sched = NULL;
-}
-
-void
-aes_icm_reinit(caddr_t key, u_int8_t *iv)
-{
- struct aes_icm_ctx *ctx;
-
- ctx = (struct aes_icm_ctx *)key;
- bcopy(iv, ctx->ac_block, AESICM_BLOCKSIZE);
-}
-
-void
-aes_gcm_reinit(caddr_t key, u_int8_t *iv)
-{
- struct aes_icm_ctx *ctx;
-
- aes_icm_reinit(key, iv);
-
- ctx = (struct aes_icm_ctx *)key;
- /* GCM starts with 2 as counter 1 is used for final xor of tag. */
- bzero(&ctx->ac_block[AESICM_BLOCKSIZE - 4], 4);
- ctx->ac_block[AESICM_BLOCKSIZE - 1] = 2;
-}
-
-void
-aes_icm_crypt(caddr_t key, u_int8_t *data)
-{
- struct aes_icm_ctx *ctx;
- u_int8_t keystream[AESICM_BLOCKSIZE];
- int i;
-
- ctx = (struct aes_icm_ctx *)key;
- rijndaelEncrypt(ctx->ac_ek, ctx->ac_nr, ctx->ac_block, keystream);
- for (i = 0; i < AESICM_BLOCKSIZE; i++)
- data[i] ^= keystream[i];
- explicit_bzero(keystream, sizeof(keystream));
-
- /* increment counter */
- for (i = AESICM_BLOCKSIZE - 1;
- i >= 0; i--)
- if (++ctx->ac_block[i]) /* continue on overflow */
- break;
-}
-
-int
-aes_icm_setkey(u_int8_t **sched, u_int8_t *key, int len)
-{
- struct aes_icm_ctx *ctx;
-
- if (len != 16 && len != 24 && len != 32)
- return EINVAL;
-
- *sched = malloc(sizeof(struct aes_icm_ctx), M_CRYPTO_DATA,
- M_NOWAIT | M_ZERO);
- if (*sched == NULL)
- return ENOMEM;
-
- ctx = (struct aes_icm_ctx *)*sched;
- ctx->ac_nr = rijndaelKeySetupEnc(ctx->ac_ek, (u_char *)key, len * 8);
- return 0;
-}
-
-void
-aes_icm_zerokey(u_int8_t **sched)
-{
-
- bzero(*sched, sizeof(struct aes_icm_ctx));
- free(*sched, M_CRYPTO_DATA);
- *sched = NULL;
-}
-
-#define AES_XTS_BLOCKSIZE 16
-#define AES_XTS_IVSIZE 8
-#define AES_XTS_ALPHA 0x87 /* GF(2^128) generator polynomial */
-
-struct aes_xts_ctx {
- rijndael_ctx key1;
- rijndael_ctx key2;
- u_int8_t tweak[AES_XTS_BLOCKSIZE];
-};
-
-void
-aes_xts_reinit(caddr_t key, u_int8_t *iv)
-{
- struct aes_xts_ctx *ctx = (struct aes_xts_ctx *)key;
- u_int64_t blocknum;
- u_int i;
-
- /*
- * Prepare tweak as E_k2(IV). IV is specified as LE representation
- * of a 64-bit block number which we allow to be passed in directly.
- */
- bcopy(iv, &blocknum, AES_XTS_IVSIZE);
- for (i = 0; i < AES_XTS_IVSIZE; i++) {
- ctx->tweak[i] = blocknum & 0xff;
- blocknum >>= 8;
- }
- /* Last 64 bits of IV are always zero */
- bzero(ctx->tweak + AES_XTS_IVSIZE, AES_XTS_IVSIZE);
-
- rijndael_encrypt(&ctx->key2, ctx->tweak, ctx->tweak);
-}
-
-static void
-aes_xts_crypt(struct aes_xts_ctx *ctx, u_int8_t *data, u_int do_encrypt)
-{
- u_int8_t block[AES_XTS_BLOCKSIZE];
- u_int i, carry_in, carry_out;
-
- for (i = 0; i < AES_XTS_BLOCKSIZE; i++)
- block[i] = data[i] ^ ctx->tweak[i];
-
- if (do_encrypt)
- rijndael_encrypt(&ctx->key1, block, data);
- else
- rijndael_decrypt(&ctx->key1, block, data);
-
- for (i = 0; i < AES_XTS_BLOCKSIZE; i++)
- data[i] ^= ctx->tweak[i];
-
- /* Exponentiate tweak */
- carry_in = 0;
- for (i = 0; i < AES_XTS_BLOCKSIZE; i++) {
- carry_out = ctx->tweak[i] & 0x80;
- ctx->tweak[i] = (ctx->tweak[i] << 1) | (carry_in ? 1 : 0);
- carry_in = carry_out;
- }
- if (carry_in)
- ctx->tweak[0] ^= AES_XTS_ALPHA;
- bzero(block, sizeof(block));
-}
-
-void
-aes_xts_encrypt(caddr_t key, u_int8_t *data)
-{
- aes_xts_crypt((struct aes_xts_ctx *)key, data, 1);
-}
-
-void
-aes_xts_decrypt(caddr_t key, u_int8_t *data)
-{
- aes_xts_crypt((struct aes_xts_ctx *)key, data, 0);
-}
-
-int
-aes_xts_setkey(u_int8_t **sched, u_int8_t *key, int len)
-{
- struct aes_xts_ctx *ctx;
-
- if (len != 32 && len != 64)
- return EINVAL;
-
- *sched = malloc(sizeof(struct aes_xts_ctx), M_CRYPTO_DATA,
- M_NOWAIT | M_ZERO);
- if (*sched == NULL)
- return ENOMEM;
- ctx = (struct aes_xts_ctx *)*sched;
-
- rijndael_set_key(&ctx->key1, key, len * 4);
- rijndael_set_key(&ctx->key2, key + (len / 2), len * 4);
-
- return 0;
-}
-void
-aes_xts_zerokey(u_int8_t **sched)
-{
- bzero(*sched, sizeof(struct aes_xts_ctx));
- free(*sched, M_CRYPTO_DATA);
- *sched = NULL;
-}
+/* Include the encryption algorithms */
+#include "xform_null.c"
+#include "xform_des1.c"
+#include "xform_des3.c"
+#include "xform_blf.c"
+#include "xform_cast5.c"
+#include "xform_skipjack.c"
+#include "xform_rijndael.c"
+#include "xform_aes_icm.c"
+#include "xform_aes_xts.c"
+#include "xform_cml.c"
-static void
-cml_encrypt(caddr_t key, u_int8_t *blk)
-{
- camellia_encrypt((camellia_ctx *) key, (u_char *) blk, (u_char *) blk);
-}
-
-static void
-cml_decrypt(caddr_t key, u_int8_t *blk)
-{
- camellia_decrypt(((camellia_ctx *) key), (u_char *) blk,
- (u_char *) blk);
-}
-
-static int
-cml_setkey(u_int8_t **sched, u_int8_t *key, int len)
-{
- int err;
-
- if (len != 16 && len != 24 && len != 32)
- return (EINVAL);
- *sched = malloc(sizeof(camellia_ctx), M_CRYPTO_DATA,
- M_NOWAIT|M_ZERO);
- if (*sched != NULL) {
- camellia_set_key((camellia_ctx *) *sched, (u_char *) key,
- len * 8);
- err = 0;
- } else
- err = ENOMEM;
- return err;
-}
-
-static void
-cml_zerokey(u_int8_t **sched)
-{
- bzero(*sched, sizeof(camellia_ctx));
- free(*sched, M_CRYPTO_DATA);
- *sched = NULL;
-}
-
-/*
- * And now for auth.
- */
-
-static void
-null_init(void *ctx)
-{
-}
-
-static void
-null_reinit(void *ctx, const u_int8_t *buf, u_int16_t len)
-{
-}
-
-static int
-null_update(void *ctx, const u_int8_t *buf, u_int16_t len)
-{
- return 0;
-}
-
-static void
-null_final(u_int8_t *buf, void *ctx)
-{
- if (buf != (u_int8_t *) 0)
- bzero(buf, 12);
-}
-
-static int
-RMD160Update_int(void *ctx, const u_int8_t *buf, u_int16_t len)
-{
- RMD160Update(ctx, buf, len);
- return 0;
-}
-
-static int
-MD5Update_int(void *ctx, const u_int8_t *buf, u_int16_t len)
-{
- MD5Update(ctx, buf, len);
- return 0;
-}
-
-static void
-SHA1Init_int(void *ctx)
-{
- SHA1Init(ctx);
-}
-
-static int
-SHA1Update_int(void *ctx, const u_int8_t *buf, u_int16_t len)
-{
- SHA1Update(ctx, buf, len);
- return 0;
-}
-
-static void
-SHA1Final_int(u_int8_t *blk, void *ctx)
-{
- SHA1Final(blk, ctx);
-}
-
-static int
-SHA256Update_int(void *ctx, const u_int8_t *buf, u_int16_t len)
-{
- SHA256_Update(ctx, buf, len);
- return 0;
-}
-
-static int
-SHA384Update_int(void *ctx, const u_int8_t *buf, u_int16_t len)
-{
- SHA384_Update(ctx, buf, len);
- return 0;
-}
-
-static int
-SHA512Update_int(void *ctx, const u_int8_t *buf, u_int16_t len)
-{
- SHA512_Update(ctx, buf, len);
- return 0;
-}
-
-/*
- * And compression
- */
+/* Include the authentication and hashing algorithms */
+#include "xform_gmac.c"
+#include "xform_md5.c"
+#include "xform_rmd160.c"
+#include "xform_sha1.c"
+#include "xform_sha2.c"
-static u_int32_t
-deflate_compress(data, size, out)
- u_int8_t *data;
- u_int32_t size;
- u_int8_t **out;
-{
- return deflate_global(data, size, 0, out);
-}
+/* Include the compression algorithms */
+#include "xform_deflate.c"
-static u_int32_t
-deflate_decompress(data, size, out)
- u_int8_t *data;
- u_int32_t size;
- u_int8_t **out;
-{
- return deflate_global(data, size, 1, out);
-}
diff --git a/sys/opencrypto/xform.h b/sys/opencrypto/xform.h
index 185e203..a176fe7 100644
--- a/sys/opencrypto/xform.h
+++ b/sys/opencrypto/xform.h
@@ -39,83 +39,9 @@
#include <opencrypto/rmd160.h>
#include <opencrypto/gmac.h>
-/* Declarations */
-struct auth_hash {
- int type;
- char *name;
- u_int16_t keysize;
- u_int16_t hashsize;
- u_int16_t ctxsize;
- u_int16_t blocksize;
- void (*Init) (void *);
- void (*Setkey) (void *, const u_int8_t *, u_int16_t);
- void (*Reinit) (void *, const u_int8_t *, u_int16_t);
- int (*Update) (void *, const u_int8_t *, u_int16_t);
- void (*Final) (u_int8_t *, void *);
-};
-
-/* XXX use a define common with other hash stuff ! */
-#define AH_ALEN_MAX 64 /* max authenticator hash length */
-
-struct enc_xform {
- int type;
- char *name;
- u_int16_t blocksize;
- u_int16_t ivsize;
- u_int16_t minkey, maxkey;
- void (*encrypt) (caddr_t, u_int8_t *);
- void (*decrypt) (caddr_t, u_int8_t *);
- int (*setkey) (u_int8_t **, u_int8_t *, int len);
- void (*zerokey) (u_int8_t **);
- void (*reinit) (caddr_t, u_int8_t *);
-};
-
-struct comp_algo {
- int type;
- char *name;
- size_t minlen;
- u_int32_t (*compress) (u_int8_t *, u_int32_t, u_int8_t **);
- u_int32_t (*decompress) (u_int8_t *, u_int32_t, u_int8_t **);
-};
-
-union authctx {
- MD5_CTX md5ctx;
- SHA1_CTX sha1ctx;
- RMD160_CTX rmd160ctx;
- SHA256_CTX sha256ctx;
- SHA384_CTX sha384ctx;
- SHA512_CTX sha512ctx;
- struct aes_gmac_ctx aes_gmac_ctx;
-};
-
-extern struct enc_xform enc_xform_null;
-extern struct enc_xform enc_xform_des;
-extern struct enc_xform enc_xform_3des;
-extern struct enc_xform enc_xform_blf;
-extern struct enc_xform enc_xform_cast5;
-extern struct enc_xform enc_xform_skipjack;
-extern struct enc_xform enc_xform_rijndael128;
-extern struct enc_xform enc_xform_aes_icm;
-extern struct enc_xform enc_xform_aes_nist_gcm;
-extern struct enc_xform enc_xform_aes_nist_gmac;
-extern struct enc_xform enc_xform_aes_xts;
-extern struct enc_xform enc_xform_arc4;
-extern struct enc_xform enc_xform_camellia;
-
-extern struct auth_hash auth_hash_null;
-extern struct auth_hash auth_hash_key_md5;
-extern struct auth_hash auth_hash_key_sha1;
-extern struct auth_hash auth_hash_hmac_md5;
-extern struct auth_hash auth_hash_hmac_sha1;
-extern struct auth_hash auth_hash_hmac_ripemd_160;
-extern struct auth_hash auth_hash_hmac_sha2_256;
-extern struct auth_hash auth_hash_hmac_sha2_384;
-extern struct auth_hash auth_hash_hmac_sha2_512;
-extern struct auth_hash auth_hash_nist_gmac_aes_128;
-extern struct auth_hash auth_hash_nist_gmac_aes_192;
-extern struct auth_hash auth_hash_nist_gmac_aes_256;
-
-extern struct comp_algo comp_algo_deflate;
+#include <opencrypto/xform_auth.h>
+#include <opencrypto/xform_comp.h>
+#include <opencrypto/xform_enc.h>
#ifdef _KERNEL
#include <sys/malloc.h>
diff --git a/sys/opencrypto/xform_aes_icm.c b/sys/opencrypto/xform_aes_icm.c
new file mode 100644
index 0000000..f4ce885
--- /dev/null
+++ b/sys/opencrypto/xform_aes_icm.c
@@ -0,0 +1,152 @@
+/* $OpenBSD: xform.c,v 1.16 2001/08/28 12:20:43 ben Exp $ */
+/*-
+ * The authors of this code are John Ioannidis (ji@tla.org),
+ * Angelos D. Keromytis (kermit@csd.uch.gr),
+ * Niels Provos (provos@physnet.uni-hamburg.de) and
+ * Damien Miller (djm@mindrot.org).
+ *
+ * This code was written by John Ioannidis for BSD/OS in Athens, Greece,
+ * in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis.
+ *
+ * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
+ * and Niels Provos.
+ *
+ * Additional features in 1999 by Angelos D. Keromytis.
+ *
+ * AES XTS implementation in 2008 by Damien Miller
+ *
+ * Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
+ * Angelos D. Keromytis and Niels Provos.
+ *
+ * Copyright (C) 2001, Angelos D. Keromytis.
+ *
+ * Copyright (C) 2008, Damien Miller
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by John-Mark Gurney
+ * under sponsorship of the FreeBSD Foundation and
+ * Rubicon Communications, LLC (Netgate).
+ *
+ * Permission to use, copy, and modify this software with or without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ * You may use this code under the GNU public license if you so wish. Please
+ * contribute changes back to the authors under this freer than GPL license
+ * so that we may further the use of strong encryption without limitations to
+ * all.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <opencrypto/xform_enc.h>
+
+static int aes_icm_setkey(u_int8_t **, u_int8_t *, int);
+static void aes_icm_crypt(caddr_t, u_int8_t *);
+static void aes_icm_zerokey(u_int8_t **);
+static void aes_icm_reinit(caddr_t, u_int8_t *);
+static void aes_gcm_reinit(caddr_t, u_int8_t *);
+
+/* Encryption instances */
+struct enc_xform enc_xform_aes_icm = {
+ CRYPTO_AES_ICM, "AES-ICM",
+ AES_BLOCK_LEN, AES_BLOCK_LEN, AES_MIN_KEY, AES_MAX_KEY,
+ aes_icm_crypt,
+ aes_icm_crypt,
+ aes_icm_setkey,
+ rijndael128_zerokey,
+ aes_icm_reinit,
+};
+
+struct enc_xform enc_xform_aes_nist_gcm = {
+ CRYPTO_AES_NIST_GCM_16, "AES-GCM",
+ AES_ICM_BLOCK_LEN, AES_GCM_IV_LEN, AES_MIN_KEY, AES_MAX_KEY,
+ aes_icm_crypt,
+ aes_icm_crypt,
+ aes_icm_setkey,
+ aes_icm_zerokey,
+ aes_gcm_reinit,
+};
+
+/*
+ * Encryption wrapper routines.
+ */
+static void
+aes_icm_reinit(caddr_t key, u_int8_t *iv)
+{
+ struct aes_icm_ctx *ctx;
+
+ ctx = (struct aes_icm_ctx *)key;
+ bcopy(iv, ctx->ac_block, AESICM_BLOCKSIZE);
+}
+
+static void
+aes_gcm_reinit(caddr_t key, u_int8_t *iv)
+{
+ struct aes_icm_ctx *ctx;
+
+ aes_icm_reinit(key, iv);
+
+ ctx = (struct aes_icm_ctx *)key;
+ /* GCM starts with 2 as counter 1 is used for final xor of tag. */
+ bzero(&ctx->ac_block[AESICM_BLOCKSIZE - 4], 4);
+ ctx->ac_block[AESICM_BLOCKSIZE - 1] = 2;
+}
+
+static void
+aes_icm_crypt(caddr_t key, u_int8_t *data)
+{
+ struct aes_icm_ctx *ctx;
+ u_int8_t keystream[AESICM_BLOCKSIZE];
+ int i;
+
+ ctx = (struct aes_icm_ctx *)key;
+ rijndaelEncrypt(ctx->ac_ek, ctx->ac_nr, ctx->ac_block, keystream);
+ for (i = 0; i < AESICM_BLOCKSIZE; i++)
+ data[i] ^= keystream[i];
+ explicit_bzero(keystream, sizeof(keystream));
+
+ /* increment counter */
+ for (i = AESICM_BLOCKSIZE - 1;
+ i >= 0; i--)
+ if (++ctx->ac_block[i]) /* continue on overflow */
+ break;
+}
+
+static int
+aes_icm_setkey(u_int8_t **sched, u_int8_t *key, int len)
+{
+ struct aes_icm_ctx *ctx;
+
+ if (len != 16 && len != 24 && len != 32)
+ return EINVAL;
+
+ *sched = KMALLOC(sizeof(struct aes_icm_ctx), M_CRYPTO_DATA,
+ M_NOWAIT | M_ZERO);
+ if (*sched == NULL)
+ return ENOMEM;
+
+ ctx = (struct aes_icm_ctx *)*sched;
+ ctx->ac_nr = rijndaelKeySetupEnc(ctx->ac_ek, (u_char *)key, len * 8);
+ return 0;
+}
+
+static void
+aes_icm_zerokey(u_int8_t **sched)
+{
+
+ bzero(*sched, sizeof(struct aes_icm_ctx));
+ KFREE(*sched, M_CRYPTO_DATA);
+ *sched = NULL;
+}
diff --git a/sys/opencrypto/xform_aes_xts.c b/sys/opencrypto/xform_aes_xts.c
new file mode 100644
index 0000000..dedbe62
--- /dev/null
+++ b/sys/opencrypto/xform_aes_xts.c
@@ -0,0 +1,164 @@
+/* $OpenBSD: xform.c,v 1.16 2001/08/28 12:20:43 ben Exp $ */
+/*-
+ * The authors of this code are John Ioannidis (ji@tla.org),
+ * Angelos D. Keromytis (kermit@csd.uch.gr),
+ * Niels Provos (provos@physnet.uni-hamburg.de) and
+ * Damien Miller (djm@mindrot.org).
+ *
+ * This code was written by John Ioannidis for BSD/OS in Athens, Greece,
+ * in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis.
+ *
+ * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
+ * and Niels Provos.
+ *
+ * Additional features in 1999 by Angelos D. Keromytis.
+ *
+ * AES XTS implementation in 2008 by Damien Miller
+ *
+ * Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
+ * Angelos D. Keromytis and Niels Provos.
+ *
+ * Copyright (C) 2001, Angelos D. Keromytis.
+ *
+ * Copyright (C) 2008, Damien Miller
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by John-Mark Gurney
+ * under sponsorship of the FreeBSD Foundation and
+ * Rubicon Communications, LLC (Netgate).
+ *
+ * Permission to use, copy, and modify this software with or without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ * You may use this code under the GNU public license if you so wish. Please
+ * contribute changes back to the authors under this freer than GPL license
+ * so that we may further the use of strong encryption without limitations to
+ * all.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <opencrypto/xform_enc.h>
+
+static int aes_xts_setkey(u_int8_t **, u_int8_t *, int);
+static void aes_xts_encrypt(caddr_t, u_int8_t *);
+static void aes_xts_decrypt(caddr_t, u_int8_t *);
+static void aes_xts_zerokey(u_int8_t **);
+static void aes_xts_reinit(caddr_t, u_int8_t *);
+
+/* Encryption instances */
+struct enc_xform enc_xform_aes_xts = {
+ CRYPTO_AES_XTS, "AES-XTS",
+ AES_BLOCK_LEN, AES_XTS_IV_LEN, AES_XTS_MIN_KEY, AES_XTS_MAX_KEY,
+ aes_xts_encrypt,
+ aes_xts_decrypt,
+ aes_xts_setkey,
+ aes_xts_zerokey,
+ aes_xts_reinit
+};
+
+/*
+ * Encryption wrapper routines.
+ */
+static void
+aes_xts_reinit(caddr_t key, u_int8_t *iv)
+{
+ struct aes_xts_ctx *ctx = (struct aes_xts_ctx *)key;
+ u_int64_t blocknum;
+ u_int i;
+
+ /*
+ * Prepare tweak as E_k2(IV). IV is specified as LE representation
+ * of a 64-bit block number which we allow to be passed in directly.
+ */
+ bcopy(iv, &blocknum, AES_XTS_IVSIZE);
+ for (i = 0; i < AES_XTS_IVSIZE; i++) {
+ ctx->tweak[i] = blocknum & 0xff;
+ blocknum >>= 8;
+ }
+ /* Last 64 bits of IV are always zero */
+ bzero(ctx->tweak + AES_XTS_IVSIZE, AES_XTS_IVSIZE);
+
+ rijndael_encrypt(&ctx->key2, ctx->tweak, ctx->tweak);
+}
+
+static void
+aes_xts_crypt(struct aes_xts_ctx *ctx, u_int8_t *data, u_int do_encrypt)
+{
+ u_int8_t block[AES_XTS_BLOCKSIZE];
+ u_int i, carry_in, carry_out;
+
+ for (i = 0; i < AES_XTS_BLOCKSIZE; i++)
+ block[i] = data[i] ^ ctx->tweak[i];
+
+ if (do_encrypt)
+ rijndael_encrypt(&ctx->key1, block, data);
+ else
+ rijndael_decrypt(&ctx->key1, block, data);
+
+ for (i = 0; i < AES_XTS_BLOCKSIZE; i++)
+ data[i] ^= ctx->tweak[i];
+
+ /* Exponentiate tweak */
+ carry_in = 0;
+ for (i = 0; i < AES_XTS_BLOCKSIZE; i++) {
+ carry_out = ctx->tweak[i] & 0x80;
+ ctx->tweak[i] = (ctx->tweak[i] << 1) | (carry_in ? 1 : 0);
+ carry_in = carry_out;
+ }
+ if (carry_in)
+ ctx->tweak[0] ^= AES_XTS_ALPHA;
+ bzero(block, sizeof(block));
+}
+
+static void
+aes_xts_encrypt(caddr_t key, u_int8_t *data)
+{
+ aes_xts_crypt((struct aes_xts_ctx *)key, data, 1);
+}
+
+static void
+aes_xts_decrypt(caddr_t key, u_int8_t *data)
+{
+ aes_xts_crypt((struct aes_xts_ctx *)key, data, 0);
+}
+
+static int
+aes_xts_setkey(u_int8_t **sched, u_int8_t *key, int len)
+{
+ struct aes_xts_ctx *ctx;
+
+ if (len != 32 && len != 64)
+ return EINVAL;
+
+ *sched = KMALLOC(sizeof(struct aes_xts_ctx), M_CRYPTO_DATA,
+ M_NOWAIT | M_ZERO);
+ if (*sched == NULL)
+ return ENOMEM;
+ ctx = (struct aes_xts_ctx *)*sched;
+
+ rijndael_set_key(&ctx->key1, key, len * 4);
+ rijndael_set_key(&ctx->key2, key + (len / 2), len * 4);
+
+ return 0;
+}
+
+static void
+aes_xts_zerokey(u_int8_t **sched)
+{
+ bzero(*sched, sizeof(struct aes_xts_ctx));
+ KFREE(*sched, M_CRYPTO_DATA);
+ *sched = NULL;
+}
diff --git a/sys/opencrypto/xform_auth.h b/sys/opencrypto/xform_auth.h
new file mode 100644
index 0000000..c51f9400
--- /dev/null
+++ b/sys/opencrypto/xform_auth.h
@@ -0,0 +1,89 @@
+/* $FreeBSD$ */
+/* $OpenBSD: xform.h,v 1.8 2001/08/28 12:20:43 ben Exp $ */
+
+/*-
+ * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu)
+ *
+ * This code was written by Angelos D. Keromytis in Athens, Greece, in
+ * February 2000. Network Security Technologies Inc. (NSTI) kindly
+ * supported the development of this code.
+ *
+ * Copyright (c) 2000 Angelos D. Keromytis
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by John-Mark Gurney
+ * under sponsorship of the FreeBSD Foundation and
+ * Rubicon Communications, LLC (Netgate).
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all source code copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#ifndef _CRYPTO_XFORM_AUTH_H_
+#define _CRYPTO_XFORM_AUTH_H_
+
+#include <sys/malloc.h>
+#include <sys/errno.h>
+
+#include <sys/md5.h>
+#include <crypto/sha1.h>
+#include <crypto/sha2/sha256.h>
+#include <crypto/sha2/sha384.h>
+#include <crypto/sha2/sha512.h>
+#include <opencrypto/rmd160.h>
+#include <opencrypto/gmac.h>
+
+#include <opencrypto/cryptodev.h>
+#include <opencrypto/xform_userland.h>
+
+/* XXX use a define common with other hash stuff ! */
+#define AH_ALEN_MAX 64 /* max authenticator hash length */
+
+/* Declarations */
+struct auth_hash {
+ int type;
+ char *name;
+ u_int16_t keysize;
+ u_int16_t hashsize;
+ u_int16_t ctxsize;
+ u_int16_t blocksize;
+ void (*Init) (void *);
+ void (*Setkey) (void *, const u_int8_t *, u_int16_t);
+ void (*Reinit) (void *, const u_int8_t *, u_int16_t);
+ int (*Update) (void *, const u_int8_t *, u_int16_t);
+ void (*Final) (u_int8_t *, void *);
+};
+
+extern struct auth_hash auth_hash_null;
+extern struct auth_hash auth_hash_key_md5;
+extern struct auth_hash auth_hash_key_sha1;
+extern struct auth_hash auth_hash_hmac_md5;
+extern struct auth_hash auth_hash_hmac_sha1;
+extern struct auth_hash auth_hash_hmac_ripemd_160;
+extern struct auth_hash auth_hash_hmac_sha2_256;
+extern struct auth_hash auth_hash_hmac_sha2_384;
+extern struct auth_hash auth_hash_hmac_sha2_512;
+extern struct auth_hash auth_hash_nist_gmac_aes_128;
+extern struct auth_hash auth_hash_nist_gmac_aes_192;
+extern struct auth_hash auth_hash_nist_gmac_aes_256;
+
+union authctx {
+ MD5_CTX md5ctx;
+ SHA1_CTX sha1ctx;
+ RMD160_CTX rmd160ctx;
+ SHA256_CTX sha256ctx;
+ SHA384_CTX sha384ctx;
+ SHA512_CTX sha512ctx;
+ struct aes_gmac_ctx aes_gmac_ctx;
+};
+
+#endif /* _CRYPTO_XFORM_AUTH_H_ */
diff --git a/sys/opencrypto/xform_blf.c b/sys/opencrypto/xform_blf.c
new file mode 100644
index 0000000..b4be5f8
--- /dev/null
+++ b/sys/opencrypto/xform_blf.c
@@ -0,0 +1,127 @@
+/* $OpenBSD: xform.c,v 1.16 2001/08/28 12:20:43 ben Exp $ */
+/*-
+ * The authors of this code are John Ioannidis (ji@tla.org),
+ * Angelos D. Keromytis (kermit@csd.uch.gr),
+ * Niels Provos (provos@physnet.uni-hamburg.de) and
+ * Damien Miller (djm@mindrot.org).
+ *
+ * This code was written by John Ioannidis for BSD/OS in Athens, Greece,
+ * in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis.
+ *
+ * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
+ * and Niels Provos.
+ *
+ * Additional features in 1999 by Angelos D. Keromytis.
+ *
+ * AES XTS implementation in 2008 by Damien Miller
+ *
+ * Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
+ * Angelos D. Keromytis and Niels Provos.
+ *
+ * Copyright (C) 2001, Angelos D. Keromytis.
+ *
+ * Copyright (C) 2008, Damien Miller
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by John-Mark Gurney
+ * under sponsorship of the FreeBSD Foundation and
+ * Rubicon Communications, LLC (Netgate).
+ *
+ * Permission to use, copy, and modify this software with or without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ * You may use this code under the GNU public license if you so wish. Please
+ * contribute changes back to the authors under this freer than GPL license
+ * so that we may further the use of strong encryption without limitations to
+ * all.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <crypto/blowfish/blowfish.h>
+#include <opencrypto/xform_enc.h>
+
+static int blf_setkey(u_int8_t **, u_int8_t *, int);
+static void blf_encrypt(caddr_t, u_int8_t *);
+static void blf_decrypt(caddr_t, u_int8_t *);
+static void blf_zerokey(u_int8_t **);
+
+/* Encryption instances */
+struct enc_xform enc_xform_blf = {
+ CRYPTO_BLF_CBC, "Blowfish",
+ BLOWFISH_BLOCK_LEN, BLOWFISH_BLOCK_LEN, BLOWFISH_MIN_KEY,
+ BLOWFISH_MAX_KEY,
+ blf_encrypt,
+ blf_decrypt,
+ blf_setkey,
+ blf_zerokey,
+ NULL,
+};
+
+/*
+ * Encryption wrapper routines.
+ */
+static void
+blf_encrypt(caddr_t key, u_int8_t *blk)
+{
+ BF_LONG t[2];
+
+ memcpy(t, blk, sizeof (t));
+ t[0] = ntohl(t[0]);
+ t[1] = ntohl(t[1]);
+ /* NB: BF_encrypt expects the block in host order! */
+ BF_encrypt(t, (BF_KEY *) key);
+ t[0] = htonl(t[0]);
+ t[1] = htonl(t[1]);
+ memcpy(blk, t, sizeof (t));
+}
+
+static void
+blf_decrypt(caddr_t key, u_int8_t *blk)
+{
+ BF_LONG t[2];
+
+ memcpy(t, blk, sizeof (t));
+ t[0] = ntohl(t[0]);
+ t[1] = ntohl(t[1]);
+ /* NB: BF_decrypt expects the block in host order! */
+ BF_decrypt(t, (BF_KEY *) key);
+ t[0] = htonl(t[0]);
+ t[1] = htonl(t[1]);
+ memcpy(blk, t, sizeof (t));
+}
+
+static int
+blf_setkey(u_int8_t **sched, u_int8_t *key, int len)
+{
+ int err;
+
+ *sched = KMALLOC(sizeof(BF_KEY),
+ M_CRYPTO_DATA, M_NOWAIT|M_ZERO);
+ if (*sched != NULL) {
+ BF_set_key((BF_KEY *) *sched, len, key);
+ err = 0;
+ } else
+ err = ENOMEM;
+ return err;
+}
+
+static void
+blf_zerokey(u_int8_t **sched)
+{
+ bzero(*sched, sizeof(BF_KEY));
+ KFREE(*sched, M_CRYPTO_DATA);
+ *sched = NULL;
+}
diff --git a/sys/opencrypto/xform_cast5.c b/sys/opencrypto/xform_cast5.c
new file mode 100644
index 0000000..85b346e
--- /dev/null
+++ b/sys/opencrypto/xform_cast5.c
@@ -0,0 +1,107 @@
+/* $OpenBSD: xform.c,v 1.16 2001/08/28 12:20:43 ben Exp $ */
+/*-
+ * The authors of this code are John Ioannidis (ji@tla.org),
+ * Angelos D. Keromytis (kermit@csd.uch.gr),
+ * Niels Provos (provos@physnet.uni-hamburg.de) and
+ * Damien Miller (djm@mindrot.org).
+ *
+ * This code was written by John Ioannidis for BSD/OS in Athens, Greece,
+ * in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis.
+ *
+ * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
+ * and Niels Provos.
+ *
+ * Additional features in 1999 by Angelos D. Keromytis.
+ *
+ * AES XTS implementation in 2008 by Damien Miller
+ *
+ * Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
+ * Angelos D. Keromytis and Niels Provos.
+ *
+ * Copyright (C) 2001, Angelos D. Keromytis.
+ *
+ * Copyright (C) 2008, Damien Miller
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by John-Mark Gurney
+ * under sponsorship of the FreeBSD Foundation and
+ * Rubicon Communications, LLC (Netgate).
+ *
+ * Permission to use, copy, and modify this software with or without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ * You may use this code under the GNU public license if you so wish. Please
+ * contribute changes back to the authors under this freer than GPL license
+ * so that we may further the use of strong encryption without limitations to
+ * all.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <opencrypto/cast.h>
+#include <opencrypto/xform_enc.h>
+
+static int cast5_setkey(u_int8_t **, u_int8_t *, int);
+static void cast5_encrypt(caddr_t, u_int8_t *);
+static void cast5_decrypt(caddr_t, u_int8_t *);
+static void cast5_zerokey(u_int8_t **);
+
+/* Encryption instances */
+struct enc_xform enc_xform_cast5 = {
+ CRYPTO_CAST_CBC, "CAST-128",
+ CAST128_BLOCK_LEN, CAST128_BLOCK_LEN, CAST_MIN_KEY, CAST_MAX_KEY,
+ cast5_encrypt,
+ cast5_decrypt,
+ cast5_setkey,
+ cast5_zerokey,
+ NULL,
+};
+
+/*
+ * Encryption wrapper routines.
+ */
+static void
+cast5_encrypt(caddr_t key, u_int8_t *blk)
+{
+ cast_encrypt((cast_key *) key, blk, blk);
+}
+
+static void
+cast5_decrypt(caddr_t key, u_int8_t *blk)
+{
+ cast_decrypt((cast_key *) key, blk, blk);
+}
+
+static int
+cast5_setkey(u_int8_t **sched, u_int8_t *key, int len)
+{
+ int err;
+
+ *sched = KMALLOC(sizeof(cast_key), M_CRYPTO_DATA, M_NOWAIT|M_ZERO);
+ if (*sched != NULL) {
+ cast_setkey((cast_key *)*sched, key, len);
+ err = 0;
+ } else
+ err = ENOMEM;
+ return err;
+}
+
+static void
+cast5_zerokey(u_int8_t **sched)
+{
+ bzero(*sched, sizeof(cast_key));
+ KFREE(*sched, M_CRYPTO_DATA);
+ *sched = NULL;
+}
diff --git a/sys/opencrypto/xform_cml.c b/sys/opencrypto/xform_cml.c
new file mode 100644
index 0000000..c807fa9
--- /dev/null
+++ b/sys/opencrypto/xform_cml.c
@@ -0,0 +1,113 @@
+/* $OpenBSD: xform.c,v 1.16 2001/08/28 12:20:43 ben Exp $ */
+/*-
+ * The authors of this code are John Ioannidis (ji@tla.org),
+ * Angelos D. Keromytis (kermit@csd.uch.gr),
+ * Niels Provos (provos@physnet.uni-hamburg.de) and
+ * Damien Miller (djm@mindrot.org).
+ *
+ * This code was written by John Ioannidis for BSD/OS in Athens, Greece,
+ * in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis.
+ *
+ * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
+ * and Niels Provos.
+ *
+ * Additional features in 1999 by Angelos D. Keromytis.
+ *
+ * AES XTS implementation in 2008 by Damien Miller
+ *
+ * Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
+ * Angelos D. Keromytis and Niels Provos.
+ *
+ * Copyright (C) 2001, Angelos D. Keromytis.
+ *
+ * Copyright (C) 2008, Damien Miller
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by John-Mark Gurney
+ * under sponsorship of the FreeBSD Foundation and
+ * Rubicon Communications, LLC (Netgate).
+ *
+ * Permission to use, copy, and modify this software with or without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ * You may use this code under the GNU public license if you so wish. Please
+ * contribute changes back to the authors under this freer than GPL license
+ * so that we may further the use of strong encryption without limitations to
+ * all.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <crypto/camellia/camellia.h>
+#include <opencrypto/xform_enc.h>
+
+static int cml_setkey(u_int8_t **, u_int8_t *, int);
+static void cml_encrypt(caddr_t, u_int8_t *);
+static void cml_decrypt(caddr_t, u_int8_t *);
+static void cml_zerokey(u_int8_t **);
+
+/* Encryption instances */
+struct enc_xform enc_xform_camellia = {
+ CRYPTO_CAMELLIA_CBC, "Camellia",
+ CAMELLIA_BLOCK_LEN, CAMELLIA_BLOCK_LEN, CAMELLIA_MIN_KEY,
+ CAMELLIA_MAX_KEY,
+ cml_encrypt,
+ cml_decrypt,
+ cml_setkey,
+ cml_zerokey,
+ NULL,
+};
+
+/*
+ * Encryption wrapper routines.
+ */
+static void
+cml_encrypt(caddr_t key, u_int8_t *blk)
+{
+ camellia_encrypt((camellia_ctx *) key, (u_char *) blk, (u_char *) blk);
+}
+
+static void
+cml_decrypt(caddr_t key, u_int8_t *blk)
+{
+ camellia_decrypt(((camellia_ctx *) key), (u_char *) blk,
+ (u_char *) blk);
+}
+
+static int
+cml_setkey(u_int8_t **sched, u_int8_t *key, int len)
+{
+ int err;
+
+ if (len != 16 && len != 24 && len != 32)
+ return (EINVAL);
+ *sched = KMALLOC(sizeof(camellia_ctx), M_CRYPTO_DATA,
+ M_NOWAIT|M_ZERO);
+ if (*sched != NULL) {
+ camellia_set_key((camellia_ctx *) *sched, (u_char *) key,
+ len * 8);
+ err = 0;
+ } else
+ err = ENOMEM;
+ return err;
+}
+
+static void
+cml_zerokey(u_int8_t **sched)
+{
+ bzero(*sched, sizeof(camellia_ctx));
+ KFREE(*sched, M_CRYPTO_DATA);
+ *sched = NULL;
+}
diff --git a/sys/opencrypto/xform_comp.h b/sys/opencrypto/xform_comp.h
new file mode 100644
index 0000000..23e4eac
--- /dev/null
+++ b/sys/opencrypto/xform_comp.h
@@ -0,0 +1,52 @@
+/* $FreeBSD$ */
+/* $OpenBSD: xform.h,v 1.8 2001/08/28 12:20:43 ben Exp $ */
+
+/*-
+ * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu)
+ *
+ * This code was written by Angelos D. Keromytis in Athens, Greece, in
+ * February 2000. Network Security Technologies Inc. (NSTI) kindly
+ * supported the development of this code.
+ *
+ * Copyright (c) 2000 Angelos D. Keromytis
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by John-Mark Gurney
+ * under sponsorship of the FreeBSD Foundation and
+ * Rubicon Communications, LLC (Netgate).
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all source code copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#ifndef _CRYPTO_XFORM_COMP_H_
+#define _CRYPTO_XFORM_COMP_H_
+
+#include <sys/malloc.h>
+#include <sys/errno.h>
+
+#include <opencrypto/deflate.h>
+#include <opencrypto/cryptodev.h>
+#include <opencrypto/xform_userland.h>
+
+/* Declarations */
+struct comp_algo {
+ int type;
+ char *name;
+ size_t minlen;
+ u_int32_t (*compress) (u_int8_t *, u_int32_t, u_int8_t **);
+ u_int32_t (*decompress) (u_int8_t *, u_int32_t, u_int8_t **);
+};
+
+extern struct comp_algo comp_algo_deflate;
+
+#endif /* _CRYPTO_XFORM_COMP_H_ */
diff --git a/sys/opencrypto/xform_deflate.c b/sys/opencrypto/xform_deflate.c
new file mode 100644
index 0000000..c8864bf
--- /dev/null
+++ b/sys/opencrypto/xform_deflate.c
@@ -0,0 +1,86 @@
+/* $OpenBSD: xform.c,v 1.16 2001/08/28 12:20:43 ben Exp $ */
+/*-
+ * The authors of this code are John Ioannidis (ji@tla.org),
+ * Angelos D. Keromytis (kermit@csd.uch.gr),
+ * Niels Provos (provos@physnet.uni-hamburg.de) and
+ * Damien Miller (djm@mindrot.org).
+ *
+ * This code was written by John Ioannidis for BSD/OS in Athens, Greece,
+ * in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis.
+ *
+ * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
+ * and Niels Provos.
+ *
+ * Additional features in 1999 by Angelos D. Keromytis.
+ *
+ * AES XTS implementation in 2008 by Damien Miller
+ *
+ * Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
+ * Angelos D. Keromytis and Niels Provos.
+ *
+ * Copyright (C) 2001, Angelos D. Keromytis.
+ *
+ * Copyright (C) 2008, Damien Miller
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by John-Mark Gurney
+ * under sponsorship of the FreeBSD Foundation and
+ * Rubicon Communications, LLC (Netgate).
+ *
+ * Permission to use, copy, and modify this software with or without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ * You may use this code under the GNU public license if you so wish. Please
+ * contribute changes back to the authors under this freer than GPL license
+ * so that we may further the use of strong encryption without limitations to
+ * all.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <opencrypto/deflate.h>
+#include <opencrypto/xform_comp.h>
+
+static u_int32_t deflate_compress(u_int8_t *, u_int32_t, u_int8_t **);
+static u_int32_t deflate_decompress(u_int8_t *, u_int32_t, u_int8_t **);
+
+/* Compression instance */
+struct comp_algo comp_algo_deflate = {
+ CRYPTO_DEFLATE_COMP, "Deflate",
+ 90, deflate_compress,
+ deflate_decompress
+};
+
+/*
+ * And compression
+ */
+
+static u_int32_t
+deflate_compress(data, size, out)
+ u_int8_t *data;
+ u_int32_t size;
+ u_int8_t **out;
+{
+ return deflate_global(data, size, 0, out);
+}
+
+static u_int32_t
+deflate_decompress(data, size, out)
+ u_int8_t *data;
+ u_int32_t size;
+ u_int8_t **out;
+{
+ return deflate_global(data, size, 1, out);
+}
diff --git a/sys/opencrypto/xform_des1.c b/sys/opencrypto/xform_des1.c
new file mode 100644
index 0000000..cbce5e2
--- /dev/null
+++ b/sys/opencrypto/xform_des1.c
@@ -0,0 +1,116 @@
+/* $OpenBSD: xform.c,v 1.16 2001/08/28 12:20:43 ben Exp $ */
+/*-
+ * The authors of this code are John Ioannidis (ji@tla.org),
+ * Angelos D. Keromytis (kermit@csd.uch.gr),
+ * Niels Provos (provos@physnet.uni-hamburg.de) and
+ * Damien Miller (djm@mindrot.org).
+ *
+ * This code was written by John Ioannidis for BSD/OS in Athens, Greece,
+ * in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis.
+ *
+ * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
+ * and Niels Provos.
+ *
+ * Additional features in 1999 by Angelos D. Keromytis.
+ *
+ * AES XTS implementation in 2008 by Damien Miller
+ *
+ * Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
+ * Angelos D. Keromytis and Niels Provos.
+ *
+ * Copyright (C) 2001, Angelos D. Keromytis.
+ *
+ * Copyright (C) 2008, Damien Miller
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by John-Mark Gurney
+ * under sponsorship of the FreeBSD Foundation and
+ * Rubicon Communications, LLC (Netgate).
+ *
+ * Permission to use, copy, and modify this software with or without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ * You may use this code under the GNU public license if you so wish. Please
+ * contribute changes back to the authors under this freer than GPL license
+ * so that we may further the use of strong encryption without limitations to
+ * all.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <crypto/des/des.h>
+#include <opencrypto/xform_enc.h>
+
+static int des1_setkey(u_int8_t **, u_int8_t *, int);
+static void des1_encrypt(caddr_t, u_int8_t *);
+static void des1_decrypt(caddr_t, u_int8_t *);
+static void des1_zerokey(u_int8_t **);
+
+/* Encryption instances */
+struct enc_xform enc_xform_des = {
+ CRYPTO_DES_CBC, "DES",
+ DES_BLOCK_LEN, DES_BLOCK_LEN, DES_MIN_KEY, DES_MAX_KEY,
+ des1_encrypt,
+ des1_decrypt,
+ des1_setkey,
+ des1_zerokey,
+ NULL,
+};
+
+/*
+ * Encryption wrapper routines.
+ */
+static void
+des1_encrypt(caddr_t key, u_int8_t *blk)
+{
+ des_cblock *cb = (des_cblock *) blk;
+ des_key_schedule *p = (des_key_schedule *) key;
+
+ des_ecb_encrypt(cb, cb, p[0], DES_ENCRYPT);
+}
+
+static void
+des1_decrypt(caddr_t key, u_int8_t *blk)
+{
+ des_cblock *cb = (des_cblock *) blk;
+ des_key_schedule *p = (des_key_schedule *) key;
+
+ des_ecb_encrypt(cb, cb, p[0], DES_DECRYPT);
+}
+
+static int
+des1_setkey(u_int8_t **sched, u_int8_t *key, int len)
+{
+ des_key_schedule *p;
+ int err;
+
+ p = KMALLOC(sizeof (des_key_schedule),
+ M_CRYPTO_DATA, M_NOWAIT|M_ZERO);
+ if (p != NULL) {
+ des_set_key((des_cblock *) key, p[0]);
+ err = 0;
+ } else
+ err = ENOMEM;
+ *sched = (u_int8_t *) p;
+ return err;
+}
+
+static void
+des1_zerokey(u_int8_t **sched)
+{
+ bzero(*sched, sizeof (des_key_schedule));
+ KFREE(*sched, M_CRYPTO_DATA);
+ *sched = NULL;
+}
diff --git a/sys/opencrypto/xform_des3.c b/sys/opencrypto/xform_des3.c
new file mode 100644
index 0000000..1b26b62
--- /dev/null
+++ b/sys/opencrypto/xform_des3.c
@@ -0,0 +1,119 @@
+/* $OpenBSD: xform.c,v 1.16 2001/08/28 12:20:43 ben Exp $ */
+/*-
+ * The authors of this code are John Ioannidis (ji@tla.org),
+ * Angelos D. Keromytis (kermit@csd.uch.gr),
+ * Niels Provos (provos@physnet.uni-hamburg.de) and
+ * Damien Miller (djm@mindrot.org).
+ *
+ * This code was written by John Ioannidis for BSD/OS in Athens, Greece,
+ * in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis.
+ *
+ * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
+ * and Niels Provos.
+ *
+ * Additional features in 1999 by Angelos D. Keromytis.
+ *
+ * AES XTS implementation in 2008 by Damien Miller
+ *
+ * Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
+ * Angelos D. Keromytis and Niels Provos.
+ *
+ * Copyright (C) 2001, Angelos D. Keromytis.
+ *
+ * Copyright (C) 2008, Damien Miller
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by John-Mark Gurney
+ * under sponsorship of the FreeBSD Foundation and
+ * Rubicon Communications, LLC (Netgate).
+ *
+ * Permission to use, copy, and modify this software with or without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ * You may use this code under the GNU public license if you so wish. Please
+ * contribute changes back to the authors under this freer than GPL license
+ * so that we may further the use of strong encryption without limitations to
+ * all.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <crypto/des/des.h>
+#include <opencrypto/xform_enc.h>
+
+static int des3_setkey(u_int8_t **, u_int8_t *, int);
+static void des3_encrypt(caddr_t, u_int8_t *);
+static void des3_decrypt(caddr_t, u_int8_t *);
+static void des3_zerokey(u_int8_t **);
+
+/* Encryption instances */
+struct enc_xform enc_xform_3des = {
+ CRYPTO_3DES_CBC, "3DES",
+ DES3_BLOCK_LEN, DES3_BLOCK_LEN, TRIPLE_DES_MIN_KEY,
+ TRIPLE_DES_MAX_KEY,
+ des3_encrypt,
+ des3_decrypt,
+ des3_setkey,
+ des3_zerokey,
+ NULL,
+};
+
+/*
+ * Encryption wrapper routines.
+ */
+static void
+des3_encrypt(caddr_t key, u_int8_t *blk)
+{
+ des_cblock *cb = (des_cblock *) blk;
+ des_key_schedule *p = (des_key_schedule *) key;
+
+ des_ecb3_encrypt(cb, cb, p[0], p[1], p[2], DES_ENCRYPT);
+}
+
+static void
+des3_decrypt(caddr_t key, u_int8_t *blk)
+{
+ des_cblock *cb = (des_cblock *) blk;
+ des_key_schedule *p = (des_key_schedule *) key;
+
+ des_ecb3_encrypt(cb, cb, p[0], p[1], p[2], DES_DECRYPT);
+}
+
+static int
+des3_setkey(u_int8_t **sched, u_int8_t *key, int len)
+{
+ des_key_schedule *p;
+ int err;
+
+ p = KMALLOC(3*sizeof (des_key_schedule),
+ M_CRYPTO_DATA, M_NOWAIT|M_ZERO);
+ if (p != NULL) {
+ des_set_key((des_cblock *)(key + 0), p[0]);
+ des_set_key((des_cblock *)(key + 8), p[1]);
+ des_set_key((des_cblock *)(key + 16), p[2]);
+ err = 0;
+ } else
+ err = ENOMEM;
+ *sched = (u_int8_t *) p;
+ return err;
+}
+
+static void
+des3_zerokey(u_int8_t **sched)
+{
+ bzero(*sched, 3*sizeof (des_key_schedule));
+ KFREE(*sched, M_CRYPTO_DATA);
+ *sched = NULL;
+}
diff --git a/sys/opencrypto/xform_enc.h b/sys/opencrypto/xform_enc.h
new file mode 100644
index 0000000..7bb6a9d
--- /dev/null
+++ b/sys/opencrypto/xform_enc.h
@@ -0,0 +1,92 @@
+/* $FreeBSD$ */
+/* $OpenBSD: xform.h,v 1.8 2001/08/28 12:20:43 ben Exp $ */
+
+/*-
+ * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu)
+ *
+ * This code was written by Angelos D. Keromytis in Athens, Greece, in
+ * February 2000. Network Security Technologies Inc. (NSTI) kindly
+ * supported the development of this code.
+ *
+ * Copyright (c) 2000 Angelos D. Keromytis
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by John-Mark Gurney
+ * under sponsorship of the FreeBSD Foundation and
+ * Rubicon Communications, LLC (Netgate).
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all source code copies of any software which is or includes a copy or
+ * modification of this software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#ifndef _CRYPTO_XFORM_ENC_H_
+#define _CRYPTO_XFORM_ENC_H_
+
+#include <sys/malloc.h>
+#include <sys/errno.h>
+#include <crypto/blowfish/blowfish.h>
+#include <crypto/des/des.h>
+#include <crypto/rijndael/rijndael.h>
+#include <crypto/camellia/camellia.h>
+#include <opencrypto/cast.h>
+#include <opencrypto/skipjack.h>
+#include <opencrypto/cryptodev.h>
+#include <opencrypto/xform_userland.h>
+
+#define AESICM_BLOCKSIZE AES_BLOCK_LEN
+#define AES_XTS_BLOCKSIZE 16
+#define AES_XTS_IVSIZE 8
+#define AES_XTS_ALPHA 0x87 /* GF(2^128) generator polynomial */
+
+/* Declarations */
+struct enc_xform {
+ int type;
+ char *name;
+ u_int16_t blocksize;
+ u_int16_t ivsize;
+ u_int16_t minkey, maxkey;
+ void (*encrypt) (caddr_t, u_int8_t *);
+ void (*decrypt) (caddr_t, u_int8_t *);
+ int (*setkey) (u_int8_t **, u_int8_t *, int len);
+ void (*zerokey) (u_int8_t **);
+ void (*reinit) (caddr_t, u_int8_t *);
+};
+
+
+extern struct enc_xform enc_xform_null;
+extern struct enc_xform enc_xform_des;
+extern struct enc_xform enc_xform_3des;
+extern struct enc_xform enc_xform_blf;
+extern struct enc_xform enc_xform_cast5;
+extern struct enc_xform enc_xform_skipjack;
+extern struct enc_xform enc_xform_rijndael128;
+extern struct enc_xform enc_xform_aes_icm;
+extern struct enc_xform enc_xform_aes_nist_gcm;
+extern struct enc_xform enc_xform_aes_nist_gmac;
+extern struct enc_xform enc_xform_aes_xts;
+extern struct enc_xform enc_xform_arc4;
+extern struct enc_xform enc_xform_camellia;
+
+struct aes_icm_ctx {
+ u_int32_t ac_ek[4*(RIJNDAEL_MAXNR + 1)];
+ /* ac_block is initalized to IV */
+ u_int8_t ac_block[AESICM_BLOCKSIZE];
+ int ac_nr;
+};
+
+struct aes_xts_ctx {
+ rijndael_ctx key1;
+ rijndael_ctx key2;
+ u_int8_t tweak[AES_XTS_BLOCKSIZE];
+};
+
+#endif /* _CRYPTO_XFORM_ENC_H_ */
diff --git a/sys/opencrypto/xform_gmac.c b/sys/opencrypto/xform_gmac.c
new file mode 100644
index 0000000..156ed7f
--- /dev/null
+++ b/sys/opencrypto/xform_gmac.c
@@ -0,0 +1,99 @@
+/* $OpenBSD: xform.c,v 1.16 2001/08/28 12:20:43 ben Exp $ */
+/*-
+ * The authors of this code are John Ioannidis (ji@tla.org),
+ * Angelos D. Keromytis (kermit@csd.uch.gr),
+ * Niels Provos (provos@physnet.uni-hamburg.de) and
+ * Damien Miller (djm@mindrot.org).
+ *
+ * This code was written by John Ioannidis for BSD/OS in Athens, Greece,
+ * in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis.
+ *
+ * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
+ * and Niels Provos.
+ *
+ * Additional features in 1999 by Angelos D. Keromytis.
+ *
+ * AES XTS implementation in 2008 by Damien Miller
+ *
+ * Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
+ * Angelos D. Keromytis and Niels Provos.
+ *
+ * Copyright (C) 2001, Angelos D. Keromytis.
+ *
+ * Copyright (C) 2008, Damien Miller
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by John-Mark Gurney
+ * under sponsorship of the FreeBSD Foundation and
+ * Rubicon Communications, LLC (Netgate).
+ *
+ * Permission to use, copy, and modify this software with or without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ * You may use this code under the GNU public license if you so wish. Please
+ * contribute changes back to the authors under this freer than GPL license
+ * so that we may further the use of strong encryption without limitations to
+ * all.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <opencrypto/gmac.h>
+#include <opencrypto/xform_auth.h>
+
+/* Encryption instances */
+struct enc_xform enc_xform_aes_nist_gmac = {
+ CRYPTO_AES_NIST_GMAC, "AES-GMAC",
+ AES_ICM_BLOCK_LEN, AES_GCM_IV_LEN, AES_MIN_KEY, AES_MAX_KEY,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+};
+
+/* Authentication instances */
+struct auth_hash auth_hash_nist_gmac_aes_128 = {
+ CRYPTO_AES_128_NIST_GMAC, "GMAC-AES-128",
+ AES_128_GMAC_KEY_LEN, AES_GMAC_HASH_LEN, sizeof(struct aes_gmac_ctx),
+ GMAC_BLOCK_LEN,
+ (void (*)(void *)) AES_GMAC_Init,
+ (void (*)(void *, const u_int8_t *, u_int16_t)) AES_GMAC_Setkey,
+ (void (*)(void *, const u_int8_t *, u_int16_t)) AES_GMAC_Reinit,
+ (int (*)(void *, const u_int8_t *, u_int16_t)) AES_GMAC_Update,
+ (void (*)(u_int8_t *, void *)) AES_GMAC_Final
+};
+
+struct auth_hash auth_hash_nist_gmac_aes_192 = {
+ CRYPTO_AES_192_NIST_GMAC, "GMAC-AES-192",
+ AES_192_GMAC_KEY_LEN, AES_GMAC_HASH_LEN, sizeof(struct aes_gmac_ctx),
+ GMAC_BLOCK_LEN,
+ (void (*)(void *)) AES_GMAC_Init,
+ (void (*)(void *, const u_int8_t *, u_int16_t)) AES_GMAC_Setkey,
+ (void (*)(void *, const u_int8_t *, u_int16_t)) AES_GMAC_Reinit,
+ (int (*)(void *, const u_int8_t *, u_int16_t)) AES_GMAC_Update,
+ (void (*)(u_int8_t *, void *)) AES_GMAC_Final
+};
+
+struct auth_hash auth_hash_nist_gmac_aes_256 = {
+ CRYPTO_AES_256_NIST_GMAC, "GMAC-AES-256",
+ AES_256_GMAC_KEY_LEN, AES_GMAC_HASH_LEN, sizeof(struct aes_gmac_ctx),
+ GMAC_BLOCK_LEN,
+ (void (*)(void *)) AES_GMAC_Init,
+ (void (*)(void *, const u_int8_t *, u_int16_t)) AES_GMAC_Setkey,
+ (void (*)(void *, const u_int8_t *, u_int16_t)) AES_GMAC_Reinit,
+ (int (*)(void *, const u_int8_t *, u_int16_t)) AES_GMAC_Update,
+ (void (*)(u_int8_t *, void *)) AES_GMAC_Final
+};
diff --git a/sys/opencrypto/xform_md5.c b/sys/opencrypto/xform_md5.c
new file mode 100644
index 0000000..3a8751d
--- /dev/null
+++ b/sys/opencrypto/xform_md5.c
@@ -0,0 +1,81 @@
+/* $OpenBSD: xform.c,v 1.16 2001/08/28 12:20:43 ben Exp $ */
+/*-
+ * The authors of this code are John Ioannidis (ji@tla.org),
+ * Angelos D. Keromytis (kermit@csd.uch.gr),
+ * Niels Provos (provos@physnet.uni-hamburg.de) and
+ * Damien Miller (djm@mindrot.org).
+ *
+ * This code was written by John Ioannidis for BSD/OS in Athens, Greece,
+ * in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis.
+ *
+ * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
+ * and Niels Provos.
+ *
+ * Additional features in 1999 by Angelos D. Keromytis.
+ *
+ * AES XTS implementation in 2008 by Damien Miller
+ *
+ * Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
+ * Angelos D. Keromytis and Niels Provos.
+ *
+ * Copyright (C) 2001, Angelos D. Keromytis.
+ *
+ * Copyright (C) 2008, Damien Miller
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by John-Mark Gurney
+ * under sponsorship of the FreeBSD Foundation and
+ * Rubicon Communications, LLC (Netgate).
+ *
+ * Permission to use, copy, and modify this software with or without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ * You may use this code under the GNU public license if you so wish. Please
+ * contribute changes back to the authors under this freer than GPL license
+ * so that we may further the use of strong encryption without limitations to
+ * all.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/md5.h>
+#include <opencrypto/xform_auth.h>
+
+static int MD5Update_int(void *, const u_int8_t *, u_int16_t);
+
+/* Authentication instances */
+struct auth_hash auth_hash_hmac_md5 = {
+ CRYPTO_MD5_HMAC, "HMAC-MD5",
+ MD5_HMAC_KEY_LEN, MD5_HASH_LEN, sizeof(MD5_CTX), MD5_HMAC_BLOCK_LEN,
+ (void (*) (void *)) MD5Init, NULL, NULL, MD5Update_int,
+ (void (*) (u_int8_t *, void *)) MD5Final
+};
+
+struct auth_hash auth_hash_key_md5 = {
+ CRYPTO_MD5_KPDK, "Keyed MD5",
+ NULL_HMAC_KEY_LEN, MD5_KPDK_HASH_LEN, sizeof(MD5_CTX), 0,
+ (void (*)(void *)) MD5Init, NULL, NULL, MD5Update_int,
+ (void (*)(u_int8_t *, void *)) MD5Final
+};
+
+/*
+ * And now for auth.
+ */
+static int
+MD5Update_int(void *ctx, const u_int8_t *buf, u_int16_t len)
+{
+ MD5Update(ctx, buf, len);
+ return 0;
+}
diff --git a/sys/opencrypto/xform_null.c b/sys/opencrypto/xform_null.c
new file mode 100644
index 0000000..74f410c
--- /dev/null
+++ b/sys/opencrypto/xform_null.c
@@ -0,0 +1,136 @@
+/* $OpenBSD: xform.c,v 1.16 2001/08/28 12:20:43 ben Exp $ */
+/*-
+ * The authors of this code are John Ioannidis (ji@tla.org),
+ * Angelos D. Keromytis (kermit@csd.uch.gr),
+ * Niels Provos (provos@physnet.uni-hamburg.de) and
+ * Damien Miller (djm@mindrot.org).
+ *
+ * This code was written by John Ioannidis for BSD/OS in Athens, Greece,
+ * in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis.
+ *
+ * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
+ * and Niels Provos.
+ *
+ * Additional features in 1999 by Angelos D. Keromytis.
+ *
+ * AES XTS implementation in 2008 by Damien Miller
+ *
+ * Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
+ * Angelos D. Keromytis and Niels Provos.
+ *
+ * Copyright (C) 2001, Angelos D. Keromytis.
+ *
+ * Copyright (C) 2008, Damien Miller
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by John-Mark Gurney
+ * under sponsorship of the FreeBSD Foundation and
+ * Rubicon Communications, LLC (Netgate).
+ *
+ * Permission to use, copy, and modify this software with or without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ * You may use this code under the GNU public license if you so wish. Please
+ * contribute changes back to the authors under this freer than GPL license
+ * so that we may further the use of strong encryption without limitations to
+ * all.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <opencrypto/xform_auth.h>
+#include <opencrypto/xform_enc.h>
+
+static int null_setkey(u_int8_t **, u_int8_t *, int);
+static void null_encrypt(caddr_t, u_int8_t *);
+static void null_decrypt(caddr_t, u_int8_t *);
+static void null_zerokey(u_int8_t **);
+
+static void null_init(void *);
+static void null_reinit(void *ctx, const u_int8_t *buf, u_int16_t len);
+static int null_update(void *, const u_int8_t *, u_int16_t);
+static void null_final(u_int8_t *, void *);
+
+/* Encryption instances */
+struct enc_xform enc_xform_null = {
+ CRYPTO_NULL_CBC, "NULL",
+ /* NB: blocksize of 4 is to generate a properly aligned ESP header */
+ NULL_BLOCK_LEN, 0, NULL_MIN_KEY, NULL_MAX_KEY,
+ null_encrypt,
+ null_decrypt,
+ null_setkey,
+ null_zerokey,
+ NULL,
+};
+
+/* Authentication instances */
+struct auth_hash auth_hash_null = { /* NB: context isn't used */
+ CRYPTO_NULL_HMAC, "NULL-HMAC",
+ NULL_HMAC_KEY_LEN, NULL_HASH_LEN, sizeof(int), NULL_HMAC_BLOCK_LEN,
+ null_init, null_reinit, null_reinit, null_update, null_final
+};
+
+/*
+ * Encryption wrapper routines.
+ */
+static void
+null_encrypt(caddr_t key, u_int8_t *blk)
+{
+}
+
+static void
+null_decrypt(caddr_t key, u_int8_t *blk)
+{
+}
+
+static int
+null_setkey(u_int8_t **sched, u_int8_t *key, int len)
+{
+ *sched = NULL;
+ return 0;
+}
+
+static void
+null_zerokey(u_int8_t **sched)
+{
+ *sched = NULL;
+}
+
+/*
+ * And now for auth.
+ */
+
+static void
+null_init(void *ctx)
+{
+}
+
+static void
+null_reinit(void *ctx, const u_int8_t *buf, u_int16_t len)
+{
+}
+
+static int
+null_update(void *ctx, const u_int8_t *buf, u_int16_t len)
+{
+ return 0;
+}
+
+static void
+null_final(u_int8_t *buf, void *ctx)
+{
+ if (buf != (u_int8_t *) 0)
+ bzero(buf, 12);
+}
diff --git a/sys/opencrypto/xform_rijndael.c b/sys/opencrypto/xform_rijndael.c
new file mode 100644
index 0000000..2c974f3
--- /dev/null
+++ b/sys/opencrypto/xform_rijndael.c
@@ -0,0 +1,113 @@
+/* $OpenBSD: xform.c,v 1.16 2001/08/28 12:20:43 ben Exp $ */
+/*-
+ * The authors of this code are John Ioannidis (ji@tla.org),
+ * Angelos D. Keromytis (kermit@csd.uch.gr),
+ * Niels Provos (provos@physnet.uni-hamburg.de) and
+ * Damien Miller (djm@mindrot.org).
+ *
+ * This code was written by John Ioannidis for BSD/OS in Athens, Greece,
+ * in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis.
+ *
+ * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
+ * and Niels Provos.
+ *
+ * Additional features in 1999 by Angelos D. Keromytis.
+ *
+ * AES XTS implementation in 2008 by Damien Miller
+ *
+ * Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
+ * Angelos D. Keromytis and Niels Provos.
+ *
+ * Copyright (C) 2001, Angelos D. Keromytis.
+ *
+ * Copyright (C) 2008, Damien Miller
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by John-Mark Gurney
+ * under sponsorship of the FreeBSD Foundation and
+ * Rubicon Communications, LLC (Netgate).
+ *
+ * Permission to use, copy, and modify this software with or without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ * You may use this code under the GNU public license if you so wish. Please
+ * contribute changes back to the authors under this freer than GPL license
+ * so that we may further the use of strong encryption without limitations to
+ * all.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <crypto/rijndael/rijndael.h>
+#include <opencrypto/xform_enc.h>
+
+static int rijndael128_setkey(u_int8_t **, u_int8_t *, int);
+static void rijndael128_encrypt(caddr_t, u_int8_t *);
+static void rijndael128_decrypt(caddr_t, u_int8_t *);
+static void rijndael128_zerokey(u_int8_t **);
+
+/* Encryption instances */
+struct enc_xform enc_xform_rijndael128 = {
+ CRYPTO_RIJNDAEL128_CBC, "Rijndael-128/AES",
+ RIJNDAEL128_BLOCK_LEN, RIJNDAEL128_BLOCK_LEN, RIJNDAEL_MIN_KEY,
+ RIJNDAEL_MAX_KEY,
+ rijndael128_encrypt,
+ rijndael128_decrypt,
+ rijndael128_setkey,
+ rijndael128_zerokey,
+ NULL,
+};
+
+/*
+ * Encryption wrapper routines.
+ */
+static void
+rijndael128_encrypt(caddr_t key, u_int8_t *blk)
+{
+ rijndael_encrypt((rijndael_ctx *) key, (u_char *) blk, (u_char *) blk);
+}
+
+static void
+rijndael128_decrypt(caddr_t key, u_int8_t *blk)
+{
+ rijndael_decrypt(((rijndael_ctx *) key), (u_char *) blk,
+ (u_char *) blk);
+}
+
+static int
+rijndael128_setkey(u_int8_t **sched, u_int8_t *key, int len)
+{
+ int err;
+
+ if (len != 16 && len != 24 && len != 32)
+ return (EINVAL);
+ *sched = KMALLOC(sizeof(rijndael_ctx), M_CRYPTO_DATA,
+ M_NOWAIT|M_ZERO);
+ if (*sched != NULL) {
+ rijndael_set_key((rijndael_ctx *) *sched, (u_char *) key,
+ len * 8);
+ err = 0;
+ } else
+ err = ENOMEM;
+ return err;
+}
+
+static void
+rijndael128_zerokey(u_int8_t **sched)
+{
+ bzero(*sched, sizeof(rijndael_ctx));
+ KFREE(*sched, M_CRYPTO_DATA);
+ *sched = NULL;
+}
diff --git a/sys/opencrypto/xform_rmd160.c b/sys/opencrypto/xform_rmd160.c
new file mode 100644
index 0000000..4bce072
--- /dev/null
+++ b/sys/opencrypto/xform_rmd160.c
@@ -0,0 +1,75 @@
+/* $OpenBSD: xform.c,v 1.16 2001/08/28 12:20:43 ben Exp $ */
+/*-
+ * The authors of this code are John Ioannidis (ji@tla.org),
+ * Angelos D. Keromytis (kermit@csd.uch.gr),
+ * Niels Provos (provos@physnet.uni-hamburg.de) and
+ * Damien Miller (djm@mindrot.org).
+ *
+ * This code was written by John Ioannidis for BSD/OS in Athens, Greece,
+ * in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis.
+ *
+ * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
+ * and Niels Provos.
+ *
+ * Additional features in 1999 by Angelos D. Keromytis.
+ *
+ * AES XTS implementation in 2008 by Damien Miller
+ *
+ * Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
+ * Angelos D. Keromytis and Niels Provos.
+ *
+ * Copyright (C) 2001, Angelos D. Keromytis.
+ *
+ * Copyright (C) 2008, Damien Miller
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by John-Mark Gurney
+ * under sponsorship of the FreeBSD Foundation and
+ * Rubicon Communications, LLC (Netgate).
+ *
+ * Permission to use, copy, and modify this software with or without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ * You may use this code under the GNU public license if you so wish. Please
+ * contribute changes back to the authors under this freer than GPL license
+ * so that we may further the use of strong encryption without limitations to
+ * all.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <opencrypto/rmd160.h>
+#include <opencrypto/xform_auth.h>
+
+static int RMD160Update_int(void *, const u_int8_t *, u_int16_t);
+
+/* Authentication instances */
+struct auth_hash auth_hash_hmac_ripemd_160 = {
+ CRYPTO_RIPEMD160_HMAC, "HMAC-RIPEMD-160",
+ RIPEMD160_HMAC_KEY_LEN, RIPEMD160_HASH_LEN, sizeof(RMD160_CTX),
+ RIPEMD160_HMAC_BLOCK_LEN,
+ (void (*)(void *)) RMD160Init, NULL, NULL, RMD160Update_int,
+ (void (*)(u_int8_t *, void *)) RMD160Final
+};
+
+/*
+ * And now for auth.
+ */
+static int
+RMD160Update_int(void *ctx, const u_int8_t *buf, u_int16_t len)
+{
+ RMD160Update(ctx, buf, len);
+ return 0;
+}
diff --git a/sys/opencrypto/xform_sha1.c b/sys/opencrypto/xform_sha1.c
new file mode 100644
index 0000000..29a5916
--- /dev/null
+++ b/sys/opencrypto/xform_sha1.c
@@ -0,0 +1,93 @@
+/* $OpenBSD: xform.c,v 1.16 2001/08/28 12:20:43 ben Exp $ */
+/*-
+ * The authors of this code are John Ioannidis (ji@tla.org),
+ * Angelos D. Keromytis (kermit@csd.uch.gr),
+ * Niels Provos (provos@physnet.uni-hamburg.de) and
+ * Damien Miller (djm@mindrot.org).
+ *
+ * This code was written by John Ioannidis for BSD/OS in Athens, Greece,
+ * in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis.
+ *
+ * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
+ * and Niels Provos.
+ *
+ * Additional features in 1999 by Angelos D. Keromytis.
+ *
+ * AES XTS implementation in 2008 by Damien Miller
+ *
+ * Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
+ * Angelos D. Keromytis and Niels Provos.
+ *
+ * Copyright (C) 2001, Angelos D. Keromytis.
+ *
+ * Copyright (C) 2008, Damien Miller
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by John-Mark Gurney
+ * under sponsorship of the FreeBSD Foundation and
+ * Rubicon Communications, LLC (Netgate).
+ *
+ * Permission to use, copy, and modify this software with or without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ * You may use this code under the GNU public license if you so wish. Please
+ * contribute changes back to the authors under this freer than GPL license
+ * so that we may further the use of strong encryption without limitations to
+ * all.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <crypto/sha1.h>
+#include <opencrypto/xform_auth.h>
+
+static void SHA1Init_int(void *);
+static int SHA1Update_int(void *, const u_int8_t *, u_int16_t);
+static void SHA1Final_int(u_int8_t *, void *);
+
+/* Authentication instances */
+struct auth_hash auth_hash_hmac_sha1 = {
+ CRYPTO_SHA1_HMAC, "HMAC-SHA1",
+ SHA1_HMAC_KEY_LEN, SHA1_HASH_LEN, sizeof(SHA1_CTX), SHA1_HMAC_BLOCK_LEN,
+ SHA1Init_int, NULL, NULL, SHA1Update_int, SHA1Final_int
+};
+
+struct auth_hash auth_hash_key_sha1 = {
+ CRYPTO_SHA1_KPDK, "Keyed SHA1",
+ NULL_HMAC_KEY_LEN, SHA1_KPDK_HASH_LEN, sizeof(SHA1_CTX), 0,
+ SHA1Init_int, NULL, NULL, SHA1Update_int, SHA1Final_int
+};
+
+/*
+ * And now for auth.
+ */
+static void
+SHA1Init_int(void *ctx)
+{
+ SHA1Init(ctx);
+}
+
+static int
+SHA1Update_int(void *ctx, const u_int8_t *buf, u_int16_t len)
+{
+ SHA1Update(ctx, buf, len);
+ return 0;
+}
+
+static void
+SHA1Final_int(u_int8_t *blk, void *ctx)
+{
+ SHA1Final(blk, ctx);
+}
diff --git a/sys/opencrypto/xform_sha2.c b/sys/opencrypto/xform_sha2.c
new file mode 100644
index 0000000..389cb8d
--- /dev/null
+++ b/sys/opencrypto/xform_sha2.c
@@ -0,0 +1,109 @@
+/* $OpenBSD: xform.c,v 1.16 2001/08/28 12:20:43 ben Exp $ */
+/*-
+ * The authors of this code are John Ioannidis (ji@tla.org),
+ * Angelos D. Keromytis (kermit@csd.uch.gr),
+ * Niels Provos (provos@physnet.uni-hamburg.de) and
+ * Damien Miller (djm@mindrot.org).
+ *
+ * This code was written by John Ioannidis for BSD/OS in Athens, Greece,
+ * in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis.
+ *
+ * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
+ * and Niels Provos.
+ *
+ * Additional features in 1999 by Angelos D. Keromytis.
+ *
+ * AES XTS implementation in 2008 by Damien Miller
+ *
+ * Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
+ * Angelos D. Keromytis and Niels Provos.
+ *
+ * Copyright (C) 2001, Angelos D. Keromytis.
+ *
+ * Copyright (C) 2008, Damien Miller
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by John-Mark Gurney
+ * under sponsorship of the FreeBSD Foundation and
+ * Rubicon Communications, LLC (Netgate).
+ *
+ * Permission to use, copy, and modify this software with or without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ * You may use this code under the GNU public license if you so wish. Please
+ * contribute changes back to the authors under this freer than GPL license
+ * so that we may further the use of strong encryption without limitations to
+ * all.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <crypto/sha2/sha256.h>
+#include <crypto/sha2/sha384.h>
+#include <crypto/sha2/sha512.h>
+#include <opencrypto/xform_auth.h>
+
+static int SHA256Update_int(void *, const u_int8_t *, u_int16_t);
+static int SHA384Update_int(void *, const u_int8_t *, u_int16_t);
+static int SHA512Update_int(void *, const u_int8_t *, u_int16_t);
+
+/* Authentication instances */
+struct auth_hash auth_hash_hmac_sha2_256 = {
+ CRYPTO_SHA2_256_HMAC, "HMAC-SHA2-256",
+ SHA2_256_HMAC_KEY_LEN, SHA2_256_HASH_LEN, sizeof(SHA256_CTX),
+ SHA2_256_HMAC_BLOCK_LEN,
+ (void (*)(void *)) SHA256_Init, NULL, NULL, SHA256Update_int,
+ (void (*)(u_int8_t *, void *)) SHA256_Final
+};
+
+struct auth_hash auth_hash_hmac_sha2_384 = {
+ CRYPTO_SHA2_384_HMAC, "HMAC-SHA2-384",
+ SHA2_384_HMAC_KEY_LEN, SHA2_384_HASH_LEN, sizeof(SHA384_CTX),
+ SHA2_384_HMAC_BLOCK_LEN,
+ (void (*)(void *)) SHA384_Init, NULL, NULL, SHA384Update_int,
+ (void (*)(u_int8_t *, void *)) SHA384_Final
+};
+
+struct auth_hash auth_hash_hmac_sha2_512 = {
+ CRYPTO_SHA2_512_HMAC, "HMAC-SHA2-512",
+ SHA2_512_HMAC_KEY_LEN, SHA2_512_HASH_LEN, sizeof(SHA512_CTX),
+ SHA2_512_HMAC_BLOCK_LEN,
+ (void (*)(void *)) SHA512_Init, NULL, NULL, SHA512Update_int,
+ (void (*)(u_int8_t *, void *)) SHA512_Final
+};
+
+/*
+ * And now for auth.
+ */
+static int
+SHA256Update_int(void *ctx, const u_int8_t *buf, u_int16_t len)
+{
+ SHA256_Update(ctx, buf, len);
+ return 0;
+}
+
+static int
+SHA384Update_int(void *ctx, const u_int8_t *buf, u_int16_t len)
+{
+ SHA384_Update(ctx, buf, len);
+ return 0;
+}
+
+static int
+SHA512Update_int(void *ctx, const u_int8_t *buf, u_int16_t len)
+{
+ SHA512_Update(ctx, buf, len);
+ return 0;
+}
diff --git a/sys/opencrypto/xform_skipjack.c b/sys/opencrypto/xform_skipjack.c
new file mode 100644
index 0000000..94090d0
--- /dev/null
+++ b/sys/opencrypto/xform_skipjack.c
@@ -0,0 +1,117 @@
+/* $OpenBSD: xform.c,v 1.16 2001/08/28 12:20:43 ben Exp $ */
+/*-
+ * The authors of this code are John Ioannidis (ji@tla.org),
+ * Angelos D. Keromytis (kermit@csd.uch.gr),
+ * Niels Provos (provos@physnet.uni-hamburg.de) and
+ * Damien Miller (djm@mindrot.org).
+ *
+ * This code was written by John Ioannidis for BSD/OS in Athens, Greece,
+ * in November 1995.
+ *
+ * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
+ * by Angelos D. Keromytis.
+ *
+ * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
+ * and Niels Provos.
+ *
+ * Additional features in 1999 by Angelos D. Keromytis.
+ *
+ * AES XTS implementation in 2008 by Damien Miller
+ *
+ * Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
+ * Angelos D. Keromytis and Niels Provos.
+ *
+ * Copyright (C) 2001, Angelos D. Keromytis.
+ *
+ * Copyright (C) 2008, Damien Miller
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by John-Mark Gurney
+ * under sponsorship of the FreeBSD Foundation and
+ * Rubicon Communications, LLC (Netgate).
+ *
+ * Permission to use, copy, and modify this software with or without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ * You may use this code under the GNU public license if you so wish. Please
+ * contribute changes back to the authors under this freer than GPL license
+ * so that we may further the use of strong encryption without limitations to
+ * all.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <opencrypto/skipjack.h>
+#include <opencrypto/xform_enc.h>
+
+static int skipjack_setkey(u_int8_t **, u_int8_t *, int);
+static void skipjack_encrypt(caddr_t, u_int8_t *);
+static void skipjack_decrypt(caddr_t, u_int8_t *);
+static void skipjack_zerokey(u_int8_t **);
+
+/* Encryption instances */
+struct enc_xform enc_xform_skipjack = {
+ CRYPTO_SKIPJACK_CBC, "Skipjack",
+ SKIPJACK_BLOCK_LEN, SKIPJACK_BLOCK_LEN, SKIPJACK_MIN_KEY,
+ SKIPJACK_MAX_KEY,
+ skipjack_encrypt,
+ skipjack_decrypt, skipjack_setkey,
+ skipjack_zerokey,
+ NULL,
+};
+
+/*
+ * Encryption wrapper routines.
+ */
+static void
+skipjack_encrypt(caddr_t key, u_int8_t *blk)
+{
+ skipjack_forwards(blk, blk, (u_int8_t **) key);
+}
+
+static void
+skipjack_decrypt(caddr_t key, u_int8_t *blk)
+{
+ skipjack_backwards(blk, blk, (u_int8_t **) key);
+}
+
+static int
+skipjack_setkey(u_int8_t **sched, u_int8_t *key, int len)
+{
+ int err;
+
+ /* NB: allocate all the memory that's needed at once */
+ *sched = KMALLOC(10 * (sizeof(u_int8_t *) + 0x100),
+ M_CRYPTO_DATA, M_NOWAIT|M_ZERO);
+ if (*sched != NULL) {
+ u_int8_t** key_tables = (u_int8_t**) *sched;
+ u_int8_t* table = (u_int8_t*) &key_tables[10];
+ int k;
+
+ for (k = 0; k < 10; k++) {
+ key_tables[k] = table;
+ table += 0x100;
+ }
+ subkey_table_gen(key, (u_int8_t **) *sched);
+ err = 0;
+ } else
+ err = ENOMEM;
+ return err;
+}
+
+static void
+skipjack_zerokey(u_int8_t **sched)
+{
+ bzero(*sched, 10 * (sizeof(u_int8_t *) + 0x100));
+ KFREE(*sched, M_CRYPTO_DATA);
+ *sched = NULL;
+}
diff --git a/sys/opencrypto/xform_userland.h b/sys/opencrypto/xform_userland.h
new file mode 100644
index 0000000..04266dc
--- /dev/null
+++ b/sys/opencrypto/xform_userland.h
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2015 Allan Jude <allanjude@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _CRYPTO_XFORM_USERLAND_H_
+#define _CRYPTO_XFORM_USERLAND_H_
+
+#ifdef _KERNEL
+#include <sys/systm.h>
+#define KMALLOC(size, type, flags) malloc(size, type, flags)
+#define KFREE(ptr, type) free(ptr, type)
+#else /* not _KERNEL */
+#ifdef _STAND
+#include <stand.h>
+#else /* !_STAND */
+#include <stdlib.h>
+#include <string.h>
+#endif /* _STAND */
+#define KMALLOC(size, type, flags) malloc(size)
+#define KFREE(ptr, type) free(ptr)
+#endif /* _KERNEL */
+
+
+#endif /* _CRYPTO_XFORM_USERLAND_H_ */
diff --git a/sys/sparc64/include/ktr.h b/sys/sparc64/include/ktr.h
index b129dd8..f8c1b43 100644
--- a/sys/sparc64/include/ktr.h
+++ b/sys/sparc64/include/ktr.h
@@ -59,7 +59,7 @@ l2: add r2, 1, r3 ; \
add r1, r2, r1 ; \
rd %tick, r2 ; \
stx r2, [r1 + KTR_TIMESTAMP] ; \
- lduw [PCPU(MID)], r2 ; \
+ lduw [PCPU(CPUID)], r2 ; \
stw r2, [r1 + KTR_CPU] ; \
stw %g0, [r1 + KTR_LINE] ; \
stx %g0, [r1 + KTR_FILE] ; \
diff --git a/sys/sys/copyright.h b/sys/sys/copyright.h
index 6e47358..e3c1e40 100644
--- a/sys/sys/copyright.h
+++ b/sys/sys/copyright.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (C) 1992-2015 The FreeBSD Project. All rights reserved.
+ * Copyright (C) 1992-2016 The FreeBSD Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -34,7 +34,7 @@
/* FreeBSD */
#define COPYRIGHT_FreeBSD \
- "Copyright (c) 1992-2015 The FreeBSD Project.\n"
+ "Copyright (c) 1992-2016 The FreeBSD Project.\n"
/* Foundation */
#define TRADEMARK_Foundation \
diff --git a/sys/sys/param.h b/sys/sys/param.h
index 69eb391..3c9747a 100644
--- a/sys/sys/param.h
+++ b/sys/sys/param.h
@@ -58,7 +58,7 @@
* in the range 5 to 9.
*/
#undef __FreeBSD_version
-#define __FreeBSD_version 1100092 /* Master, propagated to newvers */
+#define __FreeBSD_version 1100093 /* Master, propagated to newvers */
/*
* __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,
diff --git a/sys/xen/xenbus/xenbusb.c b/sys/xen/xenbus/xenbusb.c
index 4853b3a..0352548 100644
--- a/sys/xen/xenbus/xenbusb.c
+++ b/sys/xen/xenbus/xenbusb.c
@@ -561,7 +561,6 @@ xenbusb_devices_changed(struct xs_watch *watch, const char **vec,
struct xenbusb_softc *xbs;
device_t dev;
char *node;
- char *bus;
char *type;
char *id;
char *p;
@@ -580,7 +579,6 @@ xenbusb_devices_changed(struct xs_watch *watch, const char **vec,
p = strchr(node, '/');
if (p == NULL)
goto out;
- bus = node;
*p = 0;
type = p + 1;
diff --git a/tests/sys/kern/unix_passfd_test.c b/tests/sys/kern/unix_passfd_test.c
index 44f136f..12568389 100644
--- a/tests/sys/kern/unix_passfd_test.c
+++ b/tests/sys/kern/unix_passfd_test.c
@@ -109,7 +109,7 @@ samefile(struct stat *sb1, struct stat *sb2)
}
static void
-sendfd_payload(int sockfd, int sendfd, void *payload, size_t paylen)
+sendfd_payload(int sockfd, int send_fd, void *payload, size_t paylen)
{
struct iovec iovec;
char message[CMSG_SPACE(sizeof(int))];
@@ -133,7 +133,7 @@ sendfd_payload(int sockfd, int sendfd, void *payload, size_t paylen)
cmsghdr->cmsg_len = CMSG_LEN(sizeof(int));
cmsghdr->cmsg_level = SOL_SOCKET;
cmsghdr->cmsg_type = SCM_RIGHTS;
- memcpy(CMSG_DATA(cmsghdr), &sendfd, sizeof(int));
+ memcpy(CMSG_DATA(cmsghdr), &send_fd, sizeof(int));
len = sendmsg(sockfd, &msghdr, 0);
ATF_REQUIRE_MSG(len != -1, "sendmsg failed: %s", strerror(errno));
@@ -143,15 +143,15 @@ sendfd_payload(int sockfd, int sendfd, void *payload, size_t paylen)
}
static void
-sendfd(int sockfd, int sendfd)
+sendfd(int sockfd, int send_fd)
{
char ch = 0;
- return (sendfd_payload(sockfd, sendfd, &ch, sizeof(ch)));
+ return (sendfd_payload(sockfd, send_fd, &ch, sizeof(ch)));
}
static void
-recvfd_payload(int sockfd, int *recvfd, void *buf, size_t buflen)
+recvfd_payload(int sockfd, int *recv_fd, void *buf, size_t buflen)
{
struct cmsghdr *cmsghdr;
char message[CMSG_SPACE(SOCKCREDSIZE(CMGROUP_MAX)) + sizeof(int)];
@@ -178,25 +178,25 @@ recvfd_payload(int sockfd, int *recvfd, void *buf, size_t buflen)
cmsghdr = CMSG_FIRSTHDR(&msghdr);
ATF_REQUIRE_MSG(cmsghdr != NULL,
"recvmsg: did not receive control message");
- *recvfd = -1;
+ *recv_fd = -1;
for (; cmsghdr != NULL; cmsghdr = CMSG_NXTHDR(&msghdr, cmsghdr)) {
if (cmsghdr->cmsg_level == SOL_SOCKET &&
cmsghdr->cmsg_type == SCM_RIGHTS &&
cmsghdr->cmsg_len == CMSG_LEN(sizeof(int))) {
- memcpy(recvfd, CMSG_DATA(cmsghdr), sizeof(int));
- ATF_REQUIRE(*recvfd != -1);
+ memcpy(recv_fd, CMSG_DATA(cmsghdr), sizeof(int));
+ ATF_REQUIRE(*recv_fd != -1);
}
}
- ATF_REQUIRE_MSG(*recvfd != -1,
+ ATF_REQUIRE_MSG(*recv_fd != -1,
"recvmsg: did not receive single-fd message");
}
static void
-recvfd(int sockfd, int *recvfd)
+recvfd(int sockfd, int *recv_fd)
{
char ch = 0;
- return (recvfd_payload(sockfd, recvfd, &ch, sizeof(ch)));
+ return (recvfd_payload(sockfd, recv_fd, &ch, sizeof(ch)));
}
/*
diff --git a/usr.sbin/bhyve/bhyverun.c b/usr.sbin/bhyve/bhyverun.c
index 4fd9c35..bfa135b 100644
--- a/usr.sbin/bhyve/bhyverun.c
+++ b/usr.sbin/bhyve/bhyverun.c
@@ -310,14 +310,13 @@ static int
vmexit_inout(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu)
{
int error;
- int bytes, port, in, out, string;
+ int bytes, port, in, out;
int vcpu;
vcpu = *pvcpu;
port = vme->u.inout.port;
bytes = vme->u.inout.bytes;
- string = vme->u.inout.string;
in = vme->u.inout.in;
out = !in;
@@ -599,7 +598,7 @@ static vmexit_handler_t handler[VM_EXITCODE_MAX] = {
static void
vm_loop(struct vmctx *ctx, int vcpu, uint64_t startrip)
{
- int error, rc, prevcpu;
+ int error, rc;
enum vm_exitcode exitcode;
cpuset_t active_cpus;
@@ -620,8 +619,6 @@ vm_loop(struct vmctx *ctx, int vcpu, uint64_t startrip)
if (error != 0)
break;
- prevcpu = vcpu;
-
exitcode = vmexit[vcpu].exitcode;
if (exitcode >= VM_EXITCODE_MAX || handler[exitcode] == NULL) {
fprintf(stderr, "vm_loop: unexpected exitcode 0x%x\n",
@@ -629,7 +626,7 @@ vm_loop(struct vmctx *ctx, int vcpu, uint64_t startrip)
exit(1);
}
- rc = (*handler[exitcode])(ctx, &vmexit[vcpu], &vcpu);
+ rc = (*handler[exitcode])(ctx, &vmexit[vcpu], &vcpu);
switch (rc) {
case VMEXIT_CONTINUE:
diff --git a/usr.sbin/bhyve/pci_emul.c b/usr.sbin/bhyve/pci_emul.c
index af427ef..c6763c9 100644
--- a/usr.sbin/bhyve/pci_emul.c
+++ b/usr.sbin/bhyve/pci_emul.c
@@ -863,10 +863,9 @@ msixcap_cfgwrite(struct pci_devinst *pi, int capoff, int offset,
int bytes, uint32_t val)
{
uint16_t msgctrl, rwmask;
- int off, table_bar;
+ int off;
off = offset - capoff;
- table_bar = pi->pi_msix.table_bar;
/* Message Control Register */
if (off == 2 && bytes == 2) {
rwmask = PCIM_MSIXCTRL_MSIX_ENABLE | PCIM_MSIXCTRL_FUNCTION_MASK;
diff --git a/usr.sbin/camdd/camdd.c b/usr.sbin/camdd/camdd.c
index 573214e..9284eb5 100644
--- a/usr.sbin/camdd/camdd.c
+++ b/usr.sbin/camdd/camdd.c
@@ -1276,7 +1276,6 @@ camdd_probe_pass(struct cam_device *cam_dev, struct camdd_io_opts *io_opts,
struct camdd_dev_pass *pass_dev;
struct kevent ke;
int scsi_dev_type;
- int retval;
dev = NULL;
@@ -1336,7 +1335,6 @@ camdd_probe_pass(struct cam_device *cam_dev, struct camdd_io_opts *io_opts,
if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
cam_error_print(cam_dev, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr);
- retval = 1;
goto bailout;
}
@@ -1371,11 +1369,8 @@ camdd_probe_pass(struct cam_device *cam_dev, struct camdd_io_opts *io_opts,
if (cam_send_ccb(cam_dev, ccb) < 0) {
warn("error sending READ CAPACITY (16) command");
-
cam_error_print(cam_dev, ccb, CAM_ESF_ALL,
CAM_EPF_ALL, stderr);
-
- retval = 1;
goto bailout;
}
OpenPOWER on IntegriCloud