summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorngie <ngie@FreeBSD.org>2015-12-31 21:51:38 +0000
committerngie <ngie@FreeBSD.org>2015-12-31 21:51:38 +0000
commit1ce5880b96d860b35dd841ffb1fec742c1c019d6 (patch)
tree3aa79d15890879ed3ccdbf3d6eeb38835112bc3c
parent15afae85deb48e3e52ed3d9df3b576cb58793c31 (diff)
parentb8cae6c53bb98cfc07d21feaa7d74ffcf5e09bb2 (diff)
downloadFreeBSD-src-1ce5880b96d860b35dd841ffb1fec742c1c019d6.zip
FreeBSD-src-1ce5880b96d860b35dd841ffb1fec742c1c019d6.tar.gz
MFhead @ r293006
-rw-r--r--COPYRIGHT2
-rw-r--r--ObsoleteFiles.inc2
-rw-r--r--bin/sh/expand.c764
-rw-r--r--bin/sh/expand.h5
-rw-r--r--contrib/binutils/bfd/elf32-arm.c26
-rw-r--r--contrib/llvm/patches/patch-02-add-CC-aliases.diff23
-rw-r--r--contrib/llvm/tools/clang/tools/driver/driver.cpp2
-rw-r--r--lib/libc/stdio/findfp.c11
-rw-r--r--lib/libc/sys/ptrace.239
-rw-r--r--lib/libmd/mdXhl.c13
-rw-r--r--lib/libstand/Makefile6
-rw-r--r--sbin/reboot/reboot.c2
-rw-r--r--sys/arm/arm/locore-v6.S63
-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.4th43
-rw-r--r--sys/boot/i386/loader/main.c57
-rw-r--r--sys/boot/uboot/common/main.c10
-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/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/mlx5/mlx5_en/en.h3
-rw-r--r--sys/dev/mlx5/mlx5_en/mlx5_en_ethtool.c92
-rw-r--r--sys/dev/mlx5/mlx5_en/mlx5_en_main.c79
-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/kern/kern_fork.c7
-rw-r--r--sys/kern/kern_ktr.c3
-rw-r--r--sys/kern/kern_sig.c7
-rw-r--r--sys/kern/kern_thr.c63
-rw-r--r--sys/kern/kern_thread.c11
-rw-r--r--sys/kern/sys_process.c15
-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/powerpc/booke/booke_machdep.c14
-rw-r--r--sys/powerpc/booke/locore.S180
-rw-r--r--sys/powerpc/booke/machdep_e500.c59
-rw-r--r--sys/powerpc/booke/pmap.c60
-rw-r--r--sys/powerpc/mpc85xx/mpc85xx.c171
-rw-r--r--sys/powerpc/mpc85xx/mpc85xx.h38
-rw-r--r--sys/powerpc/mpc85xx/platform_mpc85xx.c100
-rw-r--r--sys/sparc64/include/ktr.h25
-rw-r--r--sys/sparc64/sparc64/exception.S94
-rw-r--r--sys/sparc64/sparc64/mp_exception.S23
-rw-r--r--sys/sparc64/sparc64/pmap.c17
-rw-r--r--sys/sparc64/sparc64/swtch.S6
-rw-r--r--sys/sys/copyright.h4
-rw-r--r--sys/sys/param.h2
-rw-r--r--sys/sys/proc.h4
-rw-r--r--sys/sys/ptrace.h3
-rw-r--r--sys/x86/include/specialreg.h1
-rw-r--r--sys/x86/x86/identcpu.c2
-rw-r--r--sys/xen/xenbus/xenbusb.c2
-rw-r--r--tests/sys/kern/Makefile1
-rw-r--r--tests/sys/kern/ptrace_test.c193
-rw-r--r--tests/sys/kern/unix_passfd_test.c396
-rw-r--r--tools/regression/sockets/unix_passfd/Makefile7
-rw-r--r--tools/regression/sockets/unix_passfd/unix_passfd.c390
-rwxr-xr-xusr.bin/clang/clang/CC.sh4
-rw-r--r--usr.bin/clang/clang/Makefile4
-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
-rw-r--r--usr.sbin/makefs/makefs.c2
125 files changed, 5914 insertions, 2667 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/ObsoleteFiles.inc b/ObsoleteFiles.inc
index cf5d2a2..dff00ae 100644
--- a/ObsoleteFiles.inc
+++ b/ObsoleteFiles.inc
@@ -105,6 +105,8 @@ OLD_FILES+=usr/lib/clang/3.7.0/include/xopintrin.h
OLD_FILES+=usr/lib/clang/3.7.0/include/xtestintrin.h
OLD_DIRS+=usr/lib/clang/3.7.0/include
OLD_FILES+=usr/lib/clang/3.7.0/lib/freebsd/libclang_rt.asan-i386.a
+OLD_FILES+=usr/lib/clang/3.7.0/lib/freebsd/libclang_rt.asan-preinit-i386.a
+OLD_FILES+=usr/lib/clang/3.7.0/lib/freebsd/libclang_rt.asan-preinit-x86_64.a
OLD_FILES+=usr/lib/clang/3.7.0/lib/freebsd/libclang_rt.asan-x86_64.a
OLD_FILES+=usr/lib/clang/3.7.0/lib/freebsd/libclang_rt.asan_cxx-i386.a
OLD_FILES+=usr/lib/clang/3.7.0/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
diff --git a/bin/sh/expand.c b/bin/sh/expand.c
index 6217982..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,41 +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(char *, char *, int, int, int, int, int);
-static char *evalvar(char *, 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, 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
@@ -168,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
@@ -183,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));
}
@@ -220,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;
@@ -252,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 '=':
@@ -285,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 == '=')
@@ -297,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);
}
}
}
@@ -344,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++;
@@ -352,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;
@@ -406,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;
@@ -424,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;
}
@@ -433,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) {
@@ -475,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);
@@ -497,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),
@@ -520,109 +531,108 @@ recordleft(const char *str, const char *loc, char *startp)
*startp++ = *loc++;
}
-static int
-subevalvar(char *p, char *str, int strloc, int subtype, int startloc,
- int varflags, 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, (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX ||
- subtype == VSTRIMRIGHT || subtype == VSTRIMRIGHTMAX ?
- EXP_CASE : 0) | EXP_TILDE);
+ argstr(p, EXP_CASE | EXP_TILDE, NULL);
STACKSTRNUL(expdest);
argbackq = saveargbackq;
startp = stackblock() + startloc;
- if (str == NULL)
- str = stackblock() + strloc;
+ str = stackblock() + strloc;
switch (subtype) {
- case VSASSIGN:
- setvar(str, startp, 0);
- amount = startp - expdest;
- STADJUST(amount, expdest);
- varflags &= ~VSNUL;
- return 1;
-
- case VSQUESTION:
- if (*p != CTLENDVAR) {
- outfmt(out2, "%s\n", startp);
- error((char *)NULL);
- }
- error("%.*s: parameter %snot set", (int)(p - str - 1),
- str, (varflags & VSNUL) ? "null or " : "");
- return 0;
-
case VSTRIMLEFT:
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);
+}
+
+
+static int
+subevalvar_misc(char *p, const char *var, int subtype, int startloc,
+ int varflags)
+{
+ char *startp;
+ struct nodelist *saveargbackq = argbackq;
+ int amount;
+
+ argstr(p, EXP_TILDE, NULL);
+ STACKSTRNUL(expdest);
+ argbackq = saveargbackq;
+ startp = stackblock() + startloc;
+ switch (subtype) {
+ case VSASSIGN:
+ setvar(var, startp, 0);
+ amount = startp - expdest;
+ STADJUST(amount, expdest);
+ return 1;
+
+ case VSQUESTION:
+ if (*p != CTLENDVAR) {
+ outfmt(out2, "%s\n", startp);
+ error((char *)NULL);
+ }
+ error("%.*s: parameter %snot set", (int)(p - var - 1),
+ var, (varflags & VSNUL) ? "null or " : "");
+ return 0;
default:
abort();
@@ -636,7 +646,7 @@ subevalvar(char *p, char *str, int strloc, int subtype, int startloc,
*/
static char *
-evalvar(char *p, int flag)
+evalvar(char *p, int flag, struct worddest *dst)
{
int subtype;
int varflags;
@@ -649,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;
@@ -693,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;
@@ -717,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:
@@ -760,32 +768,22 @@ again: /* jump here after setting a variable with ${var=text} */
*/
STPUTC('\0', expdest);
patloc = expdest - stackblock();
- if (subevalvar(p, NULL, patloc, subtype,
- startloc, varflags, 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:
case VSQUESTION:
if (!set) {
- if (subevalvar(p, var, 0, subtype, startloc, varflags,
- quotes)) {
+ 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:
@@ -797,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 (;;) {
@@ -867,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 '$':
@@ -902,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 */
@@ -924,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:
@@ -942,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);
+ cvtnum(num, buf);
+ strtodest(buf, flag, subtype, quoted, dst);
}
-/*
- * 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;
-}
-
-
-
-/*
- * 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);
+ }
}
@@ -1161,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')
@@ -1174,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++;
@@ -1190,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;
@@ -1208,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++;
@@ -1238,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 == '.')
@@ -1247,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;
@@ -1337,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;
@@ -1355,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) {
@@ -1380,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
@@ -1409,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) {
@@ -1426,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)
@@ -1444,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) {
@@ -1468,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)
@@ -1482,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++;
@@ -1539,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;
}
@@ -1552,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];
@@ -1568,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/contrib/llvm/patches/patch-02-add-CC-aliases.diff b/contrib/llvm/patches/patch-02-add-CC-aliases.diff
deleted file mode 100644
index 884b14c..0000000
--- a/contrib/llvm/patches/patch-02-add-CC-aliases.diff
+++ /dev/null
@@ -1,23 +0,0 @@
-This patch adds "CC" and "clang-CC" to the list of program name aliases which
-invoke the C++ compiler.
-
-Introduced here: http://svnweb.freebsd.org/changeset/base/257109
-
-Index: tools/clang/tools/driver/driver.cpp
-===================================================================
---- tools/clang/tools/driver/driver.cpp
-+++ tools/clang/tools/driver/driver.cpp
-@@ -213,11 +213,13 @@ static const DriverSuffix *FindDriverSuffix(String
- {"clang", nullptr},
- {"clang++", "--driver-mode=g++"},
- {"clang-c++", "--driver-mode=g++"},
-+ {"clang-CC", "--driver-mode=g++"},
- {"clang-cc", nullptr},
- {"clang-cpp", "--driver-mode=cpp"},
- {"clang-g++", "--driver-mode=g++"},
- {"clang-gcc", nullptr},
- {"clang-cl", "--driver-mode=cl"},
-+ {"CC", "--driver-mode=g++"},
- {"cc", nullptr},
- {"cpp", "--driver-mode=cpp"},
- {"cl", "--driver-mode=cl"},
diff --git a/contrib/llvm/tools/clang/tools/driver/driver.cpp b/contrib/llvm/tools/clang/tools/driver/driver.cpp
index b64fa8c..5925447 100644
--- a/contrib/llvm/tools/clang/tools/driver/driver.cpp
+++ b/contrib/llvm/tools/clang/tools/driver/driver.cpp
@@ -214,13 +214,11 @@ static const DriverSuffix *FindDriverSuffix(StringRef ProgName) {
{"clang", nullptr},
{"clang++", "--driver-mode=g++"},
{"clang-c++", "--driver-mode=g++"},
- {"clang-CC", "--driver-mode=g++"},
{"clang-cc", nullptr},
{"clang-cpp", "--driver-mode=cpp"},
{"clang-g++", "--driver-mode=g++"},
{"clang-gcc", nullptr},
{"clang-cl", "--driver-mode=cl"},
- {"CC", "--driver-mode=g++"},
{"cc", nullptr},
{"cpp", "--driver-mode=cpp"},
{"cl", "--driver-mode=cl"},
diff --git a/lib/libc/stdio/findfp.c b/lib/libc/stdio/findfp.c
index 6a68958..5e1f069 100644
--- a/lib/libc/stdio/findfp.c
+++ b/lib/libc/stdio/findfp.c
@@ -99,16 +99,7 @@ moreglue(int n)
FILE *p;
size_t align;
- /*
- * FILE has a mbstate_t variable. This variable tries to be int64_t
- * aligned through its definition. int64_t may be larger than void *,
- * which is the size traditionally used for ALIGNBYTES. So, use our own
- * rounding instead of the MI ALIGN macros. If for some reason
- * ALIGNBYTES is larger than int64_t, respect that too. There appears to
- * be no portable way to ask for FILE's alignment requirements other
- * than just knowing here.
- */
- align = MAX(ALIGNBYTES, sizeof(int64_t));
+ align = __alignof__(FILE);
g = (struct glue *)malloc(sizeof(*g) + align + n * sizeof(FILE));
if (g == NULL)
return (NULL);
diff --git a/lib/libc/sys/ptrace.2 b/lib/libc/sys/ptrace.2
index a94e314..786f457 100644
--- a/lib/libc/sys/ptrace.2
+++ b/lib/libc/sys/ptrace.2
@@ -2,7 +2,7 @@
.\" $NetBSD: ptrace.2,v 1.2 1995/02/27 12:35:37 cgd Exp $
.\"
.\" This file is in the public domain.
-.Dd October 20, 2015
+.Dd December 29, 2015
.Dt PTRACE 2
.Os
.Sh NAME
@@ -372,6 +372,20 @@ The flag is set for first event reported from a new child, which is
automatically attached due to
.Dv PT_FOLLOW_FORK
enabled.
+.It PL_FLAG_BORN
+This flag is set for the first event reported from a new LWP when LWP
+events are enabled via
+.Dv PT_LWP_EVENTS .
+It is reported along with
+.Dv PL_FLAG_SCX
+and is always reported if LWP events are enabled.
+.It PL_FLAG_EXITED
+This flag is set for the last event reported by an exiting LWP when
+LWP events are enabled via
+.Dv PT_LWP_EVENTS .
+Note that this event is not reported when the last LWP in a process exits.
+The termination of the last thread is reported via a normal process exit
+event.
.El
.It pl_sigmask
The current signal mask of the LWP
@@ -463,6 +477,29 @@ Child processes do not inherit this property.
The traced process will set the
.Dv PL_FLAG_FORKED
flag upon exit from a system call that creates a new process.
+.It PT_LWP_EVENTS
+This request controls tracing of LWP creation and destruction.
+If
+.Fa data
+is non-zero,
+then LWPs will stop to report creation and destruction events.
+If
+.Fa data
+is zero,
+then LWP creation and destruction events will not be reported.
+By default, tracing is not enabled for LWP events.
+Child processes do not inherit this property.
+New LWPs will stop to report an event with
+.Dv PL_FLAG_BORN
+set before executing their first instruction.
+Exiting LWPs will stop to report an event with
+.Dv PL_FLAG_EXITED
+set before completing their termination.
+.Pp
+Note that new processes do not report an event for the creation of their
+initial thread,
+and exiting processes do not report an event for the termination of the
+last thread.
.It PT_VM_TIMESTAMP
This request returns the generation number or timestamp of the memory map of
the traced process as the return value from
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/sbin/reboot/reboot.c b/sbin/reboot/reboot.c
index eaaa5b5..961ba41 100644
--- a/sbin/reboot/reboot.c
+++ b/sbin/reboot/reboot.c
@@ -76,7 +76,7 @@ main(int argc, char *argv[])
howto = RB_HALT;
} else
howto = 0;
- lflag = nflag = qflag = 0;
+ lflag = nflag = qflag = Nflag = 0;
while ((ch = getopt(argc, argv, "dk:lNnpqr")) != -1)
switch(ch) {
case 'd':
diff --git a/sys/arm/arm/locore-v6.S b/sys/arm/arm/locore-v6.S
index ac19906..b66b601 100644
--- a/sys/arm/arm/locore-v6.S
+++ b/sys/arm/arm/locore-v6.S
@@ -153,46 +153,49 @@ ASENTRY_NP(_start)
* Build page table from scratch.
*/
- /* Calculate the physical address of the startup pagetable. */
+ /*
+ * Figure out the physical address we're loaded at by assuming this
+ * entry point code is in the first L1 section and so if we clear the
+ * offset bits of the pc that will give us the section-aligned load
+ * address, which remains in r5 throughout all the following code.
+ */
+ ldr r2, =(L1_S_OFFSET)
+ bic r5, pc, r2
+
+ /* Find the delta between VA and PA, result stays in r0 throughout. */
adr r0, Lpagetable
bl translate_va_to_pa
- /* Clear boot page table */
- mov r1, r0
- mov r2, L1_TABLE_SIZE
- mov r3,#0
-1: str r3, [r1], #4
- subs r2, #4
- bgt 1b
-
- /*
- * Map PA == VA
+ /*
+ * First map the entire 4GB address space as VA=PA. It's mapped as
+ * normal (cached) memory because it's for things like accessing the
+ * parameters passed in from the bootloader, which might be at any
+ * physical address, different for every platform.
*/
- /* Find the start kernels load address */
- adr r5, _start
- ldr r2, =(PTE1_OFFSET)
- bic r5, r2
- mov r1, r5
- mov r2, r5
- /* Map 64MiB, preserved over calls to build_pagetables */
- mov r3, #64
+ mov r1, #0
+ mov r2, #0
+ mov r3, #4096
bl build_pagetables
- /* Create the kernel map to jump to */
+ /*
+ * Next we do 64MiB starting at the physical load address, mapped to
+ * the VA the kernel is linked for.
+ */
mov r1, r5
ldr r2, =(KERNVIRTADDR)
+ mov r3, #64
bl build_pagetables
+ /* Create a device mapping for early_printf if specified. */
#if defined(SOCDEV_PA) && defined(SOCDEV_VA)
- /* Create the custom map (1MB) used for early_printf(). */
ldr r1, =SOCDEV_PA
ldr r2, =SOCDEV_VA
mov r3, #1
- bl build_pagetables
+ bl build_device_pagetables
#endif
bl init_mmu
- /* Switch to virtual addresses. */
+ /* Transition the PC from physical to virtual addressing. */
ldr pc, =1f
1:
@@ -394,6 +397,15 @@ END(reinit_mmu)
*
* Addresses must be 1MiB aligned
*/
+build_device_pagetables:
+#if defined(ARM_NEW_PMAP)
+ ldr r4, =PTE1_V|PTE1_A|PTE1_AP_KRW|TEX1_CLASS_0
+#elif defined(SMP)
+ ldr r4, =(L1_TYPE_S|L1_S_AP(AP_KRW)|L1_SHARED)
+#else
+ ldr r4, =(L1_TYPE_S|L1_S_AP(AP_KRW))
+#endif
+ b 1f
build_pagetables:
/* Set the required page attributed */
#if defined(ARM_NEW_PMAP)
@@ -403,18 +415,19 @@ build_pagetables:
#else
ldr r4, =(L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW))
#endif
+1:
orr r1, r4
/* Move the virtual address to the correct bit location */
lsr r2, #(PTE1_SHIFT - 2)
mov r4, r3
-1:
+2:
str r1, [r0, r2]
add r2, r2, #4
add r1, r1, #(PTE1_SIZE)
adds r4, r4, #-1
- bhi 1b
+ bhi 2b
mov pc, lr
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 08f5004..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=
;
@@ -833,7 +833,7 @@ get-current ( -- wid ) previous definitions >search ( wid -- )
repeat
;
-: peek_file
+: peek_file ( addr len -- )
0 to end_of_file?
reset_line_reading
O_RDONLY fopen fd !
@@ -844,6 +844,7 @@ get-current ( -- wid ) previous definitions >search ( wid -- )
['] process_assignment catch
['] free_buffers catch
fd @ fclose
+ swap throw throw
;
only forth also support-functions definitions
@@ -851,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 !
@@ -930,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
@@ -943,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
;
@@ -970,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 )
@@ -1021,25 +1043,26 @@ string current_file_name_ref \ used to print the file name
;
: get_nextboot_conf_file ( -- addr len )
- nextboot_conf_file strget strdup \ XXX is the strdup a leak ?
+ nextboot_conf_file strget
;
: rewrite_nextboot_file ( -- )
get_nextboot_conf_file
O_WRONLY fopen fd !
fd @ -1 = if EOPEN throw then
- fd @ s' nextboot_enable="NO" ' fwrite
+ fd @ s' nextboot_enable="NO" ' fwrite ( fd buf len -- nwritten ) drop
fd @ fclose
;
-: include_nextboot_file
+: include_nextboot_file ( -- )
get_nextboot_conf_file
- ['] peek_file catch
+ ['] peek_file catch if 2drop then
nextboot? if
get_nextboot_conf_file
+ current_file_name_ref strref
['] load_conf catch
process_conf_errors
- ['] rewrite_nextboot_file catch
+ ['] rewrite_nextboot_file catch if 2drop then
then
;
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/uboot/common/main.c b/sys/boot/uboot/common/main.c
index 3071426..6c7b893 100644
--- a/sys/boot/uboot/common/main.c
+++ b/sys/boot/uboot/common/main.c
@@ -585,6 +585,10 @@ handle_uboot_env_var(enum ubenv_action action, const char * var)
*/
if (action == UBENV_IMPORT) {
len = strcspn(var, "=");
+ if (len == 0) {
+ printf("name cannot start with '=': '%s'\n", var);
+ return;
+ }
if (var[len] == 0) {
strcpy(ldvar, "uboot.");
strncat(ldvar, var, sizeof(ldvar) - 7);
@@ -604,9 +608,11 @@ handle_uboot_env_var(enum ubenv_action action, const char * var)
var = &var[6];
}
- /* If ldvar is malformed or there's no variable name left, punt. */
- if (ldvar[0] == 0 || var[0] == 0)
+ /* If there is no variable name left, punt. */
+ if (var[0] == 0) {
+ printf("empty variable name\n");
return;
+ }
val = ub_env_get(var);
if (action == UBENV_SHOW) {
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/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/mlx5/mlx5_en/en.h b/sys/dev/mlx5/mlx5_en/en.h
index bb779d2..5b22d76 100644
--- a/sys/dev/mlx5/mlx5_en/en.h
+++ b/sys/dev/mlx5/mlx5_en/en.h
@@ -698,7 +698,7 @@ enum mlx5e_link_mode {
MLX5E_56GBASE_R4 = 8,
MLX5E_10GBASE_CR = 12,
MLX5E_10GBASE_SR = 13,
- MLX5E_10GBASE_ER = 14,
+ MLX5E_10GBASE_LR = 14,
MLX5E_40GBASE_SR4 = 15,
MLX5E_40GBASE_LR4 = 16,
MLX5E_100GBASE_CR4 = 20,
@@ -787,5 +787,6 @@ void mlx5e_create_stats(struct sysctl_ctx_list *,
struct sysctl_oid_list *, const char *,
const char **, unsigned, u64 *);
void mlx5e_send_nop(struct mlx5e_sq *, u32, bool);
+int mlx5e_refresh_channel_params(struct mlx5e_priv *);
#endif /* _MLX5_EN_H_ */
diff --git a/sys/dev/mlx5/mlx5_en/mlx5_en_ethtool.c b/sys/dev/mlx5/mlx5_en/mlx5_en_ethtool.c
index 17e4461..e389a07 100644
--- a/sys/dev/mlx5/mlx5_en/mlx5_en_ethtool.c
+++ b/sys/dev/mlx5/mlx5_en/mlx5_en_ethtool.c
@@ -69,12 +69,49 @@ mlx5e_ethtool_handler(SYSCTL_HANDLER_ARGS)
} else {
error = 0;
}
-
/* check if device is gone */
if (priv->gone) {
error = ENXIO;
goto done;
}
+ /* import RX coal time */
+ if (priv->params_ethtool.rx_coalesce_usecs < 1)
+ priv->params_ethtool.rx_coalesce_usecs = 0;
+ else if (priv->params_ethtool.rx_coalesce_usecs >
+ MLX5E_FLD_MAX(cqc, cq_period)) {
+ priv->params_ethtool.rx_coalesce_usecs =
+ MLX5E_FLD_MAX(cqc, cq_period);
+ }
+ priv->params.rx_cq_moderation_usec = priv->params_ethtool.rx_coalesce_usecs;
+
+ /* import RX coal pkts */
+ if (priv->params_ethtool.rx_coalesce_pkts < 1)
+ priv->params_ethtool.rx_coalesce_pkts = 0;
+ else if (priv->params_ethtool.rx_coalesce_pkts >
+ MLX5E_FLD_MAX(cqc, cq_max_count)) {
+ priv->params_ethtool.rx_coalesce_pkts =
+ MLX5E_FLD_MAX(cqc, cq_max_count);
+ }
+ priv->params.rx_cq_moderation_pkts = priv->params_ethtool.rx_coalesce_pkts;
+
+ /* import TX coal time */
+ if (priv->params_ethtool.tx_coalesce_usecs < 1)
+ priv->params_ethtool.tx_coalesce_usecs = 0;
+ else if (priv->params_ethtool.tx_coalesce_usecs >
+ MLX5E_FLD_MAX(cqc, cq_period)) {
+ priv->params_ethtool.tx_coalesce_usecs =
+ MLX5E_FLD_MAX(cqc, cq_period);
+ }
+ priv->params.tx_cq_moderation_usec = priv->params_ethtool.tx_coalesce_usecs;
+
+ /* import TX coal pkts */
+ if (priv->params_ethtool.tx_coalesce_pkts < 1)
+ priv->params_ethtool.tx_coalesce_pkts = 0;
+ else if (priv->params_ethtool.tx_coalesce_pkts >
+ MLX5E_FLD_MAX(cqc, cq_max_count)) {
+ priv->params_ethtool.tx_coalesce_pkts = MLX5E_FLD_MAX(cqc, cq_max_count);
+ }
+ priv->params.tx_cq_moderation_pkts = priv->params_ethtool.tx_coalesce_pkts;
if (&priv->params_ethtool.arg[arg2] == &priv->params_ethtool.rx_pauseframe_control ||
&priv->params_ethtool.arg[arg2] == &priv->params_ethtool.tx_pauseframe_control) {
@@ -92,9 +129,19 @@ mlx5e_ethtool_handler(SYSCTL_HANDLER_ARGS)
}
was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state);
- if (was_opened)
+ if (was_opened) {
+ u64 *xarg = priv->params_ethtool.arg + arg2;
+
+ if (xarg == &priv->params_ethtool.tx_coalesce_pkts ||
+ xarg == &priv->params_ethtool.rx_coalesce_pkts ||
+ xarg == &priv->params_ethtool.tx_coalesce_usecs ||
+ xarg == &priv->params_ethtool.rx_coalesce_usecs) {
+ /* avoid downing and upping the network interface */
+ error = mlx5e_refresh_channel_params(priv);
+ goto done;
+ }
mlx5e_close_locked(priv->ifp);
-
+ }
/* import TX queue size */
if (priv->params_ethtool.tx_queue_size <
(1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE)) {
@@ -145,45 +192,6 @@ mlx5e_ethtool_handler(SYSCTL_HANDLER_ARGS)
priv->params_ethtool.tx_coalesce_mode = 1;
priv->params.tx_cq_moderation_mode = priv->params_ethtool.tx_coalesce_mode;
- /* import RX coal time */
- if (priv->params_ethtool.rx_coalesce_usecs < 1)
- priv->params_ethtool.rx_coalesce_usecs = 0;
- else if (priv->params_ethtool.rx_coalesce_usecs >
- MLX5E_FLD_MAX(cqc, cq_period)) {
- priv->params_ethtool.rx_coalesce_usecs =
- MLX5E_FLD_MAX(cqc, cq_period);
- }
- priv->params.rx_cq_moderation_usec = priv->params_ethtool.rx_coalesce_usecs;
-
- /* import RX coal pkts */
- if (priv->params_ethtool.rx_coalesce_pkts < 1)
- priv->params_ethtool.rx_coalesce_pkts = 0;
- else if (priv->params_ethtool.rx_coalesce_pkts >
- MLX5E_FLD_MAX(cqc, cq_max_count)) {
- priv->params_ethtool.rx_coalesce_pkts =
- MLX5E_FLD_MAX(cqc, cq_max_count);
- }
- priv->params.rx_cq_moderation_pkts = priv->params_ethtool.rx_coalesce_pkts;
-
- /* import TX coal time */
- if (priv->params_ethtool.tx_coalesce_usecs < 1)
- priv->params_ethtool.tx_coalesce_usecs = 0;
- else if (priv->params_ethtool.tx_coalesce_usecs >
- MLX5E_FLD_MAX(cqc, cq_period)) {
- priv->params_ethtool.tx_coalesce_usecs =
- MLX5E_FLD_MAX(cqc, cq_period);
- }
- priv->params.tx_cq_moderation_usec = priv->params_ethtool.tx_coalesce_usecs;
-
- /* import TX coal pkts */
- if (priv->params_ethtool.tx_coalesce_pkts < 1)
- priv->params_ethtool.tx_coalesce_pkts = 0;
- else if (priv->params_ethtool.tx_coalesce_pkts >
- MLX5E_FLD_MAX(cqc, cq_max_count)) {
- priv->params_ethtool.tx_coalesce_pkts = MLX5E_FLD_MAX(cqc, cq_max_count);
- }
- priv->params.tx_cq_moderation_pkts = priv->params_ethtool.tx_coalesce_pkts;
-
/* we always agree to turn off HW LRO - but not always to turn on */
if (priv->params_ethtool.hw_lro) {
if (priv->params_ethtool.hw_lro != 1) {
diff --git a/sys/dev/mlx5/mlx5_en/mlx5_en_main.c b/sys/dev/mlx5/mlx5_en/mlx5_en_main.c
index 63db417..82ea69d 100644
--- a/sys/dev/mlx5/mlx5_en/mlx5_en_main.c
+++ b/sys/dev/mlx5/mlx5_en/mlx5_en_main.c
@@ -106,8 +106,8 @@ static const struct {
.subtype = IFM_10G_SR,
.baudrate = IF_Gbps(10ULL),
},
- [MLX5E_10GBASE_ER] = {
- .subtype = IFM_10G_ER,
+ [MLX5E_10GBASE_LR] = {
+ .subtype = IFM_10G_LR,
.baudrate = IF_Gbps(10ULL),
},
[MLX5E_40GBASE_SR4] = {
@@ -1712,6 +1712,62 @@ mlx5e_close_channels(struct mlx5e_priv *priv)
}
static int
+mlx5e_refresh_sq_params(struct mlx5e_priv *priv, struct mlx5e_sq *sq)
+{
+ return (mlx5_core_modify_cq_moderation(priv->mdev, &sq->cq.mcq,
+ priv->params.tx_cq_moderation_usec,
+ priv->params.tx_cq_moderation_pkts));
+}
+
+static int
+mlx5e_refresh_rq_params(struct mlx5e_priv *priv, struct mlx5e_rq *rq)
+{
+ return (mlx5_core_modify_cq_moderation(priv->mdev, &rq->cq.mcq,
+ priv->params.rx_cq_moderation_usec,
+ priv->params.rx_cq_moderation_pkts));
+}
+
+static int
+mlx5e_refresh_channel_params_sub(struct mlx5e_priv *priv, struct mlx5e_channel *c)
+{
+ int err;
+ int i;
+
+ if (c == NULL)
+ return (EINVAL);
+
+ err = mlx5e_refresh_rq_params(priv, &c->rq);
+ if (err)
+ goto done;
+
+ for (i = 0; i != c->num_tc; i++) {
+ err = mlx5e_refresh_sq_params(priv, &c->sq[i]);
+ if (err)
+ goto done;
+ }
+done:
+ return (err);
+}
+
+int
+mlx5e_refresh_channel_params(struct mlx5e_priv *priv)
+{
+ int i;
+
+ if (priv->channel == NULL)
+ return (EINVAL);
+
+ for (i = 0; i < priv->params.num_channels; i++) {
+ int err;
+
+ err = mlx5e_refresh_channel_params_sub(priv, priv->channel[i]);
+ if (err)
+ return (err);
+ }
+ return (0);
+}
+
+static int
mlx5e_open_tis(struct mlx5e_priv *priv, int tc)
{
struct mlx5_core_dev *mdev = priv->mdev;
@@ -2298,6 +2354,7 @@ mlx5e_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
int size_read = 0;
int module_num;
int max_mtu;
+ uint8_t read_addr;
priv = ifp->if_softc;
@@ -2484,11 +2541,21 @@ out:
}
/*
- * Note that we ignore i2c.addr here. The driver hardcodes
- * the address to 0x50, while standard expects it to be 0xA0.
+ * Currently 0XA0 and 0xA2 are the only addresses permitted.
+ * The internal conversion is as follows:
*/
+ if (i2c.dev_addr == 0xA0)
+ read_addr = MLX5E_I2C_ADDR_LOW;
+ else if (i2c.dev_addr == 0xA2)
+ read_addr = MLX5E_I2C_ADDR_HIGH;
+ else {
+ if_printf(ifp, "Query eeprom failed, "
+ "Invalid Address: %X\n", i2c.dev_addr);
+ error = EINVAL;
+ goto err_i2c;
+ }
error = mlx5_query_eeprom(priv->mdev,
- MLX5E_I2C_ADDR_LOW, MLX5E_EEPROM_LOW_PAGE,
+ read_addr, MLX5E_EEPROM_LOW_PAGE,
(uint32_t)i2c.offset, (uint32_t)i2c.len, module_num,
(uint32_t *)i2c.data, &size_read);
if (error) {
@@ -2499,7 +2566,7 @@ out:
if (i2c.len > MLX5_EEPROM_MAX_BYTES) {
error = mlx5_query_eeprom(priv->mdev,
- MLX5E_I2C_ADDR_LOW, MLX5E_EEPROM_LOW_PAGE,
+ read_addr, MLX5E_EEPROM_LOW_PAGE,
(uint32_t)(i2c.offset + size_read),
(uint32_t)(i2c.len - size_read), module_num,
(uint32_t *)(i2c.data + size_read), &size_read);
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/kern/kern_fork.c b/sys/kern/kern_fork.c
index a395fdd..e7d7276 100644
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -1066,7 +1066,7 @@ fork_return(struct thread *td, struct trapframe *frame)
cv_broadcast(&p->p_dbgwait);
}
PROC_UNLOCK(p);
- } else if (p->p_flag & P_TRACED) {
+ } else if (p->p_flag & P_TRACED || td->td_dbgflags & TDB_BORN) {
/*
* This is the start of a new thread in a traced
* process. Report a system call exit event.
@@ -1074,9 +1074,10 @@ fork_return(struct thread *td, struct trapframe *frame)
PROC_LOCK(p);
td->td_dbgflags |= TDB_SCX;
_STOPEVENT(p, S_SCX, td->td_dbg_sc_code);
- if ((p->p_stops & S_PT_SCX) != 0)
+ if ((p->p_stops & S_PT_SCX) != 0 ||
+ (td->td_dbgflags & TDB_BORN) != 0)
ptracestop(td, SIGTRAP);
- td->td_dbgflags &= ~TDB_SCX;
+ td->td_dbgflags &= ~(TDB_SCX | TDB_BORN);
PROC_UNLOCK(p);
}
diff --git a/sys/kern/kern_ktr.c b/sys/kern/kern_ktr.c
index 32ded48..6885706 100644
--- a/sys/kern/kern_ktr.c
+++ b/sys/kern/kern_ktr.c
@@ -55,9 +55,6 @@ __FBSDID("$FreeBSD$");
#include <sys/time.h>
#include <machine/cpu.h>
-#ifdef __sparc64__
-#include <machine/ktr.h>
-#endif
#ifdef DDB
#include <ddb/ddb.h>
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
index 510b920..75a1259 100644
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -2501,7 +2501,12 @@ ptracestop(struct thread *td, int sig)
td->td_tid, p->p_pid, td->td_dbgflags, sig);
PROC_SLOCK(p);
while ((p->p_flag & P_TRACED) && (td->td_dbgflags & TDB_XSIG)) {
- if (p->p_flag & P_SINGLE_EXIT) {
+ if (p->p_flag & P_SINGLE_EXIT &&
+ !(td->td_dbgflags & TDB_EXIT)) {
+ /*
+ * Ignore ptrace stops except for thread exit
+ * events when the process exits.
+ */
td->td_dbgflags &= ~TDB_XSIG;
PROC_SUNLOCK(p);
return (sig);
diff --git a/sys/kern/kern_thr.c b/sys/kern/kern_thr.c
index 9e878d8..1b226dd 100644
--- a/sys/kern/kern_thr.c
+++ b/sys/kern/kern_thr.c
@@ -253,6 +253,8 @@ thread_create(struct thread *td, struct rtprio *rtp,
thread_unlock(td);
if (P_SHOULDSTOP(p))
newtd->td_flags |= TDF_ASTPENDING | TDF_NEEDSUSPCHK;
+ if (p->p_flag2 & P2_LWP_EVENTS)
+ newtd->td_dbgflags |= TDB_BORN;
/*
* Copy the existing thread VM policy into the new thread.
@@ -322,29 +324,54 @@ kern_thr_exit(struct thread *td)
p = td->td_proc;
- rw_wlock(&tidhash_lock);
+ /*
+ * If all of the threads in a process call this routine to
+ * exit (e.g. all threads call pthread_exit()), exactly one
+ * thread should return to the caller to terminate the process
+ * instead of the thread.
+ *
+ * Checking p_numthreads alone is not sufficient since threads
+ * might be committed to terminating while the PROC_LOCK is
+ * dropped in either ptracestop() or while removing this thread
+ * from the tidhash. Instead, the p_pendingexits field holds
+ * the count of threads in either of those states and a thread
+ * is considered the "last" thread if all of the other threads
+ * in a process are already terminating.
+ */
PROC_LOCK(p);
-
- if (p->p_numthreads != 1) {
- racct_sub(p, RACCT_NTHR, 1);
- LIST_REMOVE(td, td_hash);
- rw_wunlock(&tidhash_lock);
- tdsigcleanup(td);
- umtx_thread_exit(td);
- PROC_SLOCK(p);
- thread_stopped(p);
- thread_exit();
- /* NOTREACHED */
+ if (p->p_numthreads == p->p_pendingexits + 1) {
+ /*
+ * Ignore attempts to shut down last thread in the
+ * proc. This will actually call _exit(2) in the
+ * usermode trampoline when it returns.
+ */
+ PROC_UNLOCK(p);
+ return (0);
}
+ p->p_pendingexits++;
+ td->td_dbgflags |= TDB_EXIT;
+ if (p->p_flag & P_TRACED && p->p_flag2 & P2_LWP_EVENTS)
+ ptracestop(td, SIGTRAP);
+ PROC_UNLOCK(p);
+ tidhash_remove(td);
+ PROC_LOCK(p);
+ p->p_pendingexits--;
+
/*
- * Ignore attempts to shut down last thread in the proc. This
- * will actually call _exit(2) in the usermode trampoline when
- * it returns.
+ * The check above should prevent all other threads from this
+ * process from exiting while the PROC_LOCK is dropped, so
+ * there must be at least one other thread other than the
+ * current thread.
*/
- PROC_UNLOCK(p);
- rw_wunlock(&tidhash_lock);
- return (0);
+ KASSERT(p->p_numthreads > 1, ("too few threads"));
+ racct_sub(p, RACCT_NTHR, 1);
+ tdsigcleanup(td);
+ umtx_thread_exit(td);
+ PROC_SLOCK(p);
+ thread_stopped(p);
+ thread_exit();
+ /* NOTREACHED */
}
int
diff --git a/sys/kern/kern_thread.c b/sys/kern/kern_thread.c
index ac96ca5..66b6120 100644
--- a/sys/kern/kern_thread.c
+++ b/sys/kern/kern_thread.c
@@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
#include <sys/sched.h>
#include <sys/sleepqueue.h>
#include <sys/selinfo.h>
+#include <sys/syscallsubr.h>
#include <sys/sysent.h>
#include <sys/turnstile.h>
#include <sys/ktr.h>
@@ -942,7 +943,6 @@ thread_suspend_check(int return_instead)
*/
if ((p->p_flag & P_SINGLE_EXIT) && (p->p_singlethread != td)) {
PROC_UNLOCK(p);
- tidhash_remove(td);
/*
* Allow Linux emulation layer to do some work
@@ -950,13 +950,8 @@ thread_suspend_check(int return_instead)
*/
if (__predict_false(p->p_sysent->sv_thread_detach != NULL))
(p->p_sysent->sv_thread_detach)(td);
-
- PROC_LOCK(p);
- tdsigcleanup(td);
- umtx_thread_exit(td);
- PROC_SLOCK(p);
- thread_stopped(p);
- thread_exit();
+ kern_thr_exit(td);
+ panic("stopped thread did not exit");
}
PROC_SLOCK(p);
diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c
index 732d754..a6037e3 100644
--- a/sys/kern/sys_process.c
+++ b/sys/kern/sys_process.c
@@ -710,6 +710,7 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
case PT_TO_SCX:
case PT_SYSCALL:
case PT_FOLLOW_FORK:
+ case PT_LWP_EVENTS:
case PT_DETACH:
sx_xlock(&proctree_lock);
proctree_locked = 1;
@@ -948,6 +949,16 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
p->p_flag &= ~P_FOLLOWFORK;
break;
+ case PT_LWP_EVENTS:
+ CTR3(KTR_PTRACE, "PT_LWP_EVENTS: pid %d %s -> %s", p->p_pid,
+ p->p_flag2 & P2_LWP_EVENTS ? "enabled" : "disabled",
+ data ? "enabled" : "disabled");
+ if (data)
+ p->p_flag2 |= P2_LWP_EVENTS;
+ else
+ p->p_flag2 &= ~P2_LWP_EVENTS;
+ break;
+
case PT_STEP:
case PT_CONTINUE:
case PT_TO_SCE:
@@ -1252,6 +1263,10 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
}
if (td2->td_dbgflags & TDB_CHILD)
pl->pl_flags |= PL_FLAG_CHILD;
+ if (td2->td_dbgflags & TDB_BORN)
+ pl->pl_flags |= PL_FLAG_BORN;
+ if (td2->td_dbgflags & TDB_EXIT)
+ pl->pl_flags |= PL_FLAG_EXITED;
pl->pl_sigmask = td2->td_sigmask;
pl->pl_siglist = td2->td_siglist;
strcpy(pl->pl_tdname, td2->td_name);
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/powerpc/booke/booke_machdep.c b/sys/powerpc/booke/booke_machdep.c
index c98e301..f102677 100644
--- a/sys/powerpc/booke/booke_machdep.c
+++ b/sys/powerpc/booke/booke_machdep.c
@@ -316,8 +316,20 @@ booke_init(uint32_t arg1, uint32_t arg2)
ret = powerpc_init(dtbp, 0, 0, mdp);
- /* Enable L1 caches */
+ /* Default to 32 byte cache line size. */
+ switch ((mfpvr()) >> 16) {
+ case FSL_E500mc:
+ case FSL_E5500:
+ case FSL_E6500:
+ cacheline_size = 64;
+ break;
+ }
+
+ /* Enable caches */
booke_enable_l1_cache();
+ booke_enable_l2_cache();
+
+ booke_enable_bpred();
return (ret);
}
diff --git a/sys/powerpc/booke/locore.S b/sys/powerpc/booke/locore.S
index 2ce6e69..2d6c66d 100644
--- a/sys/powerpc/booke/locore.S
+++ b/sys/powerpc/booke/locore.S
@@ -301,7 +301,7 @@ bp_ntlb1s:
.globl bp_tlb1
bp_tlb1:
- .space 4 * 3 * 16
+ .space 4 * 3 * 64
.globl bp_tlb1_end
bp_tlb1_end:
@@ -658,77 +658,6 @@ __boot_page_padding:
/************************************************************************/
/*
- * void tid_flush(tlbtid_t tid);
- *
- * Invalidate all TLB0 entries which match the given TID. Note this is
- * dedicated for cases when invalidation(s) should NOT be propagated to other
- * CPUs.
- *
- * void tid_flush(tlbtid_t tid, int tlb0_ways, int tlb0_entries_per_way);
- *
- * XXX: why isn't this in C?
- */
-ENTRY(tid_flush)
- cmpwi %r3, TID_KERNEL
- beq tid_flush_end /* don't evict kernel translations */
-
- /* Disable interrupts */
- mfmsr %r10
- wrteei 0
-
- li %r6, 0 /* ways counter */
-loop_ways:
- li %r7, 0 /* entries [per way] counter */
-loop_entries:
- /* Select TLB0 and ESEL (way) */
- lis %r8, MAS0_TLBSEL0@h
- rlwimi %r8, %r6, 16, 14, 15
- mtspr SPR_MAS0, %r8
- isync
-
- /* Select EPN (entry within the way) */
- rlwinm %r8, %r7, 12, 13, 19
- mtspr SPR_MAS2, %r8
- isync
- tlbre
-
- /* Check if valid entry */
- mfspr %r8, SPR_MAS1
- andis. %r9, %r8, MAS1_VALID@h
- beq next_entry /* invalid entry */
-
- /* Check if this is our TID */
- rlwinm %r9, %r8, 16, 24, 31
-
- cmplw %r9, %r3
- bne next_entry /* not our TID */
-
- /* Clear VALID bit */
- rlwinm %r8, %r8, 0, 1, 31
- mtspr SPR_MAS1, %r8
- isync
- tlbwe
- isync
- msync
-
-next_entry:
- addi %r7, %r7, 1
- cmpw %r7, %r5
- bne loop_entries
-
- /* Next way */
- addi %r6, %r6, 1
- cmpw %r6, %r4
- bne loop_ways
-
- /* Restore MSR (possibly re-enable interrupts) */
- mtmsr %r10
- isync
-
-tid_flush_end:
- blr
-
-/*
* Cache disable/enable/inval sequences according
* to section 2.16 of E500CORE RM.
*/
@@ -802,6 +731,113 @@ ENTRY(icache_enable)
blr
/*
+ * L2 cache disable/enable/inval sequences for E500mc.
+ */
+
+ENTRY(l2cache_inval)
+ mfspr %r3, SPR_L2CSR0
+ oris %r3, %r3, (L2CSR0_L2FI | L2CSR0_L2LFC)@h
+ ori %r3, %r3, (L2CSR0_L2FI | L2CSR0_L2LFC)@l
+ isync
+ mtspr SPR_L2CSR0, %r3
+ isync
+1: mfspr %r3, SPR_L2CSR0
+ andis. %r3, %r3, L2CSR0_L2FI@h
+ bne 1b
+ blr
+
+ENTRY(l2cache_enable)
+ mfspr %r3, SPR_L2CSR0
+ oris %r3, %r3, (L2CSR0_L2E | L2CSR0_L2PE)@h
+ isync
+ mtspr SPR_L2CSR0, %r3
+ isync
+ blr
+
+/*
+ * Branch predictor setup.
+ */
+ENTRY(bpred_enable)
+ mfspr %r3, SPR_BUCSR
+ ori %r3, %r3, BUCSR_BBFI
+ isync
+ mtspr SPR_BUCSR, %r3
+ isync
+ ori %r3, %r3, BUCSR_BPEN
+ isync
+ mtspr SPR_BUCSR, %r3
+ isync
+ blr
+
+ENTRY(dataloss_erratum_access)
+ /* Lock two cache lines into I-Cache */
+ sync
+ mfspr %r11, SPR_L1CSR1
+ rlwinm %r11, %r11, 0, ~L1CSR1_ICUL
+ sync
+ isync
+ mtspr SPR_L1CSR1, %r11
+ isync
+
+ mflr %r9
+ bl 1f
+ .long 2f-.
+1:
+ mflr %r5
+ lwz %r8, 0(%r5)
+ mtlr %r9
+ add %r8, %r8, %r5
+ icbtls 0, 0, %r8
+ addi %r9, %r8, 64
+
+ sync
+ mfspr %r11, SPR_L1CSR1
+3: andi. %r11, %r11, L1CSR1_ICUL
+ bne 3b
+
+ icbtls 0, 0, %r9
+
+ sync
+ mfspr %r11, SPR_L1CSR1
+3: andi. %r11, %r11, L1CSR1_ICUL
+ bne 3b
+
+ b 2f
+ .align 6
+ /* Inside a locked cacheline, wait a while, write, then wait a while */
+2: sync
+
+ mfspr %r5, TBR_TBL
+4: addis %r11, %r5, 0x100000@h /* wait around one million timebase ticks */
+ mfspr %r5, TBR_TBL
+ subf. %r5, %r5, %r11
+ bgt 4b
+
+ stw %r4, 0(%r3)
+
+ mfspr %r5, TBR_TBL
+4: addis %r11, %r5, 0x100000@h /* wait around one million timebase ticks */
+ mfspr %r5, TBR_TBL
+ subf. %r5, %r5, %r11
+ bgt 4b
+
+ sync
+
+ /*
+ * Fill out the rest of this cache line and the next with nops,
+ * to ensure that nothing outside the locked area will be
+ * fetched due to a branch.
+ */
+ .rept 19
+ nop
+ .endr
+
+ icblc 0, 0, %r8
+ icblc 0, 0, %r9
+
+ blr
+
+/*
* int setfault()
*
* Similar to setjmp to setup for handling faults on accesses to user memory.
diff --git a/sys/powerpc/booke/machdep_e500.c b/sys/powerpc/booke/machdep_e500.c
index ab47f62..e0e6095 100644
--- a/sys/powerpc/booke/machdep_e500.c
+++ b/sys/powerpc/booke/machdep_e500.c
@@ -27,9 +27,15 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include <sys/cdefs.h>
#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/proc.h>
#include <sys/reboot.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
#include <machine/machdep.h>
#include <dev/fdt/fdt_common.h>
@@ -42,6 +48,7 @@ extern void icache_enable(void);
extern void icache_inval(void);
extern void l2cache_enable(void);
extern void l2cache_inval(void);
+extern void bpred_enable(void);
void
booke_init_tlb(vm_paddr_t fdt_immr_pa)
@@ -79,7 +86,6 @@ booke_enable_l1_cache(void)
(csr & L1CSR1_ICE) ? "en" : "dis");
}
-#if 0
void
booke_enable_l2_cache(void)
{
@@ -102,55 +108,18 @@ booke_enable_l2_cache(void)
}
void
-booke_enable_l3_cache(void)
+booke_enable_bpred(void)
{
- uint32_t csr, size, ver;
-
- /* Enable L3 CoreNet Platform Cache (CPC) */
- ver = SVR_VER(mfspr(SPR_SVR));
- if (ver == SVR_P2041 || ver == SVR_P2041E || ver == SVR_P3041 ||
- ver == SVR_P3041E || ver == SVR_P5020 || ver == SVR_P5020E) {
- csr = ccsr_read4(OCP85XX_CPC_CSR0);
- if ((csr & OCP85XX_CPC_CSR0_CE) == 0) {
- l3cache_inval();
- l3cache_enable();
- }
+ uint32_t csr;
- csr = ccsr_read4(OCP85XX_CPC_CSR0);
- if ((boothowto & RB_VERBOSE) != 0 ||
- (csr & OCP85XX_CPC_CSR0_CE) == 0) {
- size = OCP85XX_CPC_CFG0_SZ_K(ccsr_read4(OCP85XX_CPC_CFG0));
- printf("L3 Corenet Platform Cache: %d KB %sabled\n",
- size, (csr & OCP85XX_CPC_CSR0_CE) == 0 ?
- "dis" : "en");
- }
- }
+ bpred_enable();
+ csr = mfspr(SPR_BUCSR);
+ if ((boothowto & RB_VERBOSE) != 0 || (csr & BUCSR_BPEN) == 0)
+ printf("Branch Predictor %sabled\n",
+ (csr & BUCSR_BPEN) ? "en" : "dis");
}
void
booke_disable_l2_cache(void)
{
}
-
-static void
-l3cache_inval(void)
-{
-
- /* Flash invalidate the CPC and clear all the locks */
- ccsr_write4(OCP85XX_CPC_CSR0, OCP85XX_CPC_CSR0_FI |
- OCP85XX_CPC_CSR0_LFC);
- while (ccsr_read4(OCP85XX_CPC_CSR0) & (OCP85XX_CPC_CSR0_FI |
- OCP85XX_CPC_CSR0_LFC))
- ;
-}
-
-static void
-l3cache_enable(void)
-{
-
- ccsr_write4(OCP85XX_CPC_CSR0, OCP85XX_CPC_CSR0_CE |
- OCP85XX_CPC_CSR0_PE);
- /* Read back to sync write */
- ccsr_read4(OCP85XX_CPC_CSR0);
-}
-#endif
diff --git a/sys/powerpc/booke/pmap.c b/sys/powerpc/booke/pmap.c
index 6ea98b7..bb1a7b5 100644
--- a/sys/powerpc/booke/pmap.c
+++ b/sys/powerpc/booke/pmap.c
@@ -161,7 +161,6 @@ unsigned int kernel_ptbls; /* Number of KVA ptbls. */
#define PMAP_REMOVE_DONE(pmap) \
((pmap) != kernel_pmap && (pmap)->pm_stats.resident_count == 0)
-extern void tid_flush(tlbtid_t tid, int tlb0_ways, int tlb0_entries_per_way);
extern int elf32_nxstack;
/**************************************************************************/
@@ -195,6 +194,7 @@ static unsigned int tlb1_idx;
static vm_offset_t tlb1_map_base = VM_MAX_KERNEL_ADDRESS;
static tlbtid_t tid_alloc(struct pmap *);
+static void tid_flush(tlbtid_t tid);
static void tlb_print_entry(int, uint32_t, uint32_t, uint32_t, uint32_t);
@@ -2235,8 +2235,17 @@ mmu_booke_zero_page_area(mmu_t mmu, vm_page_t m, int off, int size)
static void
mmu_booke_zero_page(mmu_t mmu, vm_page_t m)
{
+ vm_offset_t off, va;
- mmu_booke_zero_page_area(mmu, m, 0, PAGE_SIZE);
+ mtx_lock(&zero_page_mutex);
+ va = zero_page_va;
+
+ mmu_booke_kenter(mmu, va, VM_PAGE_TO_PHYS(m));
+ for (off = 0; off < PAGE_SIZE; off += cacheline_size)
+ __asm __volatile("dcbzl 0,%0" :: "r"(va + off));
+ mmu_booke_kremove(mmu, va);
+
+ mtx_unlock(&zero_page_mutex);
}
/*
@@ -2915,7 +2924,7 @@ tid_alloc(pmap_t pmap)
tidbusy[thiscpu][tid]->pm_tid[thiscpu] = TID_NONE;
/* Flush all entries from TLB0 matching this TID. */
- tid_flush(tid, tlb0_ways, tlb0_entries_per_way);
+ tid_flush(tid);
}
tidbusy[thiscpu][tid] = pmap;
@@ -3426,3 +3435,48 @@ tlb1_iomapped(int i, vm_paddr_t pa, vm_size_t size, vm_offset_t *va)
*va = (tlb1[i].mas2 & MAS2_EPN_MASK) + (pa - pa_start);
return (0);
}
+
+/*
+ * Invalidate all TLB0 entries which match the given TID. Note this is
+ * dedicated for cases when invalidations should NOT be propagated to other
+ * CPUs.
+ */
+static void
+tid_flush(tlbtid_t tid)
+{
+ register_t msr;
+ uint32_t mas0, mas1, mas2;
+ int entry, way;
+
+
+ /* Don't evict kernel translations */
+ if (tid == TID_KERNEL)
+ return;
+
+ msr = mfmsr();
+ __asm __volatile("wrteei 0");
+
+ for (way = 0; way < TLB0_WAYS; way++)
+ for (entry = 0; entry < TLB0_ENTRIES_PER_WAY; entry++) {
+
+ mas0 = MAS0_TLBSEL(0) | MAS0_ESEL(way);
+ mtspr(SPR_MAS0, mas0);
+ __asm __volatile("isync");
+
+ mas2 = entry << MAS2_TLB0_ENTRY_IDX_SHIFT;
+ mtspr(SPR_MAS2, mas2);
+
+ __asm __volatile("isync; tlbre");
+
+ mas1 = mfspr(SPR_MAS1);
+
+ if (!(mas1 & MAS1_VALID))
+ continue;
+ if (((mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT) != tid)
+ continue;
+ mas1 &= ~MAS1_VALID;
+ mtspr(SPR_MAS1, mas1);
+ __asm __volatile("isync; tlbwe; isync; msync");
+ }
+ mtmsr(msr);
+}
diff --git a/sys/powerpc/mpc85xx/mpc85xx.c b/sys/powerpc/mpc85xx/mpc85xx.c
index 6608b4d..717e98a 100644
--- a/sys/powerpc/mpc85xx/mpc85xx.c
+++ b/sys/powerpc/mpc85xx/mpc85xx.c
@@ -32,18 +32,26 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h>
#include <sys/lock.h>
#include <sys/mutex.h>
+#include <sys/reboot.h>
#include <sys/rman.h>
#include <vm/vm.h>
#include <vm/vm_param.h>
+#include <vm/pmap.h>
#include <machine/cpu.h>
#include <machine/cpufunc.h>
+#include <machine/machdep.h>
#include <machine/pio.h>
#include <machine/spr.h>
#include <dev/fdt/fdt_common.h>
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/ofw/openfirm.h>
+
#include <powerpc/mpc85xx/mpc85xx.h>
@@ -249,3 +257,166 @@ law_pci_target(struct resource *res, int *trgt_mem, int *trgt_io)
return (rv);
}
+static void
+l3cache_inval(void)
+{
+
+ /* Flash invalidate the CPC and clear all the locks */
+ ccsr_write4(OCP85XX_CPC_CSR0, OCP85XX_CPC_CSR0_FI |
+ OCP85XX_CPC_CSR0_LFC);
+ while (ccsr_read4(OCP85XX_CPC_CSR0) & (OCP85XX_CPC_CSR0_FI |
+ OCP85XX_CPC_CSR0_LFC))
+ ;
+}
+
+static void
+l3cache_enable(void)
+{
+
+ ccsr_write4(OCP85XX_CPC_CSR0, OCP85XX_CPC_CSR0_CE |
+ OCP85XX_CPC_CSR0_PE);
+ /* Read back to sync write */
+ ccsr_read4(OCP85XX_CPC_CSR0);
+}
+
+void
+mpc85xx_enable_l3_cache(void)
+{
+ uint32_t csr, size, ver;
+
+ /* Enable L3 CoreNet Platform Cache (CPC) */
+ ver = SVR_VER(mfspr(SPR_SVR));
+ if (ver == SVR_P2041 || ver == SVR_P2041E || ver == SVR_P3041 ||
+ ver == SVR_P3041E || ver == SVR_P5020 || ver == SVR_P5020E) {
+ csr = ccsr_read4(OCP85XX_CPC_CSR0);
+ if ((csr & OCP85XX_CPC_CSR0_CE) == 0) {
+ l3cache_inval();
+ l3cache_enable();
+ }
+
+ csr = ccsr_read4(OCP85XX_CPC_CSR0);
+ if ((boothowto & RB_VERBOSE) != 0 ||
+ (csr & OCP85XX_CPC_CSR0_CE) == 0) {
+ size = OCP85XX_CPC_CFG0_SZ_K(ccsr_read4(OCP85XX_CPC_CFG0));
+ printf("L3 Corenet Platform Cache: %d KB %sabled\n",
+ size, (csr & OCP85XX_CPC_CSR0_CE) == 0 ?
+ "dis" : "en");
+ }
+ }
+}
+
+static void
+mpc85xx_dataloss_erratum_spr976(void)
+{
+ uint32_t svr = SVR_VER(mfspr(SPR_SVR));
+
+ /* Ignore whether it's the E variant */
+ svr &= ~0x8;
+
+ if (svr != SVR_P3041 && svr != SVR_P4040 &&
+ svr != SVR_P4080 && svr != SVR_P5020)
+ return;
+
+ mb();
+ isync();
+ mtspr(976, (mfspr(976) & ~0x1f8) | 0x48);
+ isync();
+}
+
+static vm_offset_t
+mpc85xx_map_dcsr(void)
+{
+ phandle_t node;
+ u_long b, s;
+ int err;
+
+ /*
+ * Try to access the dcsr node directly i.e. through /aliases/.
+ */
+ if ((node = OF_finddevice("dcsr")) != -1)
+ if (fdt_is_compatible_strict(node, "fsl,dcsr"))
+ goto moveon;
+ /*
+ * Find the node the long way.
+ */
+ if ((node = OF_finddevice("/")) == -1)
+ return (ENXIO);
+
+ if ((node = ofw_bus_find_compatible(node, "fsl,dcsr")) == 0)
+ return (ENXIO);
+
+moveon:
+ err = fdt_get_range(node, 0, &b, &s);
+
+ if (err != 0)
+ return (err);
+
+#ifdef QORIQ_DPAA
+ law_enable(OCP85XX_TGTIF_DCSR, b, 0x400000);
+#endif
+ return pmap_early_io_map(b, 0x400000);
+}
+
+
+
+void
+mpc85xx_fix_errata(vm_offset_t va_ccsr)
+{
+ uint32_t svr = SVR_VER(mfspr(SPR_SVR));
+ vm_offset_t va_dcsr;
+
+ /* Ignore whether it's the E variant */
+ svr &= ~0x8;
+
+ if (svr != SVR_P3041 && svr != SVR_P4040 &&
+ svr != SVR_P4080 && svr != SVR_P5020)
+ return;
+
+ if (mfmsr() & PSL_EE)
+ return;
+
+ /*
+ * dcsr region need to be mapped thus patch can refer to.
+ * Align dcsr right after ccsbar.
+ */
+ va_dcsr = mpc85xx_map_dcsr();
+ if (va_dcsr == 0)
+ goto err;
+
+ /*
+ * As A004510 errata specify, special purpose register 976
+ * SPR976[56:60] = 6'b001001 must be set. e500mc core reference manual
+ * does not document SPR976 register.
+ */
+ mpc85xx_dataloss_erratum_spr976();
+
+ /*
+ * Specific settings in the CCF and core platform cache (CPC)
+ * are required to reconfigure the CoreNet coherency fabric.
+ * The register settings that should be updated are described
+ * in errata and relay on base address, offset and updated value.
+ * Special conditions must be used to update these registers correctly.
+ */
+ dataloss_erratum_access(va_dcsr + 0xb0e08, 0xe0201800);
+ dataloss_erratum_access(va_dcsr + 0xb0e18, 0xe0201800);
+ dataloss_erratum_access(va_dcsr + 0xb0e38, 0xe0400000);
+ dataloss_erratum_access(va_dcsr + 0xb0008, 0x00900000);
+ dataloss_erratum_access(va_dcsr + 0xb0e40, 0xe00a0000);
+
+ switch (svr) {
+ case SVR_P5020:
+ dataloss_erratum_access(va_ccsr + 0x18600, 0xc0000000);
+ break;
+ case SVR_P4040:
+ case SVR_P4080:
+ dataloss_erratum_access(va_ccsr + 0x18600, 0xff000000);
+ break;
+ case SVR_P3041:
+ dataloss_erratum_access(va_ccsr + 0x18600, 0xf0000000);
+ }
+ dataloss_erratum_access(va_ccsr + 0x10f00, 0x415e5000);
+ dataloss_erratum_access(va_ccsr + 0x11f00, 0x415e5000);
+
+err:
+ return;
+}
diff --git a/sys/powerpc/mpc85xx/mpc85xx.h b/sys/powerpc/mpc85xx/mpc85xx.h
index 31adc58..ac8b8ff 100644
--- a/sys/powerpc/mpc85xx/mpc85xx.h
+++ b/sys/powerpc/mpc85xx/mpc85xx.h
@@ -40,6 +40,25 @@ extern vm_offset_t ccsrbar_va;
#define OCP85XX_CCSRBAR (CCSRBAR_VA + 0x0)
#define OCP85XX_BPTR (CCSRBAR_VA + 0x20)
+#define OCP85XX_BSTRH (CCSRBAR_VA + 0x20)
+#define OCP85XX_BSTRL (CCSRBAR_VA + 0x24)
+#define OCP85XX_BSTAR (CCSRBAR_VA + 0x28)
+
+#define OCP85XX_COREDISR (CCSRBAR_VA + 0xE0094)
+#define OCP85XX_BRR (CCSRBAR_VA + 0xE00E4)
+
+/*
+ * Run Control and Power Management registers
+ */
+#define CCSR_CTBENR (CCSRBAR_VA + 0xE2084)
+#define CCSR_CTBCKSELR (CCSRBAR_VA + 0xE208C)
+#define CCSR_CTBCHLTCR (CCSRBAR_VA + 0xE2094)
+
+/*
+ * DDR Memory controller.
+ */
+#define OCP85XX_DDR1_CS0_CONFIG (CCSRBAR_VA + 0x8080)
+
/*
* E500 Coherency Module registers
*/
@@ -68,6 +87,7 @@ extern vm_offset_t ccsrbar_va;
#define OCP85XX_TGTIF_RAM1 0x10
#define OCP85XX_TGTIF_RAM2 0x11
#define OCP85XX_TGTIF_BMAN 0x18
+#define OCP85XX_TGTIF_DCSR 0x1D
#define OCP85XX_TGTIF_QMAN 0x3C
#define OCP85XX_TRGT_SHIFT 20
#else
@@ -84,6 +104,20 @@ extern vm_offset_t ccsrbar_va;
#define OCP85XX_L2CTL (CCSRBAR_VA + 0x20000)
/*
+ * L3 CoreNet platform cache (CPC) registers
+ */
+#define OCP85XX_CPC_CSR0 (CCSRBAR_VA + 0x10000)
+#define OCP85XX_CPC_CSR0_CE 0x80000000
+#define OCP85XX_CPC_CSR0_PE 0x40000000
+#define OCP85XX_CPC_CSR0_FI 0x00200000
+#define OCP85XX_CPC_CSR0_WT 0x00080000
+#define OCP85XX_CPC_CSR0_FL 0x00000800
+#define OCP85XX_CPC_CSR0_LFC 0x00000400
+#define OCP85XX_CPC_CFG0 (CCSRBAR_VA + 0x10008)
+#define OCP85XX_CPC_CFG_SZ_MASK 0x00003fff
+#define OCP85XX_CPC_CFG0_SZ_K(x) (((x) & OCP85XX_CPC_CFG_SZ_MASK) << 6)
+
+/*
* Power-On Reset configuration
*/
#define OCP85XX_PORDEVSR (CCSRBAR_VA + 0xe000c)
@@ -110,4 +144,8 @@ int law_pci_target(struct resource *, int *, int *);
DECLARE_CLASS(mpc85xx_platform);
int mpc85xx_attach(platform_t);
+void mpc85xx_enable_l3_cache(void);
+void mpc85xx_fix_errata(vm_offset_t);
+void dataloss_erratum_access(vm_offset_t, uint32_t);
+
#endif /* _MPC85XX_H_ */
diff --git a/sys/powerpc/mpc85xx/platform_mpc85xx.c b/sys/powerpc/mpc85xx/platform_mpc85xx.c
index eb9577f..c84561d 100644
--- a/sys/powerpc/mpc85xx/platform_mpc85xx.c
+++ b/sys/powerpc/mpc85xx/platform_mpc85xx.c
@@ -24,6 +24,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include "opt_platform.h"
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
@@ -38,6 +39,7 @@ __FBSDID("$FreeBSD$");
#include <machine/bus.h>
#include <machine/cpu.h>
#include <machine/hid.h>
+#include <machine/machdep.h>
#include <machine/platform.h>
#include <machine/platformvar.h>
#include <machine/smp.h>
@@ -175,6 +177,9 @@ mpc85xx_attach(platform_t plat)
}
ccsrbar_va = pmap_early_io_map(ccsrbar, ccsrsize);
+ mpc85xx_fix_errata(ccsrbar_va);
+ mpc85xx_enable_l3_cache();
+
/*
* Clear local access windows. Skip DRAM entries, so we don't shoot
* ourselves in the foot.
@@ -182,14 +187,14 @@ mpc85xx_attach(platform_t plat)
law_max = law_getmax();
for (i = 0; i < law_max; i++) {
sr = ccsr_read4(OCP85XX_LAWSR(i));
- if ((sr & 0x80000000) == 0)
+ if ((sr & OCP85XX_ENA_MASK) == 0)
continue;
tgt = (sr & 0x01f00000) >> 20;
if (tgt == OCP85XX_TGTIF_RAM1 || tgt == OCP85XX_TGTIF_RAM2 ||
tgt == OCP85XX_TGTIF_RAM_INTL)
continue;
- ccsr_write4(OCP85XX_LAWSR(i), sr & 0x7fffffff);
+ ccsr_write4(OCP85XX_LAWSR(i), sr & OCP85XX_DIS_MASK);
}
return (0);
@@ -256,7 +261,11 @@ mpc85xx_timebase_freq(platform_t plat, struct cpuref *cpuref)
* HID0[SEL_TBCLK] = 0
*/
if (freq != 0)
+#ifdef QORIQ_DPAA
+ ticks = freq / 32;
+#else
ticks = freq / 8;
+#endif
out:
if (ticks <= 0)
@@ -309,17 +318,37 @@ mpc85xx_smp_start_cpu(platform_t plat, struct pcpu *pc)
{
#ifdef SMP
uint32_t *tlb1;
- uint32_t bptr, eebpcr;
+ vm_paddr_t bptr;
+ uint32_t reg;
int i, timeout;
+ uintptr_t brr;
+ int cpuid;
+
+#ifdef QORIQ_DPAA
+ uint32_t tgt;
- eebpcr = ccsr_read4(OCP85XX_EEBPCR);
- if ((eebpcr & (1 << (pc->pc_cpuid + 24))) != 0) {
+ reg = ccsr_read4(OCP85XX_COREDISR);
+ cpuid = pc->pc_cpuid;
+
+ if ((reg & cpuid) != 0) {
+ printf("%s: CPU %d is disabled!\n", __func__, pc->pc_cpuid);
+ return (-1);
+ }
+
+ brr = OCP85XX_BRR;
+#else /* QORIQ_DPAA */
+ brr = OCP85XX_EEBPCR;
+ cpuid = pc->pc_cpuid + 24;
+#endif
+ reg = ccsr_read4(brr);
+ if ((reg & (1 << cpuid)) != 0) {
printf("SMP: CPU %d already out of hold-off state!\n",
pc->pc_cpuid);
return (ENXIO);
}
ap_pcpu = pc;
+ __asm __volatile("msync; isync");
i = 0;
tlb1 = bp_tlb1;
@@ -335,24 +364,67 @@ mpc85xx_smp_start_cpu(platform_t plat, struct pcpu *pc)
if (i < bp_ntlb1s)
bp_ntlb1s = i;
+ /* Flush caches to have our changes hit DRAM. */
+ cpu_flush_dcache(__boot_page, 4096);
+
+ bptr = ((vm_paddr_t)(uintptr_t)__boot_page - KERNBASE) + kernload;
+ KASSERT((bptr & 0xfff) == 0,
+ ("%s: boot page is not aligned (%#jx)", __func__, (uintmax_t)bptr));
+#ifdef QORIQ_DPAA
+
+ /*
+ * Read DDR controller configuration to select proper BPTR target ID.
+ *
+ * On P5020 bit 29 of DDR1_CS0_CONFIG enables DDR controllers
+ * interleaving. If this bit is set, we have to use
+ * OCP85XX_TGTIF_RAM_INTL as BPTR target ID. On other QorIQ DPAA SoCs,
+ * this bit is reserved and always 0.
+ */
+
+ reg = ccsr_read4(OCP85XX_DDR1_CS0_CONFIG);
+ if (reg & (1 << 29))
+ tgt = OCP85XX_TGTIF_RAM_INTL;
+ else
+ tgt = OCP85XX_TGTIF_RAM1;
+
+ /*
+ * Set BSTR to the physical address of the boot page
+ */
+ ccsr_write4(OCP85XX_BSTRH, bptr >> 32);
+ ccsr_write4(OCP85XX_BSTRL, bptr);
+ ccsr_write4(OCP85XX_BSTAR, OCP85XX_ENA_MASK |
+ (tgt << OCP85XX_TRGT_SHIFT) | (ffsl(PAGE_SIZE) - 2));
+
+ /* Read back OCP85XX_BSTAR to synchronize write */
+ ccsr_read4(OCP85XX_BSTAR);
+
+ /*
+ * Enable and configure time base on new CPU.
+ */
+
+ /* Set TB clock source to platform clock / 32 */
+ reg = ccsr_read4(CCSR_CTBCKSELR);
+ ccsr_write4(CCSR_CTBCKSELR, reg & ~(1 << pc->pc_cpuid));
+
+ /* Enable TB */
+ reg = ccsr_read4(CCSR_CTBENR);
+ ccsr_write4(CCSR_CTBENR, reg | (1 << pc->pc_cpuid));
+#else
+
/*
* Set BPTR to the physical address of the boot page
*/
- bptr = ((uint32_t)__boot_page - KERNBASE) + kernload;
- KASSERT((bptr & 0xfff) == 0,
- ("%s: boot page is not aligned (%#x)", __func__, bptr));
bptr = (bptr >> 12) | 0x80000000u;
ccsr_write4(OCP85XX_BPTR, bptr);
__asm __volatile("isync; msync");
- /* Flush caches to have our changes hit DRAM. */
- cpu_flush_dcache(__boot_page, 4096);
+#endif /* QORIQ_DPAA */
/*
* Release AP from hold-off state
*/
- eebpcr |= (1 << (pc->pc_cpuid + 24));
- ccsr_write4(OCP85XX_EEBPCR, eebpcr);
+ reg = ccsr_read4(brr);
+ ccsr_write4(brr, reg | (1 << cpuid));
__asm __volatile("isync; msync");
timeout = 500;
@@ -364,7 +436,11 @@ mpc85xx_smp_start_cpu(platform_t plat, struct pcpu *pc)
* address (= 0xfffff000) isn't permanently remapped and thus not
* usable otherwise.
*/
+#ifdef QORIQ_DPAA
+ ccsr_write4(OCP85XX_BSTAR, 0);
+#else
ccsr_write4(OCP85XX_BPTR, 0);
+#endif
__asm __volatile("isync; msync");
if (!pc->pc_awake)
diff --git a/sys/sparc64/include/ktr.h b/sys/sparc64/include/ktr.h
index 0a7f0e1..f8c1b43 100644
--- a/sys/sparc64/include/ktr.h
+++ b/sys/sparc64/include/ktr.h
@@ -34,14 +34,10 @@
#include <sys/ktr.h>
-#ifndef LOCORE
-
-#define KTR_CPU PCPU_GET(mid)
-
-#else
+#ifdef LOCORE
/*
- * XXX could really use another register...
+ * XXX could really use another register ...
*/
#define ATR(desc, r1, r2, r3, l1, l2) \
.sect .rodata ; \
@@ -63,35 +59,30 @@ 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] ; \
SET(l1 ## b, r3, r2) ; \
stx r2, [r1 + KTR_DESC]
-/*
- * NB: this clobbers %y.
- */
#define CATR(mask, desc, r1, r2, r3, l1, l2, l3) \
- set mask, r1 ; \
- SET(ktr_mask, r3, r2) ; \
- lduw [r2], r2 ; \
+ setx mask, r3, r1 ; \
+ setx ktr_mask, r3, r2 ; \
+ ldx [r2], r2 ; \
and r2, r1, r1 ; \
brz r1, l3 ## f ; \
nop ; \
lduw [PCPU(CPUID)], r2 ; \
mov _NCPUBITS, r3 ; \
- mov %g0, %y ; \
- udiv r2, r3, r2 ; \
+ udivx r2, r3, r2 ; \
srl r2, 0, r2 ; \
sllx r2, PTR_SHIFT, r2 ; \
SET(ktr_cpumask, r3, r1) ; \
ldx [r1 + r2], r1 ; \
lduw [PCPU(CPUID)], r2 ; \
mov _NCPUBITS, r3 ; \
- mov %g0, %y ; \
- udiv r2, r3, r2 ; \
+ udivx r2, r3, r2 ; \
srl r2, 0, r2 ; \
smul r2, r3, r3 ; \
lduw [PCPU(CPUID)], r2 ; \
diff --git a/sys/sparc64/sparc64/exception.S b/sys/sparc64/sparc64/exception.S
index b3830c0..8a1160b 100644
--- a/sys/sparc64/sparc64/exception.S
+++ b/sys/sparc64/sparc64/exception.S
@@ -2628,9 +2628,9 @@ ENTRY(tl0_ret)
andn %l4, TSTATE_CWP_MASK, %g2
/*
- * Save %y in an alternate global.
+ * Restore %y. Could also be below if we had more alternate globals.
*/
- mov %l5, %g4
+ wr %l5, 0, %y
/*
* Setup %wstate for return. We need to restore the user window state
@@ -2675,8 +2675,8 @@ tl0_ret_fill:
* Fixup %tstate so the saved %cwp points to the current window and
* restore it.
*/
- rdpr %cwp, %g1
- wrpr %g2, %g1, %tstate
+ rdpr %cwp, %g4
+ wrpr %g2, %g4, %tstate
/*
* Restore the user window state. The transition bit was set above
@@ -2686,25 +2686,20 @@ tl0_ret_fill:
#if KTR_COMPILE & KTR_TRAP
CATR(KTR_TRAP, "tl0_ret: td=%#lx pil=%#lx pc=%#lx npc=%#lx sp=%#lx"
- , %g1, %g2, %g3, 7, 8, 9)
- ldx [PCPU(CURTHREAD)], %g2
- stx %g2, [%g1 + KTR_PARM1]
- rdpr %pil, %g2
- stx %g2, [%g1 + KTR_PARM2]
- rdpr %tpc, %g2
- stx %g2, [%g1 + KTR_PARM3]
- rdpr %tnpc, %g2
- stx %g2, [%g1 + KTR_PARM4]
- stx %sp, [%g1 + KTR_PARM5]
+ , %g2, %g3, %g4, 7, 8, 9)
+ ldx [PCPU(CURTHREAD)], %g3
+ stx %g3, [%g2 + KTR_PARM1]
+ rdpr %pil, %g3
+ stx %g3, [%g2 + KTR_PARM2]
+ rdpr %tpc, %g3
+ stx %g3, [%g2 + KTR_PARM3]
+ rdpr %tnpc, %g3
+ stx %g3, [%g2 + KTR_PARM4]
+ stx %sp, [%g2 + KTR_PARM5]
9:
#endif
/*
- * Restore %y. Note that the CATR above clobbered it.
- */
- wr %g4, 0, %y
-
- /*
* Return to usermode.
*/
retry
@@ -2718,11 +2713,6 @@ tl0_ret_fill_end:
stx %l6, [%l0 + KTR_PARM2]
stx %sp, [%l0 + KTR_PARM3]
9:
-
- /*
- * Restore %y clobbered by the CATR. This was saved in %l5 above.
- */
- wr %l5, 0, %y
#endif
/*
@@ -2890,36 +2880,34 @@ ENTRY(tl1_ret)
andn %l0, TSTATE_CWP_MASK, %g1
mov %l1, %g2
mov %l2, %g3
- mov %l4, %g4
wrpr %l3, 0, %pil
+ wr %l4, 0, %y
restore
wrpr %g0, 2, %tl
+ rdpr %cwp, %g4
+ wrpr %g1, %g4, %tstate
wrpr %g2, 0, %tpc
wrpr %g3, 0, %tnpc
- rdpr %cwp, %g2
- wrpr %g1, %g2, %tstate
#if KTR_COMPILE & KTR_TRAP
CATR(KTR_TRAP, "tl1_ret: td=%#lx pil=%#lx ts=%#lx pc=%#lx sp=%#lx"
- , %g1, %g2, %g3, 7, 8, 9)
- ldx [PCPU(CURTHREAD)], %g2
- stx %g2, [%g1 + KTR_PARM1]
- rdpr %pil, %g2
- stx %g2, [%g1 + KTR_PARM2]
- rdpr %tstate, %g2
- stx %g2, [%g1 + KTR_PARM3]
- rdpr %tpc, %g2
- stx %g2, [%g1 + KTR_PARM4]
- stx %sp, [%g1 + KTR_PARM5]
+ , %g2, %g3, %g4, 7, 8, 9)
+ ldx [PCPU(CURTHREAD)], %g3
+ stx %g3, [%g2 + KTR_PARM1]
+ rdpr %pil, %g3
+ stx %g3, [%g2 + KTR_PARM2]
+ rdpr %tstate, %g3
+ stx %g3, [%g2 + KTR_PARM3]
+ rdpr %tpc, %g3
+ stx %g3, [%g2 + KTR_PARM4]
+ stx %sp, [%g2 + KTR_PARM5]
9:
#endif
- wr %g4, 0, %y
-
retry
END(tl1_ret)
@@ -3020,35 +3008,33 @@ ENTRY(tl1_intr)
andn %l0, TSTATE_CWP_MASK, %g1
mov %l1, %g2
mov %l2, %g3
- mov %l4, %g4
wrpr %l3, 0, %pil
+ wr %l4, 0, %y
restore
wrpr %g0, 2, %tl
+ rdpr %cwp, %g4
+ wrpr %g1, %g4, %tstate
wrpr %g2, 0, %tpc
wrpr %g3, 0, %tnpc
- rdpr %cwp, %g2
- wrpr %g1, %g2, %tstate
#if KTR_COMPILE & KTR_INTR
CATR(KTR_INTR, "tl1_intr: td=%#x pil=%#lx ts=%#lx pc=%#lx sp=%#lx"
- , %g1, %g2, %g3, 7, 8, 9)
- ldx [PCPU(CURTHREAD)], %g2
- stx %g2, [%g1 + KTR_PARM1]
- rdpr %pil, %g2
- stx %g2, [%g1 + KTR_PARM2]
- rdpr %tstate, %g2
- stx %g2, [%g1 + KTR_PARM3]
- rdpr %tpc, %g2
- stx %g2, [%g1 + KTR_PARM4]
- stx %sp, [%g1 + KTR_PARM5]
+ , %g2, %g3, %g4, 7, 8, 9)
+ ldx [PCPU(CURTHREAD)], %g3
+ stx %g3, [%g2 + KTR_PARM1]
+ rdpr %pil, %g3
+ stx %g3, [%g2 + KTR_PARM2]
+ rdpr %tstate, %g3
+ stx %g3, [%g2 + KTR_PARM3]
+ rdpr %tpc, %g3
+ stx %g3, [%g2 + KTR_PARM4]
+ stx %sp, [%g2 + KTR_PARM5]
9:
#endif
- wr %g4, 0, %y
-
retry
END(tl1_intr)
diff --git a/sys/sparc64/sparc64/mp_exception.S b/sys/sparc64/sparc64/mp_exception.S
index 54a5e4d..9bd61b9 100644
--- a/sys/sparc64/sparc64/mp_exception.S
+++ b/sys/sparc64/sparc64/mp_exception.S
@@ -38,12 +38,10 @@ __FBSDID("$FreeBSD$");
.register %g2, #ignore
.register %g3, #ignore
-#define IPI_DONE(r1, r2, r3, r4, r5, r6) \
- rd %y, r6 ; \
+#define IPI_DONE(r1, r2, r3, r4, r5) \
lduw [PCPU(CPUID)], r2 ; \
mov _NCPUBITS, r3 ; \
- mov %g0, %y ; \
- udiv r2, r3, r4 ; \
+ udivx r2, r3, r4 ; \
srl r4, 0, r5 ; \
sllx r5, PTR_SHIFT, r5 ; \
add r1, r5, r1 ; \
@@ -51,7 +49,6 @@ __FBSDID("$FreeBSD$");
sub r2, r3, r3 ; \
mov 1, r4 ; \
sllx r4, r3, r4 ; \
- wr r6, %y ; \
ATOMIC_CLEAR_LONG(r1, r2, r3, r4)
/*
@@ -89,7 +86,7 @@ ENTRY(tl_ipi_spitfire_dcache_page_inval)
2: brgz,pt %g2, 1b
sub %g2, %g4, %g2
- IPI_DONE(%g5, %g1, %g2, %g3, %g4, %g6)
+ IPI_DONE(%g5, %g1, %g2, %g3, %g4)
retry
END(tl_ipi_spitfire_dcache_page_inval)
@@ -129,7 +126,7 @@ ENTRY(tl_ipi_spitfire_icache_page_inval)
2: brgz,pt %g2, 1b
sub %g2, %g4, %g2
- IPI_DONE(%g5, %g1, %g2, %g3, %g4, %g6)
+ IPI_DONE(%g5, %g1, %g2, %g3, %g4)
retry
END(tl_ipi_spitfire_icache_page_inval)
@@ -160,7 +157,7 @@ ENTRY(tl_ipi_cheetah_dcache_page_inval)
blt,a,pt %xcc, 1b
nop
- IPI_DONE(%g5, %g1, %g2, %g3, %g4, %g6)
+ IPI_DONE(%g5, %g1, %g2, %g3, %g4)
retry
END(tl_ipi_cheetah_dcache_page_inval)
@@ -216,7 +213,7 @@ ENTRY(tl_ipi_tlb_page_demap)
stxa %g0, [%g2] ASI_IMMU_DEMAP
flush %g3
- IPI_DONE(%g5, %g1, %g2, %g3, %g4, %g6)
+ IPI_DONE(%g5, %g1, %g2, %g3, %g4)
retry
END(tl_ipi_tlb_page_demap)
@@ -259,7 +256,7 @@ ENTRY(tl_ipi_tlb_range_demap)
blt,a,pt %xcc, 1b
sethi %hi(KERNBASE), %g6
- IPI_DONE(%g5, %g1, %g2, %g3, %g4, %g6)
+ IPI_DONE(%g5, %g1, %g2, %g3, %g4)
retry
END(tl_ipi_tlb_range_demap)
@@ -283,7 +280,7 @@ ENTRY(tl_ipi_tlb_context_demap)
stxa %g0, [%g1] ASI_IMMU_DEMAP
flush %g3
- IPI_DONE(%g5, %g1, %g2, %g3, %g4, %g6)
+ IPI_DONE(%g5, %g1, %g2, %g3, %g4)
retry
END(tl_ipi_tlb_context_demap)
@@ -295,7 +292,7 @@ ENTRY(tl_ipi_stick_rd)
rd %asr24, %g2
stx %g2, [%g1]
- IPI_DONE(%g5, %g1, %g2, %g3, %g4, %g6)
+ IPI_DONE(%g5, %g1, %g2, %g3, %g4)
retry
END(tl_ipi_stick_rd)
@@ -307,6 +304,6 @@ ENTRY(tl_ipi_tick_rd)
rd %tick, %g2
stx %g2, [%g1]
- IPI_DONE(%g5, %g1, %g2, %g3, %g4, %g6)
+ IPI_DONE(%g5, %g1, %g2, %g3, %g4)
retry
END(tl_ipi_tick_rd)
diff --git a/sys/sparc64/sparc64/pmap.c b/sys/sparc64/sparc64/pmap.c
index e0dca86..21800dd 100644
--- a/sys/sparc64/sparc64/pmap.c
+++ b/sys/sparc64/sparc64/pmap.c
@@ -346,14 +346,18 @@ pmap_bootstrap(u_int cpu_impl)
if (OF_getprop(pmem, "available", mra, sz) == -1)
OF_panic("%s: getprop /memory/available", __func__);
sz /= sizeof(*mra);
- CTR0(KTR_PMAP, "pmap_bootstrap: physical memory");
+#ifdef DIAGNOSTIC
+ OF_printf("pmap_bootstrap: physical memory\n");
+#endif
qsort(mra, sz, sizeof (*mra), mr_cmp);
physsz = 0;
getenv_quad("hw.physmem", &physmem);
physmem = btoc(physmem);
for (i = 0, j = 0; i < sz; i++, j += 2) {
- CTR2(KTR_PMAP, "start=%#lx size=%#lx", mra[i].mr_start,
+#ifdef DIAGNOSTIC
+ OF_printf("start=%#lx size=%#lx\n", mra[i].mr_start,
mra[i].mr_size);
+#endif
if (physmem != 0 && btoc(physsz + mra[i].mr_size) >= physmem) {
if (btoc(physsz) < physmem) {
phys_avail[j] = mra[i].mr_start;
@@ -617,13 +621,16 @@ pmap_bootstrap(u_int cpu_impl)
__func__);
sz /= sizeof(*translations);
translations_size = sz;
- CTR0(KTR_PMAP, "pmap_bootstrap: translations");
+#ifdef DIAGNOSTIC
+ OF_printf("pmap_bootstrap: translations\n");
+#endif
qsort(translations, sz, sizeof (*translations), om_cmp);
for (i = 0; i < sz; i++) {
- CTR3(KTR_PMAP,
- "translation: start=%#lx size=%#lx tte=%#lx",
+#ifdef DIAGNOSTIC
+ OF_printf("translation: start=%#lx size=%#lx tte=%#lx\n",
translations[i].om_start, translations[i].om_size,
translations[i].om_tte);
+#endif
if ((translations[i].om_tte & TD_V) == 0)
continue;
if (translations[i].om_start < VM_MIN_PROM_ADDRESS ||
diff --git a/sys/sparc64/sparc64/swtch.S b/sys/sparc64/sparc64/swtch.S
index 22db805..49d3cf5 100644
--- a/sys/sparc64/sparc64/swtch.S
+++ b/sys/sparc64/sparc64/swtch.S
@@ -173,8 +173,7 @@ ENTRY(cpu_switch)
* active on this CPU.
*/
mov _NCPUBITS, %l5
- mov %g0, %y
- udiv %l3, %l5, %l6
+ udivx %l3, %l5, %l6
srl %l6, 0, %l4
sllx %l4, PTR_SHIFT, %l4
add %l4, PM_ACTIVE, %l4
@@ -242,8 +241,7 @@ ENTRY(cpu_switch)
* Mark the pmap as active on this CPU.
*/
mov _NCPUBITS, %l5
- mov %g0, %y
- udiv %l3, %l5, %l6
+ udivx %l3, %l5, %l6
srl %l6, 0, %l4
sllx %l4, PTR_SHIFT, %l4
add %l4, PM_ACTIVE, %l4
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/sys/proc.h b/sys/sys/proc.h
index cb94318..fc5c90d 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -412,6 +412,8 @@ do { \
#define TDB_STOPATFORK 0x00000080 /* Stop at the return from fork (child
only) */
#define TDB_CHILD 0x00000100 /* New child indicator for ptrace() */
+#define TDB_BORN 0x00000200 /* New LWP indicator for ptrace() */
+#define TDB_EXIT 0x00000400 /* Exiting LWP indicator for ptrace() */
/*
* "Private" flags kept in td_pflags:
@@ -577,6 +579,7 @@ struct proc {
struct itimers *p_itimers; /* (c) POSIX interval timers. */
struct procdesc *p_procdesc; /* (e) Process descriptor, if any. */
u_int p_treeflag; /* (e) P_TREE flags */
+ int p_pendingexits; /* (c) Count of pending thread exits. */
/* End area that is zeroed on creation. */
#define p_endzero p_magic
@@ -695,6 +698,7 @@ struct proc {
#define P2_NOTRACE 0x00000002 /* No ptrace(2) attach or coredumps. */
#define P2_NOTRACE_EXEC 0x00000004 /* Keep P2_NOPTRACE on exec(2). */
#define P2_AST_SU 0x00000008 /* Handles SU ast for kthreads. */
+#define P2_LWP_EVENTS 0x00000010 /* Report LWP events via ptrace(2). */
/* Flags protected by proctree_lock, kept in p_treeflags. */
#define P_TREE_ORPHANED 0x00000001 /* Reparented, on orphan list */
diff --git a/sys/sys/ptrace.h b/sys/sys/ptrace.h
index 7ccd3d6..88a587e 100644
--- a/sys/sys/ptrace.h
+++ b/sys/sys/ptrace.h
@@ -64,6 +64,7 @@
#define PT_SYSCALL 22
#define PT_FOLLOW_FORK 23
+#define PT_LWP_EVENTS 24 /* report LWP birth and exit */
#define PT_GETREGS 33 /* get general-purpose registers */
#define PT_SETREGS 34 /* set general-purpose registers */
@@ -108,6 +109,8 @@ struct ptrace_lwpinfo {
#define PL_FLAG_SI 0x20 /* siginfo is valid */
#define PL_FLAG_FORKED 0x40 /* new child */
#define PL_FLAG_CHILD 0x80 /* I am from child */
+#define PL_FLAG_BORN 0x100 /* new LWP */
+#define PL_FLAG_EXITED 0x200 /* exiting LWP */
sigset_t pl_sigmask; /* LWP signal mask */
sigset_t pl_siglist; /* LWP pending signal */
struct __siginfo pl_siginfo; /* siginfo for signal */
diff --git a/sys/x86/include/specialreg.h b/sys/x86/include/specialreg.h
index b5274b2..5f2c010 100644
--- a/sys/x86/include/specialreg.h
+++ b/sys/x86/include/specialreg.h
@@ -335,6 +335,7 @@
#define CPUID_STDEXT_BMI1 0x00000008
#define CPUID_STDEXT_HLE 0x00000010
#define CPUID_STDEXT_AVX2 0x00000020
+#define CPUID_STDEXT_FDP_EXC 0x00000040
#define CPUID_STDEXT_SMEP 0x00000080
#define CPUID_STDEXT_BMI2 0x00000100
#define CPUID_STDEXT_ERMS 0x00000200
diff --git a/sys/x86/x86/identcpu.c b/sys/x86/x86/identcpu.c
index 902af6b..38c1c66 100644
--- a/sys/x86/x86/identcpu.c
+++ b/sys/x86/x86/identcpu.c
@@ -932,6 +932,8 @@ printcpuinfo(void)
"\005HLE"
/* Advanced Vector Instructions 2 */
"\006AVX2"
+ /* FDP_EXCPTN_ONLY */
+ "\007FDPEXC"
/* Supervisor Mode Execution Prot. */
"\010SMEP"
/* Bit Manipulation Instructions */
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/Makefile b/tests/sys/kern/Makefile
index a38b1f2..c9a7cfd 100644
--- a/tests/sys/kern/Makefile
+++ b/tests/sys/kern/Makefile
@@ -8,6 +8,7 @@ ATF_TESTS_C+= kern_copyin
ATF_TESTS_C+= kern_descrip_test
ATF_TESTS_C+= ptrace_test
ATF_TESTS_C+= unix_seqpacket_test
+ATF_TESTS_C+= unix_passfd_test
TEST_METADATA.unix_seqpacket_test+= timeout="15"
LIBADD.ptrace_test+= pthread
diff --git a/tests/sys/kern/ptrace_test.c b/tests/sys/kern/ptrace_test.c
index f611221..177f412 100644
--- a/tests/sys/kern/ptrace_test.c
+++ b/tests/sys/kern/ptrace_test.c
@@ -1094,6 +1094,16 @@ simple_thread(void *arg __unused)
pthread_exit(NULL);
}
+static __dead2 void
+simple_thread_main(void)
+{
+ pthread_t thread;
+
+ CHILD_REQUIRE(pthread_create(&thread, NULL, simple_thread, NULL) == 0);
+ CHILD_REQUIRE(pthread_join(thread, NULL) == 0);
+ exit(1);
+}
+
/*
* Verify that pl_syscall_code in struct ptrace_lwpinfo for a new
* thread reports the correct value.
@@ -1108,14 +1118,8 @@ ATF_TC_BODY(ptrace__new_child_pl_syscall_code_thread, tc)
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
- pthread_t thread;
-
trace_me();
-
- CHILD_REQUIRE(pthread_create(&thread, NULL, simple_thread,
- NULL) == 0);
- CHILD_REQUIRE(pthread_join(thread, NULL) == 0);
- exit(1);
+ simple_thread_main();
}
/* The first wait() should report the stop from SIGSTOP. */
@@ -1178,6 +1182,179 @@ ATF_TC_BODY(ptrace__new_child_pl_syscall_code_thread, tc)
ATF_REQUIRE(errno == ECHILD);
}
+/*
+ * Verify that the expected LWP events are reported for a child thread.
+ */
+ATF_TC_WITHOUT_HEAD(ptrace__lwp_events);
+ATF_TC_BODY(ptrace__lwp_events, tc)
+{
+ struct ptrace_lwpinfo pl;
+ pid_t fpid, wpid;
+ lwpid_t lwps[2];
+ int status;
+
+ ATF_REQUIRE((fpid = fork()) != -1);
+ if (fpid == 0) {
+ trace_me();
+ simple_thread_main();
+ }
+
+ /* The first wait() should report the stop from SIGSTOP. */
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(wpid == fpid);
+ ATF_REQUIRE(WIFSTOPPED(status));
+ ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
+
+ ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl,
+ sizeof(pl)) != -1);
+ lwps[0] = pl.pl_lwpid;
+
+ ATF_REQUIRE(ptrace(PT_LWP_EVENTS, wpid, NULL, 1) == 0);
+
+ /* Continue the child ignoring the SIGSTOP. */
+ ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+
+ /* The first event should be for the child thread's birth. */
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(wpid == fpid);
+ ATF_REQUIRE(WIFSTOPPED(status));
+ ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP);
+
+ ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
+ ATF_REQUIRE((pl.pl_flags & (PL_FLAG_BORN | PL_FLAG_SCX)) ==
+ (PL_FLAG_BORN | PL_FLAG_SCX));
+ ATF_REQUIRE(pl.pl_lwpid != lwps[0]);
+ lwps[1] = pl.pl_lwpid;
+
+ ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+
+ /* The next event should be for the child thread's death. */
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(wpid == fpid);
+ ATF_REQUIRE(WIFSTOPPED(status));
+ ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP);
+
+ ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
+ ATF_REQUIRE((pl.pl_flags & (PL_FLAG_EXITED | PL_FLAG_SCE)) ==
+ (PL_FLAG_EXITED | PL_FLAG_SCE));
+ ATF_REQUIRE(pl.pl_lwpid == lwps[1]);
+
+ ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+
+ /* The last event should be for the child process's exit. */
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE(WEXITSTATUS(status) == 1);
+
+ wpid = wait(&status);
+ ATF_REQUIRE(wpid == -1);
+ ATF_REQUIRE(errno == ECHILD);
+}
+
+static void *
+exec_thread(void *arg __unused)
+{
+
+ execl("/usr/bin/true", "true", NULL);
+ exit(127);
+}
+
+static __dead2 void
+exec_thread_main(void)
+{
+ pthread_t thread;
+
+ CHILD_REQUIRE(pthread_create(&thread, NULL, exec_thread, NULL) == 0);
+ for (;;)
+ sleep(60);
+ exit(1);
+}
+
+/*
+ * Verify that the expected LWP events are reported for a multithreaded
+ * process that calls execve(2).
+ */
+ATF_TC_WITHOUT_HEAD(ptrace__lwp_events_exec);
+ATF_TC_BODY(ptrace__lwp_events_exec, tc)
+{
+ struct ptrace_lwpinfo pl;
+ pid_t fpid, wpid;
+ lwpid_t lwps[2];
+ int status;
+
+ ATF_REQUIRE((fpid = fork()) != -1);
+ if (fpid == 0) {
+ trace_me();
+ exec_thread_main();
+ }
+
+ /* The first wait() should report the stop from SIGSTOP. */
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(wpid == fpid);
+ ATF_REQUIRE(WIFSTOPPED(status));
+ ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
+
+ ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl,
+ sizeof(pl)) != -1);
+ lwps[0] = pl.pl_lwpid;
+
+ ATF_REQUIRE(ptrace(PT_LWP_EVENTS, wpid, NULL, 1) == 0);
+
+ /* Continue the child ignoring the SIGSTOP. */
+ ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+
+ /* The first event should be for the child thread's birth. */
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(wpid == fpid);
+ ATF_REQUIRE(WIFSTOPPED(status));
+ ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP);
+
+ ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
+ ATF_REQUIRE((pl.pl_flags & (PL_FLAG_BORN | PL_FLAG_SCX)) ==
+ (PL_FLAG_BORN | PL_FLAG_SCX));
+ ATF_REQUIRE(pl.pl_lwpid != lwps[0]);
+ lwps[1] = pl.pl_lwpid;
+
+ ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+
+ /*
+ * The next event should be for the main thread's death due to
+ * single threading from execve().
+ */
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(wpid == fpid);
+ ATF_REQUIRE(WIFSTOPPED(status));
+ ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP);
+
+ ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
+ ATF_REQUIRE((pl.pl_flags & (PL_FLAG_EXITED | PL_FLAG_SCE)) ==
+ (PL_FLAG_EXITED));
+ ATF_REQUIRE(pl.pl_lwpid == lwps[0]);
+
+ ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+
+ /* The next event should be for the child process's exec. */
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(WIFSTOPPED(status));
+ ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP);
+
+ ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
+ ATF_REQUIRE((pl.pl_flags & (PL_FLAG_EXEC | PL_FLAG_SCX)) ==
+ (PL_FLAG_EXEC | PL_FLAG_SCX));
+ ATF_REQUIRE(pl.pl_lwpid == lwps[1]);
+
+ ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+
+ /* The last event should be for the child process's exit. */
+ wpid = waitpid(fpid, &status, 0);
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE(WEXITSTATUS(status) == 0);
+
+ wpid = wait(&status);
+ ATF_REQUIRE(wpid == -1);
+ ATF_REQUIRE(errno == ECHILD);
+}
+
ATF_TP_ADD_TCS(tp)
{
@@ -1197,6 +1374,8 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TC(tp, ptrace__new_child_pl_syscall_code_fork);
ATF_TP_ADD_TC(tp, ptrace__new_child_pl_syscall_code_vfork);
ATF_TP_ADD_TC(tp, ptrace__new_child_pl_syscall_code_thread);
+ ATF_TP_ADD_TC(tp, ptrace__lwp_events);
+ ATF_TP_ADD_TC(tp, ptrace__lwp_events_exec);
return (atf_no_error());
}
diff --git a/tests/sys/kern/unix_passfd_test.c b/tests/sys/kern/unix_passfd_test.c
new file mode 100644
index 0000000..12568389
--- /dev/null
+++ b/tests/sys/kern/unix_passfd_test.c
@@ -0,0 +1,396 @@
+/*-
+ * Copyright (c) 2005 Robert N. M. Watson
+ * Copyright (c) 2015 Mark Johnston
+ * 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 AUTHOR 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 AUTHOR 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$
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/un.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+/*
+ * UNIX domain sockets allow file descriptors to be passed via "ancillary
+ * data", or control messages. This regression test is intended to exercise
+ * this facility, both performing some basic tests that it operates, and also
+ * causing some kernel edge cases to execute, such as garbage collection when
+ * there are cyclic file descriptor references. Right now we test only with
+ * stream sockets, but ideally we'd also test with datagram sockets.
+ */
+
+static void
+domainsocketpair(int *fdp)
+{
+
+ ATF_REQUIRE_MSG(socketpair(PF_UNIX, SOCK_STREAM, 0, fdp) != -1,
+ "socketpair(PF_UNIX, SOCK_STREAM) failed: %s", strerror(errno));
+}
+
+static void
+closesocketpair(int *fdp)
+{
+
+ close(fdp[0]);
+ close(fdp[1]);
+}
+
+static void
+devnull(int *fdp)
+{
+ int fd;
+
+ fd = open("/dev/null", O_RDONLY);
+ ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
+ *fdp = fd;
+}
+
+static void
+tempfile(int *fdp)
+{
+ char path[PATH_MAX];
+ int fd;
+
+ snprintf(path, PATH_MAX, "%s/unix_passfd.XXXXXXXXXXXXXXX",
+ getenv("TMPDIR") == NULL ? "/tmp" : getenv("TMPDIR"));
+ fd = mkstemp(path);
+ ATF_REQUIRE_MSG(fd != -1, "mkstemp(%s) failed", path);
+ (void)unlink(path);
+ *fdp = fd;
+}
+
+static void
+dofstat(int fd, struct stat *sb)
+{
+
+ ATF_REQUIRE_MSG(fstat(fd, sb) == 0,
+ "fstat failed: %s", strerror(errno));
+}
+
+static void
+samefile(struct stat *sb1, struct stat *sb2)
+{
+
+ ATF_REQUIRE_MSG(sb1->st_dev == sb2->st_dev, "different device");
+ ATF_REQUIRE_MSG(sb1->st_ino == sb2->st_ino, "different inode");
+}
+
+static void
+sendfd_payload(int sockfd, int send_fd, void *payload, size_t paylen)
+{
+ struct iovec iovec;
+ char message[CMSG_SPACE(sizeof(int))];
+ struct cmsghdr *cmsghdr;
+ struct msghdr msghdr;
+ ssize_t len;
+
+ bzero(&msghdr, sizeof(msghdr));
+ bzero(&message, sizeof(message));
+
+ msghdr.msg_control = message;
+ msghdr.msg_controllen = sizeof(message);
+
+ iovec.iov_base = payload;
+ iovec.iov_len = paylen;
+
+ msghdr.msg_iov = &iovec;
+ msghdr.msg_iovlen = 1;
+
+ cmsghdr = (struct cmsghdr *)(void*)message;
+ cmsghdr->cmsg_len = CMSG_LEN(sizeof(int));
+ cmsghdr->cmsg_level = SOL_SOCKET;
+ cmsghdr->cmsg_type = SCM_RIGHTS;
+ memcpy(CMSG_DATA(cmsghdr), &send_fd, sizeof(int));
+
+ len = sendmsg(sockfd, &msghdr, 0);
+ ATF_REQUIRE_MSG(len != -1, "sendmsg failed: %s", strerror(errno));
+ ATF_REQUIRE_MSG((size_t)len == paylen,
+ "sendmsg: %zd messages sent; expected: %zu; %s", len, paylen,
+ strerror(errno));
+}
+
+static void
+sendfd(int sockfd, int send_fd)
+{
+ char ch = 0;
+
+ return (sendfd_payload(sockfd, send_fd, &ch, sizeof(ch)));
+}
+
+static void
+recvfd_payload(int sockfd, int *recv_fd, void *buf, size_t buflen)
+{
+ struct cmsghdr *cmsghdr;
+ char message[CMSG_SPACE(SOCKCREDSIZE(CMGROUP_MAX)) + sizeof(int)];
+ struct msghdr msghdr;
+ struct iovec iovec;
+ ssize_t len;
+
+ bzero(&msghdr, sizeof(msghdr));
+
+ msghdr.msg_control = message;
+ msghdr.msg_controllen = sizeof(message);
+
+ iovec.iov_base = buf;
+ iovec.iov_len = buflen;
+
+ msghdr.msg_iov = &iovec;
+ msghdr.msg_iovlen = 1;
+
+ len = recvmsg(sockfd, &msghdr, 0);
+ ATF_REQUIRE_MSG(len != -1, "recvmsg failed: %s", strerror(errno));
+ ATF_REQUIRE_MSG((size_t)len == buflen,
+ "recvmsg: %zd bytes received; expected %zd", len, buflen);
+
+ cmsghdr = CMSG_FIRSTHDR(&msghdr);
+ ATF_REQUIRE_MSG(cmsghdr != NULL,
+ "recvmsg: did not receive control message");
+ *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(recv_fd, CMSG_DATA(cmsghdr), sizeof(int));
+ ATF_REQUIRE(*recv_fd != -1);
+ }
+ }
+ ATF_REQUIRE_MSG(*recv_fd != -1,
+ "recvmsg: did not receive single-fd message");
+}
+
+static void
+recvfd(int sockfd, int *recv_fd)
+{
+ char ch = 0;
+
+ return (recvfd_payload(sockfd, recv_fd, &ch, sizeof(ch)));
+}
+
+/*
+ * Put a temporary file into a UNIX domain socket, then take it out and make
+ * sure it's the same file. First time around, don't close the reference
+ * after sending.
+ */
+ATF_TC_WITHOUT_HEAD(simple_send_fd);
+ATF_TC_BODY(simple_send_fd, tc)
+{
+ struct stat getfd_stat, putfd_stat;
+ int fd[2], getfd, putfd;
+
+ domainsocketpair(fd);
+ tempfile(&putfd);
+ dofstat(putfd, &putfd_stat);
+ sendfd(fd[0], putfd);
+ recvfd(fd[1], &getfd);
+ dofstat(getfd, &getfd_stat);
+ samefile(&putfd_stat, &getfd_stat);
+ close(putfd);
+ close(getfd);
+ closesocketpair(fd);
+}
+
+/*
+ * Same as simple_send_fd, only close the file reference after sending, so that
+ * the only reference is the descriptor in the UNIX domain socket buffer.
+ */
+ATF_TC_WITHOUT_HEAD(send_and_close);
+ATF_TC_BODY(send_and_close, tc)
+{
+ struct stat getfd_stat, putfd_stat;
+ int fd[2], getfd, putfd;
+
+ domainsocketpair(fd);
+ tempfile(&putfd);
+ dofstat(putfd, &putfd_stat);
+ sendfd(fd[0], putfd);
+ close(putfd);
+ recvfd(fd[1], &getfd);
+ dofstat(getfd, &getfd_stat);
+ samefile(&putfd_stat, &getfd_stat);
+ close(getfd);
+ closesocketpair(fd);
+}
+
+/*
+ * Put a temporary file into a UNIX domain socket, then close both endpoints
+ * causing garbage collection to kick off.
+ */
+ATF_TC_WITHOUT_HEAD(send_and_cancel);
+ATF_TC_BODY(send_and_cancel, tc)
+{
+ int fd[2], putfd;
+
+ domainsocketpair(fd);
+ tempfile(&putfd);
+ sendfd(fd[0], putfd);
+ close(putfd);
+ closesocketpair(fd);
+}
+
+/*
+ * Send two files. Then receive them. Make sure they are returned in the
+ * right order, and both get there.
+ */
+ATF_TC_WITHOUT_HEAD(two_files);
+ATF_TC_BODY(two_files, tc)
+{
+ struct stat getfd_1_stat, getfd_2_stat, putfd_1_stat, putfd_2_stat;
+ int fd[2], getfd_1, getfd_2, putfd_1, putfd_2;
+
+ domainsocketpair(fd);
+ tempfile(&putfd_1);
+ tempfile(&putfd_2);
+ dofstat(putfd_1, &putfd_1_stat);
+ dofstat(putfd_2, &putfd_2_stat);
+ sendfd(fd[0], putfd_1);
+ sendfd(fd[0], putfd_2);
+ close(putfd_1);
+ close(putfd_2);
+ recvfd(fd[1], &getfd_1);
+ recvfd(fd[1], &getfd_2);
+ dofstat(getfd_1, &getfd_1_stat);
+ dofstat(getfd_2, &getfd_2_stat);
+ samefile(&putfd_1_stat, &getfd_1_stat);
+ samefile(&putfd_2_stat, &getfd_2_stat);
+ close(getfd_1);
+ close(getfd_2);
+ closesocketpair(fd);
+}
+
+/*
+ * Big bundling test. Send an endpoint of the UNIX domain socket over itself,
+ * closing the door behind it.
+ */
+ATF_TC_WITHOUT_HEAD(bundle);
+ATF_TC_BODY(bundle, tc)
+{
+ int fd[2], getfd;
+
+ domainsocketpair(fd);
+
+ sendfd(fd[0], fd[0]);
+ close(fd[0]);
+ recvfd(fd[1], &getfd);
+ close(getfd);
+ close(fd[1]);
+}
+
+/*
+ * Big bundling test part two: Send an endpoint of the UNIX domain socket over
+ * itself, close the door behind it, and never remove it from the other end.
+ */
+ATF_TC_WITHOUT_HEAD(bundle_cancel);
+ATF_TC_BODY(bundle_cancel, tc)
+{
+ int fd[2];
+
+ domainsocketpair(fd);
+ sendfd(fd[0], fd[0]);
+ sendfd(fd[1], fd[0]);
+ closesocketpair(fd);
+}
+
+/*
+ * Test for PR 151758: Send an character device over the UNIX domain socket
+ * and then close both sockets to orphan the device.
+ */
+ATF_TC_WITHOUT_HEAD(devfs_orphan);
+ATF_TC_BODY(devfs_orphan, tc)
+{
+ int fd[2], putfd;
+
+ domainsocketpair(fd);
+ devnull(&putfd);
+ sendfd(fd[0], putfd);
+ close(putfd);
+ closesocketpair(fd);
+}
+
+#define LOCAL_SENDSPACE_SYSCTL "net.local.stream.sendspace"
+
+/*
+ * Test for PR 181741. Receiver sets LOCAL_CREDS, and kernel prepends a
+ * control message to the data. Sender sends large payload.
+ * Payload + SCM_RIGHTS + LOCAL_CREDS hit socket buffer limit, and receiver
+ * receives truncated data.
+ */
+ATF_TC_WITHOUT_HEAD(rights_creds_payload);
+ATF_TC_BODY(rights_creds_payload, tc)
+{
+ const int on = 1;
+ u_long sendspace;
+ size_t len;
+ void *buf;
+ int fd[2], getfd, putfd, rc;
+
+ atf_tc_expect_fail("PR 181741: Packet loss when 'control' messages "
+ "are present with large data");
+
+ len = sizeof(sendspace);
+ rc = sysctlbyname(LOCAL_SENDSPACE_SYSCTL, &sendspace,
+ &len, NULL, 0);
+ ATF_REQUIRE_MSG(rc != -1,
+ "sysctl %s failed: %s", LOCAL_SENDSPACE_SYSCTL, strerror(errno));
+
+ buf = calloc(1, sendspace);
+ ATF_REQUIRE(buf != NULL);
+
+ domainsocketpair(fd);
+ rc = setsockopt(fd[1], 0, LOCAL_CREDS, &on, sizeof(on));
+ ATF_REQUIRE_MSG(rc != -1, "setsockopt(LOCAL_CREDS) failed: %s",
+ strerror(errno));
+ tempfile(&putfd);
+ sendfd_payload(fd[0], putfd, buf, sendspace);
+ recvfd_payload(fd[1], &getfd, buf, sendspace);
+ close(putfd);
+ close(getfd);
+ closesocketpair(fd);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, simple_send_fd);
+ ATF_TP_ADD_TC(tp, send_and_close);
+ ATF_TP_ADD_TC(tp, send_and_cancel);
+ ATF_TP_ADD_TC(tp, two_files);
+ ATF_TP_ADD_TC(tp, bundle);
+ ATF_TP_ADD_TC(tp, bundle_cancel);
+ ATF_TP_ADD_TC(tp, devfs_orphan);
+ ATF_TP_ADD_TC(tp, rights_creds_payload);
+
+ return (atf_no_error());
+}
diff --git a/tools/regression/sockets/unix_passfd/Makefile b/tools/regression/sockets/unix_passfd/Makefile
deleted file mode 100644
index 600b7b1..0000000
--- a/tools/regression/sockets/unix_passfd/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-# $FreeBSD$
-
-PROG= unix_passfd
-MAN=
-WARNS?= 3
-
-.include <bsd.prog.mk>
diff --git a/tools/regression/sockets/unix_passfd/unix_passfd.c b/tools/regression/sockets/unix_passfd/unix_passfd.c
deleted file mode 100644
index 59c4c29..0000000
--- a/tools/regression/sockets/unix_passfd/unix_passfd.c
+++ /dev/null
@@ -1,390 +0,0 @@
-/*-
- * Copyright (c) 2005 Robert N. M. Watson
- * Copyright (c) 2015 Mark Johnston
- * 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 AUTHOR 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 AUTHOR 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$
- */
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/sysctl.h>
-#include <sys/un.h>
-
-#include <err.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-/*
- * UNIX domain sockets allow file descriptors to be passed via "ancillary
- * data", or control messages. This regression test is intended to exercise
- * this facility, both performing some basic tests that it operates, and also
- * causing some kernel edge cases to execute, such as garbage collection when
- * there are cyclic file descriptor references. Right now we test only with
- * stream sockets, but ideally we'd also test with datagram sockets.
- */
-
-static void
-domainsocketpair(const char *test, int *fdp)
-{
-
- if (socketpair(PF_UNIX, SOCK_STREAM, 0, fdp) < 0)
- err(-1, "%s: socketpair(PF_UNIX, SOCK_STREAM)", test);
-}
-
-static void
-closesocketpair(int *fdp)
-{
-
- close(fdp[0]);
- close(fdp[1]);
-}
-
-static void
-devnull(const char *test, int *fdp)
-{
- int fd;
-
- fd = open("/dev/null", O_RDONLY);
- if (fd < 0)
- err(-1, "%s: open(/dev/null)", test);
- *fdp = fd;
-}
-
-static void
-tempfile(const char *test, int *fdp)
-{
- char path[PATH_MAX];
- int fd;
-
- snprintf(path, PATH_MAX, "/tmp/unix_passfd.XXXXXXXXXXXXXXX");
- fd = mkstemp(path);
- if (fd < 0)
- err(-1, "%s: mkstemp(%s)", test, path);
- (void)unlink(path);
- *fdp = fd;
-}
-
-static void
-dofstat(const char *test, int fd, struct stat *sb)
-{
-
- if (fstat(fd, sb) < 0)
- err(-1, "%s: fstat", test);
-}
-
-static void
-samefile(const char *test, struct stat *sb1, struct stat *sb2)
-{
-
- if (sb1->st_dev != sb2->st_dev)
- errx(-1, "%s: samefile: different device", test);
- if (sb1->st_ino != sb2->st_ino)
- errx(-1, "%s: samefile: different inode", test);
-}
-
-static void
-sendfd_payload(const char *test, int sockfd, int sendfd,
- void *payload, size_t paylen)
-{
- struct iovec iovec;
- char message[CMSG_SPACE(sizeof(int))];
- struct cmsghdr *cmsghdr;
- struct msghdr msghdr;
- ssize_t len;
-
- bzero(&msghdr, sizeof(msghdr));
- bzero(&message, sizeof(message));
-
- msghdr.msg_control = message;
- msghdr.msg_controllen = sizeof(message);
-
- iovec.iov_base = payload;
- iovec.iov_len = paylen;
-
- msghdr.msg_iov = &iovec;
- msghdr.msg_iovlen = 1;
-
- cmsghdr = (struct cmsghdr *)message;
- cmsghdr->cmsg_len = CMSG_LEN(sizeof(int));
- cmsghdr->cmsg_level = SOL_SOCKET;
- cmsghdr->cmsg_type = SCM_RIGHTS;
- *(int *)CMSG_DATA(cmsghdr) = sendfd;
-
- len = sendmsg(sockfd, &msghdr, 0);
- if (len < 0)
- err(-1, "%s: sendmsg", test);
- if ((size_t)len != paylen)
- errx(-1, "%s: sendmsg: %zd bytes sent", test, len);
-}
-
-static void
-sendfd(const char *test, int sockfd, int sendfd)
-{
- char ch = 0;
-
- return (sendfd_payload(test, sockfd, sendfd, &ch, sizeof(ch)));
-}
-
-static void
-recvfd_payload(const char *test, int sockfd, int *recvfd,
- void *buf, size_t buflen)
-{
- struct cmsghdr *cmsghdr;
- char message[CMSG_SPACE(SOCKCREDSIZE(CMGROUP_MAX)) + sizeof(int)];
- struct msghdr msghdr;
- struct iovec iovec;
- ssize_t len;
-
- bzero(&msghdr, sizeof(msghdr));
-
- msghdr.msg_control = message;
- msghdr.msg_controllen = sizeof(message);
-
- iovec.iov_base = buf;
- iovec.iov_len = buflen;
-
- msghdr.msg_iov = &iovec;
- msghdr.msg_iovlen = 1;
-
- len = recvmsg(sockfd, &msghdr, 0);
- if (len < 0)
- err(-1, "%s: recvmsg", test);
- if ((size_t)len != buflen)
- errx(-1, "%s: recvmsg: %zd bytes received", test, len);
-
- cmsghdr = CMSG_FIRSTHDR(&msghdr);
- if (cmsghdr == NULL)
- errx(-1, "%s: recvmsg: did not receive control message", test);
- *recvfd = -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))) {
- *recvfd = *(int *)CMSG_DATA(cmsghdr);
- if (*recvfd == -1)
- errx(-1, "%s: recvmsg: received fd -1", test);
- }
- }
- if (*recvfd == -1)
- errx(-1, "%s: recvmsg: did not receive single-fd message",
- test);
-}
-
-static void
-recvfd(const char *test, int sockfd, int *recvfd)
-{
- char ch = 0;
-
- return (recvfd_payload(test, sockfd, recvfd, &ch, sizeof(ch)));
-}
-
-int
-main(void)
-{
- struct stat putfd_1_stat, putfd_2_stat, getfd_1_stat, getfd_2_stat;
- int fd[2], putfd_1, putfd_2, getfd_1, getfd_2;
- const char *test;
-
- /*
- * First test: put a temporary file into a UNIX domain socket, then
- * take it out and make sure it's the same file. First time around,
- * don't close the reference after sending.
- */
- test = "test1-simplesendfd";
- printf("beginning %s\n", test);
-
- domainsocketpair(test, fd);
- tempfile(test, &putfd_1);
- dofstat(test, putfd_1, &putfd_1_stat);
- sendfd(test, fd[0], putfd_1);
- recvfd(test, fd[1], &getfd_1);
- dofstat(test, getfd_1, &getfd_1_stat);
- samefile(test, &putfd_1_stat, &getfd_1_stat);
- close(putfd_1);
- close(getfd_1);
- closesocketpair(fd);
-
- printf("%s passed\n", test);
-
- /*
- * Second test: same as first, only close the file reference after
- * sending, so that the only reference is the descriptor in the UNIX
- * domain socket buffer.
- */
- test = "test2-sendandclose";
- printf("beginning %s\n", test);
-
- domainsocketpair(test, fd);
- tempfile(test, &putfd_1);
- dofstat(test, putfd_1, &putfd_1_stat);
- sendfd(test, fd[0], putfd_1);
- close(putfd_1);
- recvfd(test, fd[1], &getfd_1);
- dofstat(test, getfd_1, &getfd_1_stat);
- samefile(test, &putfd_1_stat, &getfd_1_stat);
- close(getfd_1);
- closesocketpair(fd);
-
- printf("%s passed\n", test);
-
- /*
- * Third test: put a temporary file into a UNIX domain socket, then
- * close both endpoints causing garbage collection to kick off.
- */
- test = "test3-sendandcancel";
- printf("beginning %s\n", test);
-
- domainsocketpair(test, fd);
- tempfile(test, &putfd_1);
- sendfd(test, fd[0], putfd_1);
- close(putfd_1);
- closesocketpair(fd);
-
- printf("%s passed\n", test);
-
- /*
- * Send two files. Then receive them. Make sure they are returned
- * in the right order, and both get there.
- */
-
- test = "test4-twofile";
- printf("beginning %s\n", test);
-
- domainsocketpair(test, fd);
- tempfile(test, &putfd_1);
- tempfile(test, &putfd_2);
- dofstat(test, putfd_1, &putfd_1_stat);
- dofstat(test, putfd_2, &putfd_2_stat);
- sendfd(test, fd[0], putfd_1);
- sendfd(test, fd[0], putfd_2);
- close(putfd_1);
- close(putfd_2);
- recvfd(test, fd[1], &getfd_1);
- recvfd(test, fd[1], &getfd_2);
- dofstat(test, getfd_1, &getfd_1_stat);
- dofstat(test, getfd_2, &getfd_2_stat);
- samefile(test, &putfd_1_stat, &getfd_1_stat);
- samefile(test, &putfd_2_stat, &getfd_2_stat);
- close(getfd_1);
- close(getfd_2);
- closesocketpair(fd);
-
- printf("%s passed\n", test);
-
- /*
- * Big bundling test. Send an endpoint of the UNIX domain socket
- * over itself, closing the door behind it.
- */
-
- test = "test5-bundle";
- printf("beginning %s\n", test);
-
- domainsocketpair(test, fd);
-
- sendfd(test, fd[0], fd[0]);
- close(fd[0]);
- recvfd(test, fd[1], &getfd_1);
- close(getfd_1);
- close(fd[1]);
-
- printf("%s passed\n", test);
-
- /*
- * Big bundling test part two: Send an endpoint of the UNIX domain
- * socket over itself, close the door behind it, and never remove it
- * from the other end.
- */
-
- test = "test6-bundlecancel";
- printf("beginning %s\n", test);
-
- domainsocketpair(test, fd);
- sendfd(test, fd[0], fd[0]);
- sendfd(test, fd[1], fd[0]);
- closesocketpair(fd);
-
- printf("%s passed\n", test);
-
- /*
- * Test for PR 151758: Send an character device over the UNIX
- * domain socket and then close both sockets to orphan the
- * device.
- */
-
- test = "test7-devfsorphan";
- printf("beginning %s\n", test);
-
- domainsocketpair(test, fd);
- devnull(test, &putfd_1);
- sendfd(test, fd[0], putfd_1);
- close(putfd_1);
- closesocketpair(fd);
-
- printf("%s passed\n", test);
-
- /*
- * Test for PR 181741. Receiver sets LOCAL_CREDS, and kernel
- * prepends a control message to the data. Sender sends large
- * payload. Payload + SCM_RIGHTS + LOCAL_CREDS hit socket buffer
- * limit, and receiver receives truncated data.
- */
- test = "test8-rights+creds+payload";
- printf("beginning %s\n", test);
-
- {
- const int on = 1;
- u_long sendspace;
- size_t len;
- void *buf;
-
- len = sizeof(sendspace);
- if (sysctlbyname("net.local.stream.sendspace", &sendspace,
- &len, NULL, 0) < 0)
- err(-1, "%s: sysctlbyname(net.local.stream.sendspace)",
- test);
-
- if ((buf = calloc(1, sendspace)) == NULL)
- err(-1, "%s: calloc", test);
-
- domainsocketpair(test, fd);
- if (setsockopt(fd[1], 0, LOCAL_CREDS, &on, sizeof(on)) < 0)
- err(-1, "%s: setsockopt(LOCAL_CREDS)", test);
- tempfile(test, &putfd_1);
- sendfd_payload(test, fd[0], putfd_1, buf, sendspace);
- recvfd_payload(test, fd[1], &getfd_1, buf, sendspace);
- close(putfd_1);
- close(getfd_1);
- closesocketpair(fd);
- }
-
- printf("%s passed\n", test);
-
- return (0);
-}
diff --git a/usr.bin/clang/clang/CC.sh b/usr.bin/clang/clang/CC.sh
new file mode 100755
index 0000000..45faeec
--- /dev/null
+++ b/usr.bin/clang/clang/CC.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+# $FreeBSD$
+# This file is in the public domain.
+exec /usr/bin/c++ "$@"
diff --git a/usr.bin/clang/clang/Makefile b/usr.bin/clang/clang/Makefile
index 18ee730..1489a5e 100644
--- a/usr.bin/clang/clang/Makefile
+++ b/usr.bin/clang/clang/Makefile
@@ -18,9 +18,11 @@ LINKS= ${BINDIR}/clang ${BINDIR}/clang++ \
MLINKS= clang.1 clang++.1 \
clang.1 clang-cpp.1
.if ${MK_CLANG_IS_CC} != "no"
+SCRIPTS=CC.sh
+SCRIPTSNAME=CC
+
LINKS+= ${BINDIR}/clang ${BINDIR}/cc \
${BINDIR}/clang ${BINDIR}/c++ \
- ${BINDIR}/clang ${BINDIR}/CC \
${BINDIR}/clang ${BINDIR}/cpp
MLINKS+= clang.1 cc.1 \
clang.1 c++.1 \
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;
}
diff --git a/usr.sbin/makefs/makefs.c b/usr.sbin/makefs/makefs.c
index 79cffed..a7ca751 100644
--- a/usr.sbin/makefs/makefs.c
+++ b/usr.sbin/makefs/makefs.c
@@ -116,7 +116,7 @@ main(int argc, char *argv[])
start_time.tv_sec = start.tv_sec;
start_time.tv_nsec = start.tv_usec * 1000;
- while ((ch = getopt(argc, argv, "B:b:Dd:f:F:M:m:N:o:pr:s:S:t:xZ")) != -1) {
+ while ((ch = getopt(argc, argv, "B:b:Dd:f:F:M:m:N:o:pR:s:S:t:xZ")) != -1) {
switch (ch) {
case 'B':
OpenPOWER on IntegriCloud