From 88310b4011d39bc96fa1aceaf360cc0a7c42ff58 Mon Sep 17 00:00:00 2001 From: "Bjoern A. Zeeb" Date: Wed, 30 Dec 2015 17:10:03 +0000 Subject: [PATCH 01/37] This code is not in modules that need KPI stability so no need to use the wrapper functions as used in r252511. We can directly use the locking macros. Reviewed by: jtl, rwatson MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D4731 --- sys/netinet6/in6.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c index 0f8fb67a143f..aa770199bd8e 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); } From 5f0a5fefc661aea4aba7c21ba3d6a840fcd666a9 Mon Sep 17 00:00:00 2001 From: Andrew Turner Date: Wed, 30 Dec 2015 17:36:34 +0000 Subject: [PATCH 02/37] Decode and print the ID_AA64* registers on boot. These registers hold information on what the core supports. In most cases these will be identical across most CPUs in the SoC, however there may be the case where, with a big.LITTLE setup they may differ. In this case we print the decoded data on all CPUs. Reviewed by: kib Sponsored by: ABT Systems Ltd Differential Revision: https://reviews.freebsd.org/D4725 --- sys/arm64/arm64/identcpu.c | 505 +++++++++++++++++++++++++++++++++-- sys/arm64/arm64/mp_machdep.c | 10 +- sys/arm64/include/armreg.h | 152 ++++++++++- sys/arm64/include/cpu.h | 1 + 4 files changed, 639 insertions(+), 29 deletions(-) diff --git a/sys/arm64/arm64/identcpu.c b/sys/arm64/arm64/identcpu.c index fb5092291d59..72e2021e6dc1 100644 --- a/sys/arm64/arm64/identcpu.c +++ b/sys/arm64/arm64/identcpu.c @@ -37,9 +37,12 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include +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; + cpu_desc[cpu].mpidr = get_mpidr(); + CPU_AFFINITY(cpu) = cpu_desc[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].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 (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"); } - - if (bootverbose) - printf("CPU%u affinity: %u.%u.%u.%u\n", 0, CPU_AFF0(mpidr), - CPU_AFF1(mpidr), CPU_AFF2(mpidr), CPU_AFF3(mpidr)); } diff --git a/sys/arm64/arm64/mp_machdep.c b/sys/arm64/arm64/mp_machdep.c index 73adb760e05d..19cee7788c3f 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 de8ce40c5f26..f8d19960139e 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 14bffbc1f536..8f14e8238967 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)] From 8d03d93fb7d6828804a37895a7eb14668d5b73a7 Mon Sep 17 00:00:00 2001 From: "Jonathan T. Looney" Date: Wed, 30 Dec 2015 18:04:50 +0000 Subject: [PATCH 03/37] Fix a file descriptor leak in mdXhl.c (which is used by numerous hashing algorithms. CID: 1305669,1305611,1305663,1305603,1305584,1305639,1346865,1305601 Differential Revision: https://reviews.freebsd.org/D4732 Reviewed by: allanjude, delphij MFC after: 2 weeks Sponsored by: Juniper Networks --- lib/libmd/mdXhl.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/libmd/mdXhl.c b/lib/libmd/mdXhl.c index f2e918f548d9..378d8adfafc0 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; From 912568c8819861592b05d2e5a6f65649c1b1c54b Mon Sep 17 00:00:00 2001 From: "Jonathan T. Looney" Date: Wed, 30 Dec 2015 18:08:05 +0000 Subject: [PATCH 04/37] Add the appropriate case statement for IPV6_BINDMULTI so the option can be retrieved with getsockopt(). CID: 1229928 Differential Revision: https://reviews.freebsd.org/D4737 Reviewed by: adrian Sponsored by: Juniper Networks --- sys/netinet6/ip6_output.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c index 778f39dab438..af9fdbafe195 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: From 67fe84f1639155ce03b788c63edc69e4f778d3dd Mon Sep 17 00:00:00 2001 From: Enji Cooper Date: Wed, 30 Dec 2015 18:13:43 +0000 Subject: [PATCH 05/37] Rename `recvfd` and `sendfd` variables in recvfd/sendfd functions to avoid -Wshadow issues with gcc MFC after: 1 week Reported by: bz, jenkins Sponsored by: EMC / Isilon Storage Division --- tests/sys/kern/unix_passfd_test.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/sys/kern/unix_passfd_test.c b/tests/sys/kern/unix_passfd_test.c index 44f136fc1fea..12568389bc3d 100644 --- a/tests/sys/kern/unix_passfd_test.c +++ b/tests/sys/kern/unix_passfd_test.c @@ -109,7 +109,7 @@ samefile(struct stat *sb1, struct stat *sb2) } static void -sendfd_payload(int sockfd, int sendfd, void *payload, size_t paylen) +sendfd_payload(int sockfd, int send_fd, void *payload, size_t paylen) { struct iovec iovec; char message[CMSG_SPACE(sizeof(int))]; @@ -133,7 +133,7 @@ sendfd_payload(int sockfd, int sendfd, void *payload, size_t paylen) cmsghdr->cmsg_len = CMSG_LEN(sizeof(int)); cmsghdr->cmsg_level = SOL_SOCKET; cmsghdr->cmsg_type = SCM_RIGHTS; - memcpy(CMSG_DATA(cmsghdr), &sendfd, sizeof(int)); + memcpy(CMSG_DATA(cmsghdr), &send_fd, sizeof(int)); len = sendmsg(sockfd, &msghdr, 0); ATF_REQUIRE_MSG(len != -1, "sendmsg failed: %s", strerror(errno)); @@ -143,15 +143,15 @@ sendfd_payload(int sockfd, int sendfd, void *payload, size_t paylen) } static void -sendfd(int sockfd, int sendfd) +sendfd(int sockfd, int send_fd) { char ch = 0; - return (sendfd_payload(sockfd, sendfd, &ch, sizeof(ch))); + return (sendfd_payload(sockfd, send_fd, &ch, sizeof(ch))); } static void -recvfd_payload(int sockfd, int *recvfd, void *buf, size_t buflen) +recvfd_payload(int sockfd, int *recv_fd, void *buf, size_t buflen) { struct cmsghdr *cmsghdr; char message[CMSG_SPACE(SOCKCREDSIZE(CMGROUP_MAX)) + sizeof(int)]; @@ -178,25 +178,25 @@ recvfd_payload(int sockfd, int *recvfd, void *buf, size_t buflen) cmsghdr = CMSG_FIRSTHDR(&msghdr); ATF_REQUIRE_MSG(cmsghdr != NULL, "recvmsg: did not receive control message"); - *recvfd = -1; + *recv_fd = -1; for (; cmsghdr != NULL; cmsghdr = CMSG_NXTHDR(&msghdr, cmsghdr)) { if (cmsghdr->cmsg_level == SOL_SOCKET && cmsghdr->cmsg_type == SCM_RIGHTS && cmsghdr->cmsg_len == CMSG_LEN(sizeof(int))) { - memcpy(recvfd, CMSG_DATA(cmsghdr), sizeof(int)); - ATF_REQUIRE(*recvfd != -1); + memcpy(recv_fd, CMSG_DATA(cmsghdr), sizeof(int)); + ATF_REQUIRE(*recv_fd != -1); } } - ATF_REQUIRE_MSG(*recvfd != -1, + ATF_REQUIRE_MSG(*recv_fd != -1, "recvmsg: did not receive single-fd message"); } static void -recvfd(int sockfd, int *recvfd) +recvfd(int sockfd, int *recv_fd) { char ch = 0; - return (recvfd_payload(sockfd, recvfd, &ch, sizeof(ch))); + return (recvfd_payload(sockfd, recv_fd, &ch, sizeof(ch))); } /* From 258527a37292f361968907ea27fca0b59d6eef7e Mon Sep 17 00:00:00 2001 From: Marius Strobl Date: Wed, 30 Dec 2015 18:57:29 +0000 Subject: [PATCH 06/37] Change the - hopefully - last piece of ktr(9) to use PCPU_GET(cpuid) instead of the MD module ID for KTR_CPU. --- sys/sparc64/include/ktr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/sparc64/include/ktr.h b/sys/sparc64/include/ktr.h index b129dd895c62..f8c1b43e9cd0 100644 --- a/sys/sparc64/include/ktr.h +++ b/sys/sparc64/include/ktr.h @@ -59,7 +59,7 @@ l2: add r2, 1, r3 ; \ add r1, r2, r1 ; \ rd %tick, r2 ; \ stx r2, [r1 + KTR_TIMESTAMP] ; \ - lduw [PCPU(MID)], r2 ; \ + lduw [PCPU(CPUID)], r2 ; \ stw r2, [r1 + KTR_CPU] ; \ stw %g0, [r1 + KTR_LINE] ; \ stx %g0, [r1 + KTR_FILE] ; \ From 6f73b583d9e19e9c24751c5f7bbb64065037e938 Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Wed, 30 Dec 2015 19:49:22 +0000 Subject: [PATCH 07/37] Force nullfs vnode reclaim after unlinking, to potentially unlink lower vnode. Otherwise, reference to the lower vnode from the upper one prevents final unlink. PR: 178238 Tested by: pho Sponsored by: The FreeBSD Foundation MFC after: 1 week --- sys/fs/nullfs/null_vnops.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sys/fs/nullfs/null_vnops.c b/sys/fs/nullfs/null_vnops.c index 4762a3c8679e..72b884f65cac 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); From 2155bb238f8245c92772441f964d0e23247bb464 Mon Sep 17 00:00:00 2001 From: Allan Jude Date: Wed, 30 Dec 2015 22:43:07 +0000 Subject: [PATCH 08/37] Break up opencrypto/xform.c so it can be reused piecemeal Keep xform.c as a meta-file including the broken out bits existing code that includes xform.c continues to work as normal Individual algorithms can now be reused elsewhere, including outside of the kernel Reviewed by: bapt (previous version), gnn, delphij Approved by: secteam MFC after: 1 week Sponsored by: ScaleEngine Inc. Differential Revision: https://reviews.freebsd.org/D4674 --- sys/crypto/sha1.h | 2 +- sys/opencrypto/skipjack.h | 5 + sys/opencrypto/xform.c | 914 +------------------------------- sys/opencrypto/xform.h | 80 +-- sys/opencrypto/xform_aes_icm.c | 152 ++++++ sys/opencrypto/xform_aes_xts.c | 164 ++++++ sys/opencrypto/xform_auth.h | 89 ++++ sys/opencrypto/xform_blf.c | 127 +++++ sys/opencrypto/xform_cast5.c | 107 ++++ sys/opencrypto/xform_cml.c | 113 ++++ sys/opencrypto/xform_comp.h | 52 ++ sys/opencrypto/xform_deflate.c | 86 +++ sys/opencrypto/xform_des1.c | 116 ++++ sys/opencrypto/xform_des3.c | 119 +++++ sys/opencrypto/xform_enc.h | 92 ++++ sys/opencrypto/xform_gmac.c | 99 ++++ sys/opencrypto/xform_md5.c | 81 +++ sys/opencrypto/xform_null.c | 136 +++++ sys/opencrypto/xform_rijndael.c | 113 ++++ sys/opencrypto/xform_rmd160.c | 75 +++ sys/opencrypto/xform_sha1.c | 93 ++++ sys/opencrypto/xform_sha2.c | 109 ++++ sys/opencrypto/xform_skipjack.c | 117 ++++ sys/opencrypto/xform_userland.h | 48 ++ 24 files changed, 2118 insertions(+), 971 deletions(-) create mode 100644 sys/opencrypto/xform_aes_icm.c create mode 100644 sys/opencrypto/xform_aes_xts.c create mode 100644 sys/opencrypto/xform_auth.h create mode 100644 sys/opencrypto/xform_blf.c create mode 100644 sys/opencrypto/xform_cast5.c create mode 100644 sys/opencrypto/xform_cml.c create mode 100644 sys/opencrypto/xform_comp.h create mode 100644 sys/opencrypto/xform_deflate.c create mode 100644 sys/opencrypto/xform_des1.c create mode 100644 sys/opencrypto/xform_des3.c create mode 100644 sys/opencrypto/xform_enc.h create mode 100644 sys/opencrypto/xform_gmac.c create mode 100644 sys/opencrypto/xform_md5.c create mode 100644 sys/opencrypto/xform_null.c create mode 100644 sys/opencrypto/xform_rijndael.c create mode 100644 sys/opencrypto/xform_rmd160.c create mode 100644 sys/opencrypto/xform_sha1.c create mode 100644 sys/opencrypto/xform_sha2.c create mode 100644 sys/opencrypto/xform_skipjack.c create mode 100644 sys/opencrypto/xform_userland.h diff --git a/sys/crypto/sha1.h b/sys/crypto/sha1.h index 3686d7ddde51..d32aa8a17842 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/opencrypto/skipjack.h b/sys/opencrypto/skipjack.h index 3e88418ce217..80367ea4177b 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 3dee3664e0a4..ee9f0b6484e3 100644 --- a/sys/opencrypto/xform.c +++ b/sys/opencrypto/xform.c @@ -75,196 +75,9 @@ __FBSDID("$FreeBSD$"); #include #include -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 -}; +/* 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" + +/* 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" + +/* Include the compression algorithms */ +#include "xform_deflate.c" -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; -} - -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 - */ - -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.h b/sys/opencrypto/xform.h index 185e20324b51..a176fe756c66 100644 --- a/sys/opencrypto/xform.h +++ b/sys/opencrypto/xform.h @@ -39,83 +39,9 @@ #include #include -/* 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 +#include +#include #ifdef _KERNEL #include diff --git a/sys/opencrypto/xform_aes_icm.c b/sys/opencrypto/xform_aes_icm.c new file mode 100644 index 000000000000..f4ce885172ef --- /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 +__FBSDID("$FreeBSD$"); + +#include + +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 000000000000..dedbe6275e10 --- /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 +__FBSDID("$FreeBSD$"); + +#include + +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 000000000000..c51f9400f87f --- /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 +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* 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 000000000000..b4be5f8d4636 --- /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 +__FBSDID("$FreeBSD$"); + +#include +#include + +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 000000000000..85b346eb2ca9 --- /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 +__FBSDID("$FreeBSD$"); + +#include +#include + +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 000000000000..c807fa97c98d --- /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 +__FBSDID("$FreeBSD$"); + +#include +#include + +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 000000000000..23e4eacf6e81 --- /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 +#include + +#include +#include +#include + +/* 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 000000000000..c8864bf6228f --- /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 +__FBSDID("$FreeBSD$"); + +#include +#include + +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 000000000000..cbce5e290b2b --- /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 +__FBSDID("$FreeBSD$"); + +#include +#include + +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 000000000000..1b26b622f6b4 --- /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 +__FBSDID("$FreeBSD$"); + +#include +#include + +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 000000000000..7bb6a9dd1a37 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 000000000000..156ed7f13443 --- /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 +__FBSDID("$FreeBSD$"); + +#include +#include + +/* 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 000000000000..3a8751d9c020 --- /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 +__FBSDID("$FreeBSD$"); + +#include +#include + +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 000000000000..74f410cba945 --- /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 +__FBSDID("$FreeBSD$"); + +#include +#include + +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 000000000000..2c974f3d62df --- /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 +__FBSDID("$FreeBSD$"); + +#include +#include + +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 000000000000..4bce0729fa0b --- /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 +__FBSDID("$FreeBSD$"); + +#include +#include + +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 000000000000..29a5916559c2 --- /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 +__FBSDID("$FreeBSD$"); + +#include +#include + +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 000000000000..389cb8dab981 --- /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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +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 000000000000..94090d0d9612 --- /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 +__FBSDID("$FreeBSD$"); + +#include +#include + +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 000000000000..04266dc8cd8e --- /dev/null +++ b/sys/opencrypto/xform_userland.h @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 2015 Allan Jude + * 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 +#define KMALLOC(size, type, flags) malloc(size, type, flags) +#define KFREE(ptr, type) free(ptr, type) +#else /* not _KERNEL */ +#ifdef _STAND +#include +#else /* !_STAND */ +#include +#include +#endif /* _STAND */ +#define KMALLOC(size, type, flags) malloc(size) +#define KFREE(ptr, type) free(ptr) +#endif /* _KERNEL */ + + +#endif /* _CRYPTO_XFORM_USERLAND_H_ */ From dfd3a89ff0eb5dfdac4d64700353bfcaa35baba3 Mon Sep 17 00:00:00 2001 From: Ian Lepore Date: Wed, 30 Dec 2015 23:04:08 +0000 Subject: [PATCH 09/37] Add the MOVT/MOVW types to the list of relocs which do not generate .plt entries. This fixes the segfaults in arm userland code compiled with -march= or -mcpu= values that allow the compiler to generate movw/movt sequences to load 32-bit constants. --- contrib/binutils/bfd/elf32-arm.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/contrib/binutils/bfd/elf32-arm.c b/contrib/binutils/bfd/elf32-arm.c index 753cdcc1783e..e20ccca85162 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. */ From e80e04aeb7c096d5c31175cba17b0c4ca15572fd Mon Sep 17 00:00:00 2001 From: Allan Jude Date: Wed, 30 Dec 2015 23:27:24 +0000 Subject: [PATCH 10/37] Bump __FreeBSD_version because r292782 removes sys/crypto/sha2.h Submitted by: Oliver Pinter --- sys/sys/param.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/sys/param.h b/sys/sys/param.h index 69eb391d2c50..3c9747aa4045 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, From f7e124adf559556e2c2642e7b2c1baa02bb2220d Mon Sep 17 00:00:00 2001 From: Marcelo Araujo Date: Thu, 31 Dec 2015 01:54:07 +0000 Subject: [PATCH 11/37] Clean up unused-but-set-variable spotted by gcc-4.9. Reviewed by: royger Approved by: rodrigc (mentor) Differential Revision: https://reviews.freebsd.org/D4733 --- sys/xen/xenbus/xenbusb.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sys/xen/xenbus/xenbusb.c b/sys/xen/xenbus/xenbusb.c index 4853b3a211a1..03525484793d 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; From d74fdc6a35271ee995de983b193d737950b89b82 Mon Sep 17 00:00:00 2001 From: Marcelo Araujo Date: Thu, 31 Dec 2015 01:55:51 +0000 Subject: [PATCH 12/37] Clean up unused-but-set-variable spotted by gcc-4.9. Reviewed by: grehan Approved by: bapt (mentor) Differential Revision: https://reviews.freebsd.org/D4735 --- usr.sbin/bhyve/pci_emul.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/usr.sbin/bhyve/pci_emul.c b/usr.sbin/bhyve/pci_emul.c index af427effdfdd..c6763c93c018 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; From 09df572391c107dcf26d2cbdd4008039e2c0430f Mon Sep 17 00:00:00 2001 From: Marcelo Araujo Date: Thu, 31 Dec 2015 01:57:55 +0000 Subject: [PATCH 13/37] Clean up unused-but-set-variable spotted by gcc-4.9. Approved by: bapt (mentor) Differential Revision: https://reviews.freebsd.org/D4736 --- usr.sbin/camdd/camdd.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/usr.sbin/camdd/camdd.c b/usr.sbin/camdd/camdd.c index 573214e5bc5b..9284eb5459d0 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; } From 2bfd3dfb9f0cc1dcee5689351ce86434f39c50f0 Mon Sep 17 00:00:00 2001 From: Marcelo Araujo Date: Thu, 31 Dec 2015 02:01:20 +0000 Subject: [PATCH 14/37] Wrap using #ifdef 'notyet' those variables and statements not yet implemented to lower the compiler warnings. It fix the case of unused-but-set-variable spotted by gcc4.9. Reviewed by: ngie, ae Approved by: bapt (mentor) Differential Revision: https://reviews.freebsd.org/D4720 --- sys/net/if_gre.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/sys/net/if_gre.c b/sys/net/if_gre.c index 24ed971135c2..9d4a9763ca7f 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)) { From 4fb3a8208cf96df2a43eca52a11cbe339419e3a9 Mon Sep 17 00:00:00 2001 From: "Alexander V. Chernikov" Date: Thu, 31 Dec 2015 05:03:27 +0000 Subject: [PATCH 15/37] Implement interface link header precomputation API. Add if_requestencap() interface method which is capable of calculating various link headers for given interface. Right now there is support for INET/INET6/ARP llheader calculation (IFENCAP_LL type request). Other types are planned to support more complex calculation (L2 multipath lagg nexthops, tunnel encap nexthops, etc..). Reshape 'struct route' to be able to pass additional data (with is length) to prepend to mbuf. These two changes permits routing code to pass pre-calculated nexthop data (like L2 header for route w/gateway) down to the stack eliminating the need for other lookups. It also brings us closer to more complex scenarios like transparently handling MPLS nexthops and tunnel interfaces. Last, but not least, it removes layering violation introduced by flowtable code (ro_lle) and simplifies handling of existing if_output consumers. ARP/ND changes: Make arp/ndp stack pre-calculate link header upon installing/updating lle record. Interface link address change are handled by re-calculating headers for all lles based on if_lladdr event. After these changes, arpresolve()/nd6_resolve() returns full pre-calculated header for supported interfaces thus simplifying if_output(). Move these lookups to separate ether_resolve_addr() function which ether returs error or fully-prepared link header. Add resolve_addr() compat versions to return link addresses instead of pre-calculated data. BPF changes: Raw bpf writes occupied _two_ cases: AF_UNSPEC and pseudo_AF_HDRCMPLT. Despite the naming, both of there have ther header "complete". The only difference is that interface source mac has to be filled by OS for AF_UNSPEC (controlled via BIOCGHDRCMPLT). This logic has to stay inside BPF and not pollute if_output() routines. Convert BPF to pass prepend data via new 'struct route' mechanism. Note that it does not change non-optimized if_output(): ro_prepend handling is purely optional. Side note: hackish pseudo_AF_HDRCMPLT is supported for ethernet and FDDI. It is not needed for ethernet anymore. The only remaining FDDI user is dev/pdq mostly untouched since 2007. FDDI support was eliminated from OpenBSD in 2013 (sys/net/if_fddisubr.c rev 1.65). Flowtable changes: Flowtable violates layering by saving (and not correctly managing) rtes/lles. Instead of passing lle pointer, pass pointer to pre-calculated header data from that lle. Differential Revision: https://reviews.freebsd.org/D4102 --- sys/dev/cxgb/ulp/tom/cxgb_l2t.c | 2 +- sys/dev/cxgbe/tom/t4_tom_l2t.c | 2 +- sys/net/bpf.c | 24 +- sys/net/flowtable.c | 10 +- sys/net/if.c | 41 +++ sys/net/if_ethersubr.c | 289 +++++++++++------- sys/net/if_llatbl.c | 102 ++++++- sys/net/if_llatbl.h | 20 +- sys/net/if_var.h | 44 +++ sys/net/route.h | 13 +- sys/netinet/if_ether.c | 178 ++++++++--- sys/netinet/if_ether.h | 2 + sys/netinet/in.c | 12 +- sys/netinet/ip_output.c | 2 +- sys/netinet/toecore.c | 2 +- sys/netinet6/icmp6.c | 2 +- sys/netinet6/in6.c | 10 +- sys/netinet6/in6.h | 6 +- sys/netinet6/nd6.c | 92 +++++- sys/netinet6/nd6.h | 2 + sys/netinet6/nd6_nbr.c | 22 +- .../drivers/infiniband/ulp/ipoib/ipoib_main.c | 8 +- 22 files changed, 672 insertions(+), 213 deletions(-) diff --git a/sys/dev/cxgb/ulp/tom/cxgb_l2t.c b/sys/dev/cxgb/ulp/tom/cxgb_l2t.c index 4352f33e6cd1..c2390ae2f93d 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 65f7d2389473..8aadf34a9b5e 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/net/bpf.c b/sys/net/bpf.c index 37edbe827537..661a1cfbd1fb 100644 --- a/sys/net/bpf.c +++ b/sys/net/bpf.c @@ -69,6 +69,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #ifdef BPF_JITTER @@ -76,6 +77,7 @@ __FBSDID("$FreeBSD$"); #endif #include #include +#include #include #include @@ -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 a16584356ee4..f45a6872a815 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 39656efa363d..b9e524cdad89 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); @@ -3397,6 +3401,43 @@ if_setlladdr(struct ifnet *ifp, const u_char *lladdr, int len) return (0); } +/* + * 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 diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index 71e28ea00166..5186406248d9 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) @@ -135,6 +136,138 @@ update_mbuf_csumflags(struct mbuf *src, struct mbuf *dst) dst->m_pkthdr.csum_data = 0xffff; } +/* + * 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. @@ -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_llatbl.c b/sys/net/if_llatbl.c index b0450b36000b..beef6b481adb 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 8a300c31ed16..b6111c65cc9f 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 5911cecb706b..54de56727f91 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 66f4d775bb84..743c830f54f9 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 4c0c586b6643..0bf5cecb8eec 100644 --- a/sys/netinet/if_ether.c +++ b/sys/netinet/if_ether.c @@ -281,6 +281,37 @@ arptimer(void *arg) CURVNET_RESTORE(); } +/* + * 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 @@ -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 @@ in_arpinput(struct mbuf *m) 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 @@ in_arpinput(struct mbuf *m) */ 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 @@ in_arpinput(struct mbuf *m) 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 @@ in_arpinput(struct mbuf *m) 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 1583ca560770..06ec210c07fb 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 7504c8ffdb93..c30c1f3fdf88 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 557458a320bd..7ad43a229dba 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -567,7 +567,7 @@ ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro, int flags, 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 ef82f8aa7aae..6ed8eb02d260 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 f0c5371d245d..a7bbac05ab03 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 aa770199bd8e..0d47d4b3707d 100644 --- a/sys/netinet6/in6.c +++ b/sys/netinet6/in6.c @@ -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 8f08c8f195fa..9bc142a0068c 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/nd6.c b/sys/netinet6/nd6.c index 7ca172cd449c..fbbf4214776b 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 8a0a56e1b7f0..6ff4cac2918d 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 bf43fb65d530..a5ce2ec83c84 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 1077b4050f39..e1f2dc082d33 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 From 25656def0d92e1a4f75d6cbdb51e3f457041a2c1 Mon Sep 17 00:00:00 2001 From: Marcelo Araujo Date: Thu, 31 Dec 2015 07:03:41 +0000 Subject: [PATCH 16/37] Clean up unused-but-set-variable spotted by gcc4.9. Reviewed by: ngie Approved by: rodrigc (mentor) Differential Revision: https://reviews.freebsd.org/D4719 --- sys/net/if_gif.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sys/net/if_gif.c b/sys/net/if_gif.c index 33d583c9686a..1607af9c8e65 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) { From 3ec1cff5297dc10403308bf74358fe6055fe61f5 Mon Sep 17 00:00:00 2001 From: Marcelo Araujo Date: Thu, 31 Dec 2015 07:08:21 +0000 Subject: [PATCH 17/37] Clean up unused-but-set-variable spotted by gcc-4.9. Reviewed by: grehan Approved by: rodrigc (mentor) Differential Revision: https://reviews.freebsd.org/D4734 --- usr.sbin/bhyve/bhyverun.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/usr.sbin/bhyve/bhyverun.c b/usr.sbin/bhyve/bhyverun.c index 4fd9c358f82a..cb29a484800b 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; @@ -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: From cc398e21511f78d3436a3ab31dcec8ab4fa37708 Mon Sep 17 00:00:00 2001 From: "Bjoern A. Zeeb" Date: Thu, 31 Dec 2015 10:55:50 +0000 Subject: [PATCH 18/37] Remove unused variable after r292981 to unbreak the build. --- usr.sbin/bhyve/bhyverun.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usr.sbin/bhyve/bhyverun.c b/usr.sbin/bhyve/bhyverun.c index cb29a484800b..bfa135b16cce 100644 --- a/usr.sbin/bhyve/bhyverun.c +++ b/usr.sbin/bhyve/bhyverun.c @@ -598,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; From 881b1e2f95c26f5cb25260c074675f7de0e064ec Mon Sep 17 00:00:00 2001 From: "Bjoern A. Zeeb" Date: Thu, 31 Dec 2015 11:21:45 +0000 Subject: [PATCH 19/37] Bump copyright year. Happy New Year 2016! --- COPYRIGHT | 2 +- sys/sys/copyright.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/COPYRIGHT b/COPYRIGHT index 1d7198f722ce..94046dd8d368 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/sys/sys/copyright.h b/sys/sys/copyright.h index 6e47358ac14b..e3c1e40d3914 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 \ From 337cb9f04c4ee9de4531003426ae0bf595f3e634 Mon Sep 17 00:00:00 2001 From: Hans Petter Selasky Date: Thu, 31 Dec 2015 11:27:36 +0000 Subject: [PATCH 20/37] Make the kobject refcounting compliant with Linux. Refcounting on the parent kobject cannot be factored out and must be done by the kobject consumers. MFC after: 1 week Sponsored by: Mellanox Technologies --- sys/compat/linuxkpi/common/include/linux/cdev.h | 7 +++++++ sys/compat/linuxkpi/common/src/linux_compat.c | 5 +---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/sys/compat/linuxkpi/common/include/linux/cdev.h b/sys/compat/linuxkpi/common/include/linux/cdev.h index 5d8962f46355..0f81099d0efb 100644 --- a/sys/compat/linuxkpi/common/include/linux/cdev.h +++ b/sys/compat/linuxkpi/common/include/linux/cdev.h @@ -54,21 +54,27 @@ static inline void 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 inline void 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); } static struct kobj_type cdev_ktype = { @@ -114,6 +120,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/src/linux_compat.c b/sys/compat/linuxkpi/common/src/linux_compat.c index 91ec693065c3..b57326ae2e74 100644 --- a/sys/compat/linuxkpi/common/src/linux_compat.c +++ b/sys/compat/linuxkpi/common/src/linux_compat.c @@ -157,7 +157,7 @@ kobject_add_complete(struct kobject *kobj, struct kobject *parent) 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; @@ -198,9 +198,6 @@ kobject_release(struct kref *kref) 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); From 06204f8e2541cdaa1a8779cb124cf35b87ba5ed0 Mon Sep 17 00:00:00 2001 From: Hans Petter Selasky Date: Thu, 31 Dec 2015 12:30:19 +0000 Subject: [PATCH 21/37] Minor LinuxKPI code cleanup: - Declare some static functions in linux_compat.c instead if inside various header files. - Prefix FreeBSD local functions in the LinuxKPI with "linux_" to avoid symbol name conflicts in the future and to make debugging easier. - Make the "struct kobj_ktype" declaractions constant to shave off a few bytes from the data segment. MFC after: 1 week Sponsored by: Mellanox Technologies --- .../linuxkpi/common/include/linux/cdev.h | 41 +--- .../linuxkpi/common/include/linux/device.h | 115 +---------- .../linuxkpi/common/include/linux/kobject.h | 16 +- .../common/include/linux/miscdevice.h | 8 +- sys/compat/linuxkpi/common/src/linux_compat.c | 188 +++++++++++++++--- sys/compat/linuxkpi/common/src/linux_pci.c | 6 +- 6 files changed, 192 insertions(+), 182 deletions(-) diff --git a/sys/compat/linuxkpi/common/include/linux/cdev.h b/sys/compat/linuxkpi/common/include/linux/cdev.h index 0f81099d0efb..84b7b70947d1 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; @@ -50,46 +52,11 @@ struct linux_cdev { const struct file_operations *ops; }; -static inline void -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 inline void -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); -} - -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; } @@ -100,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); } diff --git a/sys/compat/linuxkpi/common/include/linux/device.h b/sys/compat/linuxkpi/common/include/linux/device.h index 02b2064587d5..f4b8ec664514 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/kobject.h b/sys/compat/linuxkpi/common/include/linux/kobject.h index 475095e0963e..a000c4eebc10 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 96d8fe7f2dad..a873987888fd 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 b57326ae2e74..4d48519ff43d 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,10 +151,10 @@ 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 = parent; @@ -191,7 +191,7 @@ 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; @@ -205,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, ...) @@ -239,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); @@ -249,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; @@ -998,6 +1101,41 @@ destroy_workqueue(struct workqueue_struct *wq) kfree(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) { @@ -1006,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); @@ -1030,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 2d3d03b7de40..7c49a54a6dc0 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) From b6480353136adb6ba9cc4107ebeffac1d5926dfe Mon Sep 17 00:00:00 2001 From: Hans Petter Selasky Date: Thu, 31 Dec 2015 14:47:45 +0000 Subject: [PATCH 22/37] Handle when filedescriptors are closed before initialized. An early fdclose() call can cause fget_unlocked() to fail. Found by: mjg @ MFC after: 1 week Reviewed by: Mark Block Sponsored by: Mellanox Technologies Differential Revision: https://reviews.freebsd.org/D4351 --- sys/compat/linuxkpi/common/include/linux/file.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sys/compat/linuxkpi/common/include/linux/file.h b/sys/compat/linuxkpi/common/include/linux/file.h index e52afa55f202..559ac0437681 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); From 47d8814c7f8788017cfa867cf2bfa3a2fb302512 Mon Sep 17 00:00:00 2001 From: Jilles Tjoelker Date: Thu, 31 Dec 2015 17:51:15 +0000 Subject: [PATCH 23/37] sh: Perform IFS splitting during the first expansion phases. This simplifies the code and should be faster in some cases. Side effect: the order of operations is different so that the value of IFS used when IFS is modified during expansion (${IFS:=...}, ${IFS=...} or $((...IFS=...))) may be different. Note that this order is highly unportable between shells. --- bin/sh/expand.c | 615 ++++++++++++++++++++---------------------------- 1 file changed, 253 insertions(+), 362 deletions(-) diff --git a/bin/sh/expand.c b/bin/sh/expand.c index c876abb8028b..653ffc4c8c86 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 . All rights reserved. + * Copyright (c) 2010-2015 + * Jilles Tjoelker . All rights reserved. * * This code is derived from software contributed to Berkeley by * Kenneth Almquist. @@ -79,42 +81,32 @@ __FBSDID("$FreeBSD$"); #include "show.h" #include "builtins.h" -/* - * Structure specifying which parts of the string should be searched - * for IFS characters. - */ +enum wordstate { WORD_IDLE, WORD_WS_DELIMITED, WORD_QUOTEMARK }; -struct ifsregion { - struct ifsregion *next; /* next region in list */ - int begoff; /* offset of start of region */ - int endoff; /* offset of end of region */ - int inquotes; /* search for nul bytes only */ +struct worddest { + struct arglist list; + enum wordstate state; }; - static char *expdest; /* output of current string */ static struct nodelist *argbackq; /* list of back quote expressions */ -static struct ifsregion ifsfirst; /* first struct in list of ifs regions */ -static struct ifsregion *ifslastp; /* last struct in list */ -static char *argstr(char *, int); +static char *argstr(char *, int, struct worddest *); static char *exptilde(char *, int); -static char *expari(char *); -static void expbackq(union node *, int, int); -static int subevalvar_trim(char *, int, int, int, int); +static char *expari(char *, int, struct worddest *); +static void expbackq(union node *, int, int, struct worddest *); +static void subevalvar_trim(char *, int, int, int); static int subevalvar_misc(char *, const char *, int, int, int); -static char *evalvar(char *, int); +static char *evalvar(char *, int, struct worddest *); static int varisset(const char *, int); -static void strtodest(const char *, int, int, int); -static void varvalue(const char *, int, int, int); -static void recordregion(int, int, int); -static void removerecordregions(int); -static void ifsbreakup(char *, struct arglist *); +static void 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(struct arglist *, struct arglist *); static void expmeta(char *, char *, struct arglist *); static int expsortcmp(const void *, const void *); -static int patmatch(const char *, const char *, int); -static char *cvtnum(int, char *); +static int patmatch(const char *, const char *); +static void cvtnum(int, char *); static int collate_range_cmp(wchar_t, wchar_t); void @@ -169,6 +161,50 @@ 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, 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); + 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, p, dstlist) p = nextword(c, p, dstlist) + +static char * +stputs_split(const char *data, const char *syntax, 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, p, dst); + continue; + } + if (syntax[(int)c] == CCTL) + USTPUTC(CTLESC, p); + USTPUTC(c, p); + } + return (p); +} +#define STPUTS_SPLIT(data, syntax, p, dst) p = stputs_split((data), syntax, p, dst) + /* * Perform expansions on an argument, placing the resulting list of arguments * in arglist. Parameter expansion, command substitution and arithmetic @@ -184,34 +220,27 @@ 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; argbackq = arg->narg.backquote; + emptyarglist(&exparg.list); + 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_FULL) == 0 || expdest != stackblock() || + exparg.state == WORD_QUOTEMARK) { + STPUTC('\0', expdest); + if (flag & EXP_FULL) + appendarglist(&exparg.list, grabstackstr(expdest)); } + if (flag & EXP_FULL) + expandmeta(&exparg.list, arglist); + else + appendarglist(arglist, grabstackstr(expdest)); } @@ -223,10 +252,11 @@ expandarg(union node *arg, struct arglist *arglist, int flag) * This is used to expand word in ${var+word} etc. * If EXP_FULL 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_FULL 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 */ @@ -253,32 +283,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_FULL) != 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, expdest, dst); + break; + } + if (quotes) + USTPUTC(CTLESC, expdest); USTPUTC(c, expdest); - if (split_lit && !lit_quoted) - recordregion(expdest - stackblock() - - (quotes ? 2 : 1), - expdest - stackblock(), 0); break; case CTLVAR: - p = evalvar(p, flag); + p = evalvar(p, flag, dst); break; case CTLBACKQ: case CTLBACKQ|CTLQUOTE: - expbackq(argbackq->n, c & CTLQUOTE, flag); + expbackq(argbackq->n, c & CTLQUOTE, flag, dst); argbackq = argbackq->next; break; case CTLARI: - p = expari(p); + p = expari(p, flag, dst); break; case ':': case '=': @@ -286,10 +317,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, expdest, dst); + break; + } USTPUTC(c, expdest); - if (split_lit && !lit_quoted) - recordregion(expdest - stackblock() - 1, - expdest - stackblock(), 0); if (flag & EXP_VARTILDE && *p == '~' && (c != '=' || firsteq)) { if (c == '=') @@ -298,10 +331,12 @@ argstr(char *p, int flag) } break; default: + if (split_lit && !lit_quoted && + strchr(ifsset() ? ifsval() : " \t\n", c) != NULL) { + NEXTWORD(c, expdest, dst); + break; + } USTPUTC(c, expdest); - if (split_lit && !lit_quoted) - recordregion(expdest - stackblock() - 1, - expdest - stackblock(), 0); } } } @@ -345,7 +380,7 @@ exptilde(char *p, int flag) *p = c; if (home == NULL || *home == '\0') return (startp); - strtodest(home, flag, VSNORMAL, 1); + strtodest(home, flag, VSNORMAL, 1, NULL); return (p); } p++; @@ -353,51 +388,11 @@ exptilde(char *p, int flag) } -static void -removerecordregions(int endoff) -{ - if (ifslastp == NULL) - return; - - if (ifsfirst.endoff > endoff) { - while (ifsfirst.next != NULL) { - struct ifsregion *ifsp; - INTOFF; - ifsp = ifsfirst.next->next; - ckfree(ifsfirst.next); - ifsfirst.next = ifsp; - INTON; - } - if (ifsfirst.begoff > endoff) - ifslastp = NULL; - else { - ifslastp = &ifsfirst; - ifsfirst.endoff = endoff; - } - return; - } - - ifslastp = &ifsfirst; - while (ifslastp->next && ifslastp->next->begoff < endoff) - ifslastp=ifslastp->next; - while (ifslastp->next != NULL) { - struct ifsregion *ifsp; - INTOFF; - ifsp = ifslastp->next->next; - ckfree(ifslastp->next); - ifslastp->next = ifsp; - INTON; - } - if (ifslastp->endoff > endoff) - ifslastp->endoff = endoff; -} - /* * Expand arithmetic expression. - * Note that flag is not required as digits never require CTLESC characters. */ static char * -expari(char *p) +expari(char *p, int flag, struct worddest *dst) { char *q, *start; arith_t result; @@ -407,8 +402,7 @@ expari(char *p) quoted = *p++ == '"'; begoff = expdest - stackblock(); - p = argstr(p, 0); - removerecordregions(begoff); + p = argstr(p, 0, NULL); STPUTC('\0', expdest); start = stackblock() + begoff; @@ -425,7 +419,7 @@ expari(char *p) adj = strlen(expdest); STADJUST(adj, expdest); if (!quoted) - recordregion(begoff, expdest - stackblock(), 0); + reprocess(expdest - adj - stackblock(), flag, VSNORMAL, 0, dst); return p; } @@ -434,35 +428,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); 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_FULL) + ifs = ifsset() ? ifsval() : " \t\n"; + else + ifs = ""; /* Don't copy trailing newlines */ for (;;) { if (--in.nleft < 0) { @@ -476,15 +469,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', dest, dst); + nnl = 0; + } else { + CHECKSTRSPACE(nnl + 2, dest); + while (nnl > 0) { + nnl--; + USTPUTC('\n', dest); + } } + } + if (strchr(ifs, lastc) != NULL) + NEXTWORD(lastc, dest, dst); + else { + CHECKSTRSPACE(2, dest); if (quotes && syntax[(int)lastc] == CCTL) USTPUTC(CTLESC, dest); USTPUTC(lastc, dest); @@ -498,8 +503,6 @@ expbackq(union node *cmd, int quoted, int flag) ckfree(in.buf); if (in.jp) exitstatus = waitforjob(in.jp, (int *)NULL); - if (quoted == 0) - recordregion(startloc, dest - stackblock(), 0); TRACE(("expbackq: size=%td: \"%.*s\"\n", ((dest - stackblock()) - startloc), (int)((dest - stackblock()) - startloc), @@ -521,18 +524,17 @@ recordleft(const char *str, const char *loc, char *startp) *startp++ = *loc++; } -static int -subevalvar_trim(char *p, int strloc, int subtype, int startloc, int quotes) +static void +subevalvar_trim(char *p, int strloc, int subtype, int startloc) { char *startp; char *loc = NULL; - char *q; char *str; int c = 0; struct nodelist *saveargbackq = argbackq; int amount; - argstr(p, EXP_CASE | EXP_TILDE); + argstr(p, EXP_CASE | EXP_TILDE, NULL); STACKSTRNUL(expdest); argbackq = saveargbackq; startp = stackblock() + startloc; @@ -543,72 +545,56 @@ subevalvar_trim(char *p, int strloc, int subtype, int startloc, int quotes) for (loc = startp; loc < str; loc++) { c = *loc; *loc = '\0'; - if (patmatch(str, startp, quotes)) { + if (patmatch(str, startp)) { *loc = c; recordleft(str, loc, startp); - return 1; + return; } *loc = c; - if (quotes && *loc == CTLESC) - loc++; } - return 0; + break; case VSTRIMLEFTMAX: for (loc = str - 1; loc >= startp;) { c = *loc; *loc = '\0'; - if (patmatch(str, startp, quotes)) { + if (patmatch(str, startp)) { *loc = c; recordleft(str, loc, startp); - return 1; + return; } *loc = c; loc--; - if (quotes && loc > startp && *(loc - 1) == CTLESC) { - for (q = startp; q < loc; q++) - if (*q == CTLESC) - q++; - if (q > loc) - loc--; - } } - return 0; + break; case VSTRIMRIGHT: for (loc = str - 1; loc >= startp;) { - if (patmatch(str, loc, quotes)) { + if (patmatch(str, loc)) { amount = loc - expdest; STADJUST(amount, expdest); - return 1; + return; } loc--; - if (quotes && loc > startp && *(loc - 1) == CTLESC) { - for (q = startp; q < loc; q++) - if (*q == CTLESC) - q++; - if (q > loc) - loc--; - } } - return 0; + break; case VSTRIMRIGHTMAX: for (loc = startp; loc < str - 1; loc++) { - if (patmatch(str, loc, quotes)) { + if (patmatch(str, loc)) { amount = loc - expdest; STADJUST(amount, expdest); - return 1; + return; } - if (quotes && *loc == CTLESC) - loc++; } - return 0; + break; default: abort(); } + amount = (expdest - stackblock() - strloc) + 1; + STADJUST(-amount, expdest); } @@ -620,7 +606,7 @@ subevalvar_misc(char *p, const char *var, int subtype, int startloc, struct nodelist *saveargbackq = argbackq; int amount; - argstr(p, EXP_TILDE); + argstr(p, EXP_TILDE, NULL); STACKSTRNUL(expdest); argbackq = saveargbackq; startp = stackblock() + startloc; @@ -653,7 +639,7 @@ subevalvar_misc(char *p, const char *var, int subtype, int startloc, */ static char * -evalvar(char *p, int flag) +evalvar(char *p, int flag, struct worddest *dst) { int subtype; int varflags; @@ -666,9 +652,7 @@ evalvar(char *p, int flag) int startloc; int varlen; int varlenb; - int easy; - int quotes = flag & (EXP_FULL | EXP_CASE); - int record = 0; + char buf[21]; varflags = (unsigned char)*p++; subtype = varflags & VSTYPE; @@ -710,10 +694,16 @@ evalvar(char *p, int flag) if (set && subtype != VSPLUS) { /* insert the value of the variable */ if (special) { - if (varflags & VSLINENO) - STPUTBIN(var, p - var - 1, expdest); - else - varvalue(var, varflags & VSQUOTE, subtype, flag); + if (varflags & VSLINENO) { + if (p - var > (ptrdiff_t)sizeof(buf)) + abort(); + memcpy(buf, var, p - var - 1); + buf[p - var - 1] = '\0'; + strtodest(buf, flag, subtype, + varflags & VSQUOTE, dst); + } else + varvalue(var, varflags & VSQUOTE, subtype, flag, + dst); if (subtype == VSLENGTH) { varlenb = expdest - stackblock() - startloc; varlen = varlenb; @@ -734,35 +724,29 @@ evalvar(char *p, int flag) } 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)); + (varflags & VSQUOTE ? EXP_LIT_QUOTED : 0), dst); break; } - record = easy; break; case VSTRIMLEFT: @@ -777,14 +761,10 @@ evalvar(char *p, int flag) */ STPUTC('\0', expdest); patloc = expdest - stackblock(); - if (subevalvar_trim(p, patloc, subtype, - startloc, quotes) == 0) { - int amount = (expdest - stackblock() - patloc) + 1; - STADJUST(-amount, expdest); - } - /* Remove any recorded regions beyond start of variable */ - removerecordregions(startloc); - record = 1; + subevalvar_trim(p, patloc, subtype, startloc); + reprocess(startloc, flag, VSNORMAL, varflags & VSQUOTE, dst); + if (flag & EXP_FULL && *var == '@' && varflags & VSQUOTE) + dst->state = WORD_QUOTEMARK; break; case VSASSIGN: @@ -793,16 +773,10 @@ evalvar(char *p, int flag) if (subevalvar_misc(p, var, subtype, startloc, varflags)) { varflags &= ~VSNUL; - /* - * Remove any recorded regions beyond - * start of variable - */ - removerecordregions(startloc); goto again; } break; } - record = easy; break; case VSERROR: @@ -814,11 +788,6 @@ evalvar(char *p, int flag) abort(); } - if (record) - recordregion(startloc, expdest - stackblock(), - varflags & VSQUOTE || (ifsset() && ifsval()[0] == '\0' && - (*var == '@' || *var == '*'))); - if (subtype != VSNORMAL) { /* skip to end of alternative */ int nesting = 1; for (;;) { @@ -884,26 +853,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_FULL && !quoted && dst != NULL) + STPUTS_SPLIT(p, BASESYNTAX, expdest, dst); + else if (flag & (EXP_FULL | 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_FULL && (quoted || (zlen > 0 && zpos < len))) + NEXTWORD('\0', expdest, dst); + } +} + /* * Add the value of a specialized variable to the stack string. */ static void -varvalue(const char *name, int quoted, int subtype, int flag) +varvalue(const char *name, int quoted, int subtype, int flag, + struct worddest *dst) { int num; char *p; int i; + int splitlater; char sep[2]; char **ap; + char buf[(NSHORTOPTS > 10 ? NSHORTOPTS : 10) + 1]; + + if (subtype == VSLENGTH) + flag &= ~EXP_FULL; + splitlater = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX || + subtype == VSTRIMRIGHT || subtype == VSTRIMRIGHTMAX; switch (*name) { case '$': @@ -919,18 +942,27 @@ 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) { 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', expdest, dst); + } } + if (shellparam.nparam > 0) + dst->state = WORD_QUOTEMARK; return; } /* FALLTHROUGH */ @@ -941,13 +973,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_FULL && !quoted && **ap != '\0') { + if (splitlater) + STPUTC('\0', expdest); + else + NEXTWORD('\0', expdest, dst); + } } return; default: @@ -959,149 +995,16 @@ 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)) @@ -1264,7 +1167,7 @@ expmeta(char *enddir, char *name, struct arglist *arglist) while (! int_pending() && (dp = readdir(dirp)) != NULL) { if (dp->d_name[0] == '.' && ! matchdot) continue; - if (patmatch(start, dp->d_name, 0)) { + if (patmatch(start, dp->d_name)) { namlen = dp->d_namlen; if (enddir + namlen + 1 > expdir_end) continue; @@ -1354,7 +1257,7 @@ match_charclass(const char *p, wchar_t chr, const char **end) */ static int -patmatch(const char *pattern, const char *string, int squoted) +patmatch(const char *pattern, const char *string) { const char *p, *q, *end; const char *bt_p, *bt_q; @@ -1372,16 +1275,12 @@ 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) { @@ -1426,8 +1325,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) { @@ -1485,8 +1382,6 @@ patmatch(const char *pattern, const char *string, int squoted) break; } dft: default: - if (squoted && *q == CTLESC) - q++; if (*q == '\0') return 0; if (*q++ == c) @@ -1499,8 +1394,6 @@ dft: default: */ if (bt_p == NULL) return 0; - if (squoted && *bt_q == CTLESC) - bt_q++; if (*bt_q == '\0') return 0; bt_q++; @@ -1556,11 +1449,10 @@ casematch(union node *pattern, const char *val) setstackmark(&smark); argbackq = pattern->narg.backquote; STARTSTACKSTR(expdest); - ifslastp = NULL; - argstr(pattern->narg.text, EXP_TILDE | EXP_CASE); + argstr(pattern->narg.text, EXP_TILDE | EXP_CASE, NULL); STPUTC('\0', expdest); p = grabstackstr(expdest); - result = patmatch(p, val, 0); + result = patmatch(p, val); popstackmark(&smark); return result; } @@ -1569,7 +1461,7 @@ casematch(union node *pattern, const char *val) * Our own itoa(). */ -static char * +static void cvtnum(int num, char *buf) { char temp[32]; @@ -1585,8 +1477,7 @@ cvtnum(int num, char *buf) if (neg) *--p = '-'; - STPUTS(p, buf); - return buf; + memcpy(buf, p, temp + 32 - p); } /* From dd876af4dea7e03e8202bc7ec4d16bea27e3cad6 Mon Sep 17 00:00:00 2001 From: Kristof Provost Date: Thu, 31 Dec 2015 18:12:35 +0000 Subject: [PATCH 24/37] Add suppoort for the Sitecom LN-031 This is an AX88178 chip, which we already support so all we have to do is add the USB product and vendor ID. --- sys/dev/usb/net/if_axe.c | 1 + sys/dev/usb/usbdevs | 1 + 2 files changed, 2 insertions(+) diff --git a/sys/dev/usb/net/if_axe.c b/sys/dev/usb/net/if_axe.c index 199549729de7..aa1ce0ed4c37 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 42ba9c1ffcd0..2a55e7cba4e8 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 From 1256437c729f35334fc30bfea55b583ee4cbe678 Mon Sep 17 00:00:00 2001 From: Ian Lepore Date: Thu, 31 Dec 2015 18:29:24 +0000 Subject: [PATCH 25/37] When building libstand for arm, don't emit instructions that require relocation fixups unsupported by the self_reloc() code, and don't optimize memcpy/memset using floating point registers, because in a standalone environment nothing has initialized the fpu hardware. --- lib/libstand/Makefile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/libstand/Makefile b/lib/libstand/Makefile index a69a935b3809..3126c1c30197 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 From 0e39c931e219daa9b410c0606acd51e054575419 Mon Sep 17 00:00:00 2001 From: Jilles Tjoelker Date: Thu, 31 Dec 2015 18:47:54 +0000 Subject: [PATCH 26/37] sh: Perform pathname generation during the first expansion phases. This avoids the need to add and remove CTLESC bytes if pathname generation will not be performed (set -f). Side effect: the order of operations is slightly different: pathname generation in ${$+* $(CMD)} will not see filesystem changes from CMD. --- bin/sh/expand.c | 104 ++++++++++++++++++++++++------------------------ bin/sh/expand.h | 5 ++- 2 files changed, 57 insertions(+), 52 deletions(-) diff --git a/bin/sh/expand.c b/bin/sh/expand.c index 653ffc4c8c86..70280a1b8e21 100644 --- a/bin/sh/expand.c +++ b/bin/sh/expand.c @@ -84,7 +84,7 @@ __FBSDID("$FreeBSD$"); enum wordstate { WORD_IDLE, WORD_WS_DELIMITED, WORD_QUOTEMARK }; struct worddest { - struct arglist list; + struct arglist *list; enum wordstate state; }; @@ -102,7 +102,7 @@ static int varisset(const char *, int); 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(struct arglist *, struct arglist *); +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 *); @@ -162,7 +162,7 @@ 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, char *p, struct worddest *dst) +nextword(char c, int flag, char *p, struct worddest *dst) { int is_ws; @@ -170,20 +170,23 @@ nextword(char c, char *p, struct worddest *dst) if (p != stackblock() || (is_ws ? dst->state == WORD_QUOTEMARK : dst->state != WORD_WS_DELIMITED) || c == '\0') { STPUTC('\0', p); - appendarglist(&dst->list, grabstackstr(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--; + appendarglist(dst->list, NULL); + dst->list->count--; STARTSTACKSTR(p); return p; } -#define NEXTWORD(c, p, dstlist) p = nextword(c, p, dstlist) +#define NEXTWORD(c, flag, p, dstlist) p = nextword(c, flag, p, dstlist) static char * -stputs_split(const char *data, const char *syntax, char *p, +stputs_split(const char *data, const char *syntax, int flag, char *p, struct worddest *dst) { const char *ifs; @@ -194,16 +197,16 @@ stputs_split(const char *data, const char *syntax, char *p, CHECKSTRSPACE(2, p); c = *data++; if (strchr(ifs, c) != NULL) { - NEXTWORD(c, p, dst); + NEXTWORD(c, flag, p, dst); continue; } - if (syntax[(int)c] == CCTL) + if (flag & EXP_GLOB && syntax[(int)c] == CCTL) USTPUTC(CTLESC, p); USTPUTC(c, p); } return (p); } -#define STPUTS_SPLIT(data, syntax, p, dst) p = stputs_split((data), syntax, p, dst) +#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 @@ -222,8 +225,10 @@ expandarg(union node *arg, struct arglist *arglist, int flag) { struct worddest exparg; + if (fflag) + flag &= ~EXP_GLOB; argbackq = arg->narg.backquote; - emptyarglist(&exparg.list); + exparg.list = arglist; exparg.state = WORD_IDLE; STARTSTACKSTR(expdest); argstr(arg->narg.text, flag, &exparg); @@ -231,15 +236,17 @@ expandarg(union node *arg, struct arglist *arglist, int flag) STACKSTRNUL(expdest); return; /* here document expanded */ } - if ((flag & EXP_FULL) == 0 || expdest != stackblock() || + if ((flag & EXP_SPLIT) == 0 || expdest != stackblock() || exparg.state == WORD_QUOTEMARK) { STPUTC('\0', expdest); - if (flag & EXP_FULL) - appendarglist(&exparg.list, grabstackstr(expdest)); + if (flag & EXP_SPLIT) { + if (flag & EXP_GLOB) + expandmeta(grabstackstr(expdest), exparg.list); + else + appendarglist(exparg.list, grabstackstr(expdest)); + } } - if (flag & EXP_FULL) - expandmeta(&exparg.list, arglist); - else + if ((flag & EXP_SPLIT) == 0) appendarglist(arglist, grabstackstr(expdest)); } @@ -250,16 +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, dst receives any complete words produced. + * If EXP_SPLIT is set, dst receives any complete words produced. */ static char * 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; @@ -283,7 +290,7 @@ argstr(char *p, int flag, struct worddest *dst) if (p[0] == CTLVAR && (p[1] & VSQUOTE) != 0 && p[2] == '@' && p[3] == '=') break; - if ((flag & EXP_FULL) != 0 && expdest == stackblock()) + if ((flag & EXP_SPLIT) != 0 && expdest == stackblock()) dst->state = WORD_QUOTEMARK; break; case CTLQUOTEEND: @@ -293,7 +300,7 @@ argstr(char *p, int flag, struct worddest *dst) c = *p++; if (split_lit && !lit_quoted && strchr(ifsset() ? ifsval() : " \t\n", c) != NULL) { - NEXTWORD(c, expdest, dst); + NEXTWORD(c, flag, expdest, dst); break; } if (quotes) @@ -319,7 +326,7 @@ argstr(char *p, int flag, struct worddest *dst) */ if (split_lit && !lit_quoted && strchr(ifsset() ? ifsval() : " \t\n", c) != NULL) { - NEXTWORD(c, expdest, dst); + NEXTWORD(c, flag, expdest, dst); break; } USTPUTC(c, expdest); @@ -333,7 +340,7 @@ argstr(char *p, int flag, struct worddest *dst) default: if (split_lit && !lit_quoted && strchr(ifsset() ? ifsval() : " \t\n", c) != NULL) { - NEXTWORD(c, expdest, dst); + NEXTWORD(c, flag, expdest, dst); break; } USTPUTC(c, expdest); @@ -438,7 +445,7 @@ expbackq(union node *cmd, int quoted, int flag, struct worddest *dst) struct nodelist *saveargbackq; char lastc; 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; @@ -452,7 +459,7 @@ expbackq(union node *cmd, int quoted, int flag, struct worddest *dst) p = in.buf; lastc = '\0'; nnl = 0; - if (!quoted && flag & EXP_FULL) + if (!quoted && flag & EXP_SPLIT) ifs = ifsset() ? ifsval() : " \t\n"; else ifs = ""; @@ -476,7 +483,7 @@ expbackq(union node *cmd, int quoted, int flag, struct worddest *dst) } else { if (nnl > 0) { if (strchr(ifs, '\n') != NULL) { - NEXTWORD('\n', dest, dst); + NEXTWORD('\n', flag, dest, dst); nnl = 0; } else { CHECKSTRSPACE(nnl + 2, dest); @@ -487,7 +494,7 @@ expbackq(union node *cmd, int quoted, int flag, struct worddest *dst) } } if (strchr(ifs, lastc) != NULL) - NEXTWORD(lastc, dest, dst); + NEXTWORD(lastc, flag, dest, dst); else { CHECKSTRSPACE(2, dest); if (quotes && syntax[(int)lastc] == CCTL) @@ -743,7 +750,7 @@ evalvar(char *p, int flag, struct worddest *dst) case VSPLUS: case VSMINUS: if (!set) { - argstr(p, flag | (flag & EXP_FULL ? EXP_SPLIT_LIT : 0) | + argstr(p, flag | (flag & EXP_SPLIT ? EXP_SPLIT_LIT : 0) | (varflags & VSQUOTE ? EXP_LIT_QUOTED : 0), dst); break; } @@ -763,7 +770,7 @@ evalvar(char *p, int flag, struct worddest *dst) patloc = expdest - stackblock(); subevalvar_trim(p, patloc, subtype, startloc); reprocess(startloc, flag, VSNORMAL, varflags & VSQUOTE, dst); - if (flag & EXP_FULL && *var == '@' && varflags & VSQUOTE) + if (flag & EXP_SPLIT && *var == '@' && varflags & VSQUOTE) dst->state = WORD_QUOTEMARK; break; @@ -860,9 +867,9 @@ strtodest(const char *p, int flag, int subtype, int quoted, subtype == VSTRIMLEFTMAX || subtype == VSTRIMRIGHT || subtype == VSTRIMRIGHTMAX) STPUTS(p, expdest); - else if (flag & EXP_FULL && !quoted && dst != NULL) - STPUTS_SPLIT(p, BASESYNTAX, expdest, dst); - else if (flag & (EXP_FULL | EXP_CASE)) + 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); @@ -902,8 +909,8 @@ reprocess(int startloc, int flag, int subtype, int quoted, zpos += zlen + 1; if (zpos == len + 1) break; - if (flag & EXP_FULL && (quoted || (zlen > 0 && zpos < len))) - NEXTWORD('\0', expdest, dst); + if (flag & EXP_SPLIT && (quoted || (zlen > 0 && zpos < len))) + NEXTWORD('\0', flag, expdest, dst); } } @@ -951,14 +958,15 @@ varvalue(const char *name, int quoted, int subtype, int flag, 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, dst); if (*ap) { if (splitlater) STPUTC('\0', expdest); else - NEXTWORD('\0', expdest, dst); + NEXTWORD('\0', flag, expdest, + dst); } } if (shellparam.nparam > 0) @@ -978,11 +986,11 @@ varvalue(const char *name, int quoted, int subtype, int flag, break; if (sep[0]) strtodest(sep, flag, subtype, quoted, dst); - else if (flag & EXP_FULL && !quoted && **ap != '\0') { + else if (flag & EXP_SPLIT && !quoted && **ap != '\0') { if (splitlater) STPUTC('\0', expdest); else - NEXTWORD('\0', expdest, dst); + NEXTWORD('\0', flag, expdest, dst); } } return; @@ -1014,40 +1022,34 @@ static char expdir[PATH_MAX]; * 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]; + p = pattern; for (; (c = *p) != '\0'; p++) { /* fast check for meta chars */ if (c == '*' || c == '?' || c == '[') { INTOFF; - expmeta(expdir, srclist->args[i], - dstlist); + expmeta(expdir, pattern, dstlist); INTON; break; } } - } if (dstlist->count == firstmatch) { /* * no matches */ - rmescapes(srclist->args[i]); - appendarglist(dstlist, srclist->args[i]); + rmescapes(pattern); + appendarglist(dstlist, pattern); } else { qsort(&dstlist->args[firstmatch], dstlist->count - firstmatch, sizeof(dstlist->args[0]), expsortcmp); } - } } diff --git a/bin/sh/expand.h b/bin/sh/expand.h index d024e8f6b7af..7fa7613007fb 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 *); From ee97d8648c80e696cb0aa6240641c4526278261f Mon Sep 17 00:00:00 2001 From: Jilles Tjoelker Date: Thu, 31 Dec 2015 18:56:11 +0000 Subject: [PATCH 27/37] sh: Reindent expandmeta(). --- bin/sh/expand.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/bin/sh/expand.c b/bin/sh/expand.c index 70280a1b8e21..6d5819dc6509 100644 --- a/bin/sh/expand.c +++ b/bin/sh/expand.c @@ -1028,28 +1028,28 @@ expandmeta(char *pattern, struct arglist *dstlist) int firstmatch; char c; - 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); + 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); + } } From 7e0feeac69be9c1779a4f67d535e544682663ebd Mon Sep 17 00:00:00 2001 From: Devin Teske Date: Thu, 31 Dec 2015 19:00:45 +0000 Subject: [PATCH 28/37] Remove debugging messages. NB: SVN r187143 reads: comment out some debugging messages that slipped in by mistake (removing them 7 years after they have been commented out) MFC after: 1 week --- sys/boot/forth/support.4th | 3 --- 1 file changed, 3 deletions(-) diff --git a/sys/boot/forth/support.4th b/sys/boot/forth/support.4th index 9a68872d2c95..0fe9a8c94712 100644 --- a/sys/boot/forth/support.4th +++ b/sys/boot/forth/support.4th @@ -852,7 +852,6 @@ only forth also support-functions definitions \ Interface to loading conf files : load_conf ( addr len -- ) - \ ." ----- Trying conf " 2dup type cr \ debugging 0 to end_of_file? reset_line_reading O_RDONLY fopen fd ! @@ -944,7 +943,6 @@ string current_file_name_ref \ used to print the file name \ loader_conf_files processing support functions : get_conf_files ( -- addr len ) \ put addr/len on stack, reset var - \ ." -- starting on <" conf_files strtype ." >" cr \ debugging conf_files strget 0 0 conf_files strset ; @@ -971,7 +969,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 ) From 58eaee0654da86db04253e89da251e770faf4816 Mon Sep 17 00:00:00 2001 From: Ed Maste Date: Thu, 31 Dec 2015 19:25:35 +0000 Subject: [PATCH 29/37] newvers.sh: put variable assignments on separate lines This makes it easier to grep for where they're set, and may simplify future merging for FreeBSD derivatives that change these. --- sys/conf/newvers.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sys/conf/newvers.sh b/sys/conf/newvers.sh index fc812c515e2d..a5d47491eb06 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 From 40c94e016823b9da0a5e6c433e0f54750df1bc0d Mon Sep 17 00:00:00 2001 From: Devin Teske Date: Thu, 31 Dec 2015 19:33:17 +0000 Subject: [PATCH 30/37] Fix a memory leak. nextboot_conf_file is not volatile, as far as I can tell, and thus the strdup is entirely unnecessary. Thanks to: Toomas Soome (tsoome at-me dot-com) MFC after: 1 week --- sys/boot/forth/support.4th | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/boot/forth/support.4th b/sys/boot/forth/support.4th index 0fe9a8c94712..7812a9bafd3d 100644 --- a/sys/boot/forth/support.4th +++ b/sys/boot/forth/support.4th @@ -1019,7 +1019,7 @@ string current_file_name_ref \ used to print the file name ; : get_nextboot_conf_file ( -- addr len ) - nextboot_conf_file strget strdup + nextboot_conf_file strget ; : rewrite_nextboot_file ( -- ) From 29a46b532018930979b26f9068cceb4870bc90d8 Mon Sep 17 00:00:00 2001 From: Devin Teske Date: Thu, 31 Dec 2015 19:37:14 +0000 Subject: [PATCH 31/37] Remove supposition comment that code would better live elsewhere. Thinking this through, and looking at process_assignment, I believe moving the code would be wrong considering that set_conf_files is called in one condition while set_nextboot_conf is guarded by a different condition of having nextboot_enable="YES". So these must stay separated and not combined. MFC after: 1 week --- sys/boot/forth/support.4th | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/boot/forth/support.4th b/sys/boot/forth/support.4th index 7812a9bafd3d..5a005b4acd83 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= ; From f1aba489c111c6622f8e66ed9af5591ba5562bdf Mon Sep 17 00:00:00 2001 From: Allan Jude Date: Thu, 31 Dec 2015 20:00:53 +0000 Subject: [PATCH 32/37] Introduce the ZFS Boot Environments menu to the loader menu If the system was booted with ZFS, a new menu item (#7) appears It contains an autogenerated list of ZFS Boot Environments This allows the user to switch to an alternate root file system Use Cases: - Revert a failed upgrade - Concurrently run different versions of FreeBSD with common home directory - Easier integration with the sysadmin/beadm utility Requested by: many Reviewed by: dteske MFC after: 10 days Relnotes: yes Sponsored by: ScaleEngine Inc. Differential Revision: https://reviews.freebsd.org/D3167 --- sys/boot/forth/loader.conf | 1 + sys/boot/forth/menu-commands.4th | 64 ++++++++++++ sys/boot/forth/menu.rc | 53 ++++++++++ sys/boot/forth/support.4th | 24 +++++ sys/boot/i386/loader/main.c | 57 +++++++++++ sys/boot/zfs/libzfs.h | 3 + sys/boot/zfs/zfs.c | 166 ++++++++++++++++++++++++++++++- sys/boot/zfs/zfsimpl.c | 62 ++++++++++-- 8 files changed, 423 insertions(+), 7 deletions(-) diff --git a/sys/boot/forth/loader.conf b/sys/boot/forth/loader.conf index e2338abe4c05..c13e90ec7d44 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 07846760021e..9adf30a46b66 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 7ffeef40aced..3c7de7138b8a 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 5a005b4acd83..3a8e1f24e04c 100644 --- a/sys/boot/forth/support.4th +++ b/sys/boot/forth/support.4th @@ -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 diff --git a/sys/boot/i386/loader/main.c b/sys/boot/i386/loader/main.c index 00873383e299..d4073e7da714 100644 --- a/sys/boot/i386/loader/main.c +++ b/sys/boot/i386/loader/main.c @@ -69,6 +69,7 @@ static int isa_inb(int port); static void isa_outb(int port, int value); void exit(int code); #ifdef LOADER_ZFS_SUPPORT +static void init_zfs_bootenv(char *currdev); static void i386_zfs_probe(void); #endif @@ -294,12 +295,40 @@ extract_currdev(void) new_currdev.d_unit = 0; } +#ifdef LOADER_ZFS_SUPPORT + init_zfs_bootenv(zfs_fmtdev(&new_currdev)); +#endif + env_setenv("currdev", EV_VOLATILE, i386_fmtdev(&new_currdev), i386_setcurrdev, env_nounset); env_setenv("loaddev", EV_VOLATILE, i386_fmtdev(&new_currdev), env_noset, env_nounset); } +#ifdef LOADER_ZFS_SUPPORT +static void +init_zfs_bootenv(char *currdev) +{ + char *beroot; + + /* Remove the trailing : */ + currdev[strlen(currdev) - 1] = '\0'; + setenv("zfs_be_active", currdev, 1); + /* Do not overwrite if already set */ + setenv("vfs.root.mountfrom", currdev, 0); + /* Forward past zfs: */ + currdev = strchr(currdev, ':'); + currdev++; + /* Remove the last element (current bootenv) */ + beroot = strrchr(currdev, '/'); + beroot[0] = '\0'; + + beroot = currdev; + + setenv("zfs_be_root", beroot, 1); +} +#endif + COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); static int @@ -353,6 +382,34 @@ command_lszfs(int argc, char *argv[]) command_errmsg = strerror(err); return (CMD_ERROR); } + + return (CMD_OK); +} + +COMMAND_SET(reloadbe, "reloadbe", "refresh the list of ZFS Boot Environments", + command_reloadbe); + +static int +command_reloadbe(int argc, char *argv[]) +{ + int err; + + if (argc > 2) { + command_errmsg = "wrong number of arguments"; + return (CMD_ERROR); + } + + if (argc == 2) { + err = zfs_bootenv(argv[1]); + } else { + err = zfs_bootenv(getenv("zfs_be_root")); + } + + if (err != 0) { + command_errmsg = strerror(err); + return (CMD_ERROR); + } + return (CMD_OK); } #endif diff --git a/sys/boot/zfs/libzfs.h b/sys/boot/zfs/libzfs.h index 6834f8b14ba5..b28984958c9a 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 64c738de314a..0e15ac48ff6a 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 d889047ffbd5..927fbadd8021 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 /* From bc57b4d4699e65768fa90b0db5bacb62ae9a1701 Mon Sep 17 00:00:00 2001 From: Jilles Tjoelker Date: Thu, 31 Dec 2015 20:15:57 +0000 Subject: [PATCH 33/37] sh: Remove redundant CTLQUOTEMARK checks. With the new expand.c code, the intermediate representation passed to the pathname generation code only contains CTLESC, not CTLQUOTEMARK. CTLQUOTEMARK now only occurs in the text of NARG nodes (output of the parser). --- bin/sh/expand.c | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/bin/sh/expand.c b/bin/sh/expand.c index 6d5819dc6509..59ba5490f7fe 100644 --- a/bin/sh/expand.c +++ b/bin/sh/expand.c @@ -1018,7 +1018,7 @@ static char expdir[PATH_MAX]; /* * 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 @@ -1083,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') @@ -1096,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++; @@ -1112,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; @@ -1130,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++; @@ -1160,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 == '.') @@ -1280,8 +1270,6 @@ patmatch(const char *pattern, const char *string) if (*q++ != *p++) goto backtrack; break; - case CTLQUOTEMARK: - continue; case '?': if (*q == '\0') return 0; @@ -1298,7 +1286,7 @@ patmatch(const char *pattern, const char *string) break; case '*': c = *p; - while (c == CTLQUOTEMARK || c == '*') + while (c == '*') c = *++p; /* * If the pattern ends here, we know the string @@ -1342,8 +1330,6 @@ patmatch(const char *pattern, const char *string) c = '['; goto dft; } - if (c == CTLQUOTEMARK) - continue; if (c == '[' && *p == ':') { found |= match_charclass(p, chr, &end); if (end != NULL) @@ -1360,8 +1346,6 @@ patmatch(const char *pattern, const char *string) wc = (unsigned char)c; if (*p == '-' && p[1] != ']') { p++; - while (*p == CTLQUOTEMARK) - p++; if (*p == CTLESC) p++; if (localeisutf8) { From 5198e5ef551f8634b8ff22050e43b3da1b8f91e6 Mon Sep 17 00:00:00 2001 From: Adrian Chadd Date: Thu, 31 Dec 2015 22:31:43 +0000 Subject: [PATCH 34/37] [rtwn] add rtwn firmware. Submitted by: kevlo --- sys/contrib/dev/rtwn/LICENSE | 39 ++ sys/contrib/dev/rtwn/rtwn-rtl8192cfwU.fw.uu | 333 ++++++++++++++++ sys/contrib/dev/rtwn/rtwn-rtl8192cfwU_B.fw.uu | 366 ++++++++++++++++++ 3 files changed, 738 insertions(+) create mode 100644 sys/contrib/dev/rtwn/LICENSE create mode 100644 sys/contrib/dev/rtwn/rtwn-rtl8192cfwU.fw.uu create mode 100644 sys/contrib/dev/rtwn/rtwn-rtl8192cfwU_B.fw.uu diff --git a/sys/contrib/dev/rtwn/LICENSE b/sys/contrib/dev/rtwn/LICENSE new file mode 100644 index 000000000000..d70921f49379 --- /dev/null +++ b/sys/contrib/dev/rtwn/LICENSE @@ -0,0 +1,39 @@ +Copyright (c) 2010, Realtek Semiconductor Corporation +All rights reserved. + +Redistribution. Redistribution and use in binary form, without +modification, are permitted provided that the following conditions are +met: + +* Redistributions must reproduce the above copyright notice and the + following disclaimer in the documentation and/or other materials + provided with the distribution. +* Neither the name of Realtek Semiconductor Corporation nor the names of its + suppliers may be used to endorse or promote products derived from this + software without specific prior written permission. +* No reverse engineering, decompilation, or disassembly of this software + is permitted. + +Limited patent license. Realtek Semiconductor Corporation grants a world-wide, +royalty-free, non-exclusive license under patents it now or hereafter +owns or controls to make, have made, use, import, offer to sell and +sell ("Utilize") this software, but solely to the extent that any +such patent is necessary to Utilize the software alone, or in +combination with an operating system licensed under an approved Open +Source license as listed by the Open Source Initiative at +http://opensource.org/licenses. The patent license shall not apply to +any other combinations which include this software. No hardware per +se is licensed hereunder. + +DISCLAIMER. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. diff --git a/sys/contrib/dev/rtwn/rtwn-rtl8192cfwU.fw.uu b/sys/contrib/dev/rtwn/rtwn-rtl8192cfwU.fw.uu new file mode 100644 index 000000000000..d542b2ea3fff --- /dev/null +++ b/sys/contrib/dev/rtwn/rtwn-rtl8192cfwU.fw.uu @@ -0,0 +1,333 @@ +begin 444 rtwn-rtl8192cfwU.fw.uu +MP8@"`$@````%$!!3PCD!`(%C`0`````````````````"0[H````````````` +M`````````E!$```````````````````````````````````````````````` +M`````````````E;@```````"2VH```4$`P(``P8%!`,`!`8%!`(`!`@'!@0` +M!@H)"`8`"`H)"`0`"`H)"`(`"`H)"```"!(1$`@`$!H9&!``&"(A(!@`("(A +M(!``("(A(`@`("(A'`@`("(A%`@`("(@&`@`(#$P(!``,#$P&```,#$O$!`` +M,#$L$!``,#$H$```,#$@$```,#$0$```,`0$!`4$!`0%!04&!@0$!`4%!08& +M!`0%!04%!@8$!`4%!04&!PH+#1`$!04&!@D,$0@("0D*#!`1!`0$!00$!0<' +M!P@*!`0$!`8*"PT%!0<'"`L-#P0$!`4'!PD)#`X0$@0$!04&"A$3"0D)"0P. +M$1,````````````D)BH8&AT?(2`"@`,@!0`&0`>`",`$L`4`!X`+0`^@$L`9`!]```@`" +M``0`"``,`!(`&``D`#``2`!@`&P`*``\`%``9`"@`,@`\`$8`&0`H`#P`6@! +M]`)8`R`#Z`("`@("`@,#!`0%!P0$!PH*#`P2!0<'"`L2)#P!`0$!`0(#!`4& +M!P@!`@,$!08'"`4&!P@)"@L,(!X<&!`8````````````````NP$,Y8(I]8+E +M@SKU@^`B4`;I)8+XYB*[_@;I)8+XXB+E@BGU@N6#.O6#Y),BNP$&B8**@_`B +M4`+W(KO^`?,B^+L!#>6"*?6"Y8,Z]8/H\")0!NDE@LCV(KO^!>DE@LCR(L7P +M^*/@*/#%\/CE@A6"<`(5@^`X\"*[`0J)@HJ#X/7PH^`B4`:'\`GG&2*[_@?C +M]?`)XQDBB8**@^23]?!T`9,BNP$0Y8(I]8+E@SKU@^#U\*/@(E`)Z26"^(;P +M".8BN_X*Z26"^.+U\`CB(N6#*O6#Z9/U\*/IDR*[`0J)@HJ#\.7PH_`B4`;W +M":?P&2*[_@;SY?`)\QDB^+L!$>6"*?6"Y8,Z]8/H\.7PH_`B4`GI)8+(]@BF +M\"*[_@GI)8+(\N7P"/(B[TO_[DK^[4G][$C\(N#\H^#]H^#^H^#_(J0E@O6" +MY?`U@_6#(N#[H^#ZH^#Y(OC@^Z.CX/DE\/#E@A6"<`(5@^#Z./`BZ_"CZO"C +MZ?`BT(/0@OCDDW`2=`&3<`VCHY/X=`&3]8*(@^1S=`*3:&#OHZ.C@-\"0_@" +M2"_DDZ/XY).C0`/V@`'R"-_T@"GDDZ/X5`1^`9-@O*/_5#\PY0E4'_[DDZ-@`0[/5,`EX&"H +M0+CDDZ/ZY).C^.23H\C%@LC*Q8/*\*/(Q8+(RL6#RM_IWN>`OD&7?P!!EZ$` +M09=K@$&7HP``CX*.@Z.CH^3P(N3U(W]@?@&`[=,0KP'#P-"0EUUQBY"777%K +MD``!4<+ZY?`D`/_D.OZ0EUUQ:Y```>Z/\'$9$B1B_V`HM2,4D)==<6N0``%1 +MPF4E<`3E)&7P8!^0EUUQ:Y```5'"_Z[PL5.`#I"777%K$B1B92-@`I%8T-"2 +MKR+T_Y``0^!?\-,0KP'#P-!_$-_^T-"2KR*0`=,0KP'#P-"+8(IAB6*0EXAQBZMCJF2I99"7BW&+ +MKV859N]@&Y"7B^1U\`%Q=!(D8O^0EXCD=?`!<73O44V`WJM@JF&I8M#0DJ\B +MD)=@[O"C[_!U(P&.)/4EY/U_"[&6Y/U_`K&6$FU;Y/^1YN3U)Y`!R>4G\)"7 +M8.#\H^#][/N-1.3U17T!?V!^`0(P8M,0KP'#P-"0EV/M\)"78N_PTY0'4$ZC +MX'`:D)=BX/]T`:@'"(`"PS/8_/3_D`!'X%_P@!>0EV+@_W0!J`<(@`+#,]C\ +M_Y``1^!/\)'6D)=BX/]T`:@'"(`"PS/8_/3_D`!&@%F0EV+@)/CPH^!P'9"7 +M8N#_=`&H!PB``L,SV/S$5/#T_Y``0^!?\(`:D)=BX/]T`:@'"(`"PS/8_,14 +M\/^0`$/@3_"1UI"78N#_=`&H!PB``L,SV/ST_Y``0^!?\)'6T-"2KR+@_WT! +MD)>4[_"C[?#DH_"C\.5J8`7D_Q).>9"7E.`PX`F0EY;D\*-T@/"0!!W@8!V0 +M!2+@D)>8\.#_5)!@[)`!R'3\\.]4;Y`%(O"`W9"7E.#_PQ.0_1#PD`0E[_"0 +MEY7@8!^CH^#_)`_U@N0T_/6#X$2`\'00+_6"Y#3\]8/@1(#PD)>6H^#__20( +M]8+D-/SU@^3P=`DM]8+D-/SU@^!4\/!T(2_U@N0T_/6#X%3W\)"7EN#^H^#_ +M(O"0`$7@5/[]?T73$*\!P\#0CX)U@P#M\)'6T-"2KR+O%&`P%&!E)`)@`N': +MD)!$$/U_18!OY)"7./"0 +MES1Q4Y"`EA(E"'^`?@@2*PB0`$7@1._]?T7Q()``1>!4[_U_1?$@D`!&X$00 +M_7]&@#>0ESAT`?"0ESYQ4Y"`EA(E"'^`?@@2*PB0`$7@1"#]?T7Q()``1>!$ +M$/U_1?$@D`!&X$00_7]&\2`BD`!)X)"7I/#@5`_P1/#]?TGQ()"7I.!$L/U_ +M2>$@=2@SY/4I=2H"]2N0`3#E*/"CY2GPH^4J\*/E*_`B=3`?=3$!Y/4RD`$X +MY3#PH^4Q\*/E,O`BY)"73_"C\'6.`A)LK9```N!4X)"7AF`%=`'P@`-T`O"0 +M`//@,.,(D)>'=`'P@`7DD)>'\)"7A^"T`1.0`/+@,.<,D)=]=/WPHW0S\(`* +MD)=]=/WPHW0O\.3U5Q)JZQ)O\A)?K!(N`1)M5Q)'^9``\^`PX@V0!4%T$/"0 +M!5KPH^3PD`%D=*#P=43_Y/5%^WT!?U!^`1(P8A$7$D4"$G=(D)=1Y=GP$E`5 +MPJ^0`(#@1$#P$D36=>@#0ZB%TJ^0ET_@9`'P)"^0`<3P=$BC\.57,.0*PJ]3 +M5^_2KQ)7@.57,.86PJ]35[_2KQ)A9)"7/.#_8`.T`0(Q8)"7/.!P`Q)WIC$S +M@+B0!C3@8"8435_^7X!$FSUOP$)D`8UX%0/\(`%@``";)[DD`8T +M\"*0ES/@PY044`7@!/!!&)"7,^!D%&`"01B0ET+@<"60ET7@0!/W@5/[PD)="X)`$1/"0ET/@D`1%\)"71."0 +M!$;PH^3PD)=%X)`$2/"0ET;@D`1)\)"71^"0!$KPH^3PD)#^TY]0"Y"72^##GM.4`4`0D)"0ETGPD`5BX)"72O"0!6/@D)=+\,-T_Y_^D)=)X-.>0![@+_"CX+3_#^3P +MH^"T_P/D\"*0ETN``Y"72N`$\"*0ETG@+_`BD)#_46*0ETQT`1)'%H!`D)=,X&0!<#B0ESW@_U%BY)"73/"0`$7@1`']?T42 +M1R"0ES+@8!60ES020U.0@)82)0A_@'X($BL(@`60!2+D\)`%A^!D@/"0ETC@ +MD`6$\)"72>"0!87PD)=*X)`%AO"0ETO@D`6'\"+`X,#PP(/`@L#0==``P`#` +M`<`"P`/`!,`%P`;`!Y`!Q'1J\'1+H_!3D=^0`3S@53#U-*/@53'U-:/@53+U +M-J/@53/U-^4T,.`&D`$\=`'PY30PX0B0`3QT`O#QJ^4T,.(RD`$\=`3PD`:2 +MX##@'G5$%'5%`.3[_7]8?@$2,&*0`5MT!?"0!I)T`?"`!Y"7=N3PD8KE-##C +M,I`!/'0(\)`&DN`PX1YU1!1U10#D^_U_7'X!$C!BD`%?=`7PD`:2=`+P@`>0 +MEW7D\)&*Y30PY`F0`3QT$/`2;7?E-##E")`!/'0@\%&TY34PX!"0`3UT`?"0 +M`(/@D)=Y\)&*=&H$D`'$\'1+H_#0!]`&T`70!-`#T`+0`=``T-#0@M"#T/#0 +MX#*0EWG@_WT!@`1]`7\,CV>-:.5G5`__D)=WX%0/;V!QY6]@*[%.D)=WX%0/_[\$#>5G(.(($E8Q[V`4T920EW?@5`__ +MOP(($F`)[V`"T>!4O_`BD`8$X$1`\.5IM`$$?P'Q2)"7=^!4\/#@1`3P +M(N]D`7`N?7U_`A(Q+'T"?P,2,2R0`5?D\)`!/'0"\)&3Y/_1>9`&!.!4?_"0 +M!@K@5/CP(I`!-G1]\*-T`O!]??\2,9U]`G\#$C&=D`8$X$2`\)`&"N!$!_"0 +MEW+@H^"0!5CPY6DPX!J0EV_@%&`O)`-P0'\!@#JK$:H2J1.0 +M``(20B#]Y/_14X`GJQ&J$JD3D``"$D(@_7\!T5,?@!.K$:H2J1.0``(20B#] +M?P+14^3_L6HB[R3^8`L$V0EWAP!70%\(`"[?"0EWC@D)=M +M\"+O8`N0EX?@M`$0Y/^`"9"7A^"T`05_`1)O^R*0`3=T`O"0!2)T__`2;E_O +M<`:0`BX&`%D`4BY/"0EW?@ +M5/#PX$0$\"*0!@3@5+_P[V`)Y6FT`03D__%(D)=WX%3P\.!$#/`B$E/\OP$: +MD)=VX'`4D)=UX'`.D)=YX%0/TY0$4`-_`2)_`"*/:Y"7@A)&7>5K8!!T(2_U +M@N0T_/6#X$00\(`.="$O]8+D-/SU@^!4[_"0!!]T`?`B?0)_`Q(Q+.5J%"3] +M4`*`(9"7>N!@!GT!?PR`#Y"7=^!4#\.4!%`&?0%_!)&7Y/_1>2*0EWO@8`[D +M\*/@5/WPX%0'<">`(Y"7;N`$\)"7?.!4[_"0EV[@TY0!0`WE:;0!"J/@<`;@ +M!/`BD8HBD`$PY/"C\*/PH_"0`3CPH_"C\*/P_7]0$D<@Y/U_41)'(.3]?U(2 +M1R#D_7]3`D<@D`$\=/_PH_"C\)`!-/"C\*/PH_#]?U021R!]_W]5$D<@??]_ +M5A)'('W_?U<"1R#`X,#PP(/`@L#0==``P`#``<`"P`/`!,`%P`;`!Y`!Q'1$ +M\'10H_"0`33@52CU+)`!-N!5*O4NH^!5*_4OY2P@X`(AVY`!-'0!\(713872 +M3H733X744(7548764H774X795.545$##$__E4U0@;W`"(9+E5##E`B&2Y5)4 +M'_4(Y4U4/_4)Y5%4'__E""7@)./U@N0TE/6#Y(_P$D*!Y5-4'__E""7@),#U +M@N0TD?6#Y(_P$D*!Y0G3E`1``W4)!'7P"N4(D)``$D-?=?`"Y0D20U_@_J/@ +M_^535!\O_^0^_G7P"N4(D)``$D-?=?`"Y0D20U_N\*/O\.54(.8CY5-4'__E +M""7@)&/U@N0TE/6#Y(_P$D*!Y4\PYS2O"+'#@"[E4U0?_^4()>`DH_6"Y#24 +M]8/DC_`20H'E3S#G$>5/5'_]Y5-4'_4-JPFO")&PY6H4)/U0`H!`D)=ZX&`R +MD`%;Y/"0`3QT!/!Q_.]D`7`H=404]47[_7]8?@$2,&*0`5MT!?"0!I)T`?"0 +MEW;P@`AQ_+\!`Q),BN4L,.$FD`$T=`+PD/T0='_PA=%8A=)9A=-:A=1;A=5< +MA=9=A==>A=E?D0OE+##C!I`!-'0(\.4L,.0)D`$T=!#P0U<0Y2PPY2:0`<_@ +M,.4?X%3?\)`!-'0@\'6H`'7H`!)/Y9```^!4^_`21-:`_N4L,.8&D`$T=$#P +MY2XPX3R0`39T`O!#5T"0`0+@5`-D`7`ID`$WX##@"G0!\)"7?^3P@!B0EW_@ +M!/#@PY0*0`SD\)`$&>`PX`,21/+E+C#@")`!-G0!\-%EY2XPXG&0`39T!/#E +M:60!<&7E:F!AY6ID`F`&Y6ID!7`GD`:KX)"7;?"0!JK@D)=X\)"7;>!P!Y"7 +M>.#_@`60EVW@_Y"7;>_PD)=OX&`#X!3PD)=NY/"0`5?PD`$\=`+PD)=\X%3] +M\.!4[_#E:A0D_5`"@`*Q$.4N,.,QD`$V=`CPY6ED`7`EY6I@(9`!5^3PD`$\ +M=`+P=40#=44`Y/O]?U1^`1(P8I`!5W0%\.4N,.0OD`$V=!#PY6ED`7`CY6I@ +M'Y`!5^3PD`$\=`+PD)=[Y/"0EWS@5/WPX%0'<`,23(KE+C#E'9`!-G0@\.5I +MM`$2Y6I@#I"7>N!D`F`$L7B``K&)Y2XPYAZ0`39T0/#E:;0!$^5J8`^0EWS@ +M5/[PX%0'<`,23(KE+S#A"9`!-W0"\!)/>71$!)`!Q/!T4*/PT`?0!M`%T`30 +M`]`"T`'0`-#0T(+0@]#PT.`RD`0;X%1_9']_`6`"?P`BD)=-X%3P1`/P5`]$ +M@/![`'H`>5B0EY$20XL+>I=Y3=,0KP'#P-"0EXX20XN0EX;@9`)@;)`!K^!@ +M"9`!Q^`$\/"`\9"7H^#_!/"0EXX20VN0``'O$D)?D)>.$D-KBV.*9(EE=68" +M>P%Z`7F@$D4)D)>1$D-KBV.*9(EED)>.$D-K$B1B_\14#_5F>P%Z`7FB$D4) +MD`&O=/_PD`'+X&2`\-#0DJ\BJ07I5!_U#W0!+_6"Y#22]8/@]0Z0!/W@M`$% +M=1`#@`-U$`'KPY400`*AP^4.)0W^Y0^00=:3_>[3G70!0!0EWS@1`'PD)=ZX&0"8`2Q>(`+L8F`!Y"7?.!4_O#E"I"7?##G +M(.!$`O!U1`/D]47[_7]4?@$2,&*0`5=T!?"0EWMT`?`BX%3]\"*0EX'@_^3] +M$D9AD`0?=`'P(I`!7^3PD`$\=`CP=404Y/5%^_U_7'X!$C!BD`%?=`7PD`:2 +M=`+PD)=U%/"0EW?@5`_#E`Q0`Q),DR*M!W7P">V0DR<20U_@_W2E+?6"Y#26 +M]8/@5!_\TY]``JP'["7@))[U@N0T0?6#Y)/^=`&3_^PEX"1F]8+D-$'U@W0! +MDR__Y),^PQ/^[Q/_[27@).'U@N0TDO6#[O"C[_!TA"WU@N0T!/6#[/#_(G'\ +M[V0!<"J0EWS@5`-P(I"7>>!4#].4`E`7D)=\X"#B$)"7?.`@Y`F0EV_@<`-_ +M`2)_`"+DD)=-\.5J8''E:60!<&OE:A1@*23]8"4D`B3[4`*`(Y"7;>`4\.!@ +M!*/@8!:0EVW@<`J0EWC@D)=M\(``D)=-=`'PD)=-X&`QD)=\X$00\)"7=.#U +M1.3U1?O]?U1^`1(P8I`!5W0%\)"7=^!4#\.4!%`'?0%_!!),ER+`X,#PP(/` +M@L#0==``P`#``<`"P`/`!,`%P`;`!Y`!Q'3@\'16H_!3D>^0`%'@_Y``5>!? +M]3WE/3#F&'1`\)"7.^!4`_^_`PN0ESC@8`5_`1)'->4],.<5D`!5=(#PD)<[ +MX%0#_[\#!7\"$D0EZ'@_W0! +M?@"H!PB`!<,SSC/.V/G_[UUP`P)8O9"7H>!U\`20`=`20U_@D)=3\'5C`75D +MEW5E4W5F`7L!>I=Y5!)%"9"75.#_Q!,3$U0!D)>A,.!9X'7P`I``B!)#7^"0 +MEU7PD)>AX'7P`I``B1)#7^"0EU;PD)>AX'7P!)`!T1)#7^"0EU?PD)>AX'7P +M!)`!TA)#7^"0EUCPD)>AX'7P!)`!TQ)#7^"0EUGP@#/@=?`$D`'1$D-?X)"7 +M5?"0EZ'@=?`$D`'2$D-?X)"75O"0EZ'@=?`$D`'3$D-?X)"75_#O5'__>P%Z +MEWE5$#^=`&H!@B``L,SV/ST7Y"74O"0EZ'@_W0!J`<(@`+# +M,]C\D`',\)"7H>`$\.!4`_`"5XJ0`<;@1`+P`E>*(I"76A)#B^\20Y18]`%8 +M_`)9!`-9#`59%`991@=9'`E9)0Q9+@U9-@X``%D_D)=:$D-KP=B0EUH20VO! +MTI"76A)#:^%DD)=:$D-KX0*0EUH20VN`*Y"76A)#:P)$89"76A)#:P)X?Y"7 +M6A)#:^$QD)=:$D-K`G9PD`'&X$0!\"*0``020B#_5!_^[U0@Q!-4!_VO!I"7 +M7>_PH^WPHQ)#BY"77Q)#:Y```Q)"(%3PQ%0/D)=B\)``!!)"(%1`Q!,35`.0 +MEV/PD)==X/]U\`F0DR420U^M@JR#D)=D[/"C[?#O=?`)I"0C^723-?#Z>P&C +M$D.+D)=?$D-KD``#$D(@5`__D)=F$D-K[Q)"39"77Q)#:Y```A)"(/^0EV82 +M0VN0``'O$D)?D)=?$D-KD``!$D(@_Y"79.#\H^#]]8*,@^_P$B1BC8*,@Z/P +MD)=BX/Z0EUW@_R3!]8+D-)+U@^[PD)=>X/YU\`GOD),I$D-?[O!U\`GOD),J +M$D-?=`'PD)=CX/YU\`GOD),K$D-?[O"/$>\EX"3D]8+D-)6O@O43CQ3E$77P +M`J0D@?ETDC7P=14!]1:)%W7P">41D),E$D-?KX*%@QB/&>41=?`)I"0C^723 +M-?!U&@'U&XD<=,$E$?6"Y#22]8/@$D.46M4`6NH!6O\"6Q0#6ST$6U(%6V<& +M6XT,6[H-6^<.7!0/``!<2.41)>`DY/6"Y#25]8-T\/"C=!6`/.41)>`DY/6" +MY#25]8-T\/"C=!"`)^41)>`DY/6"Y#25]8-T\/"C=`6`$N41)>`DY/6"Y#25 +M]8-T\/"CY/#E$27@)('U@N0TDO6#=`_PHW2/\(%(Y1$EX"3D]8+D-)7U@W0/ +M\*-T]8`GY1$EX"3D]8+D-)7U@W0/\*-T\(`2Y1$EX"3D]8+D-)7U@^3PHW0- +M\.41)>`D@?6"Y#22]8/D\*/P@4B0!$?@JQ6J%JD7$D)-D`1&X*L5JA:I%Y`` +M`1)"7Y`$1>"%%(*%$X/PD`1$@3^0!$O@JQ6J%JD7$D)-D`1*X*L5JA:I%Y`` +M`1)"7Y`$2>"%%(*%$X/PD`1(@%B0!$_@JQ6J%JD7$D)-D`1.X*L5JA:I%Y`` +M`1)"7Y`$3>"%%(*%$X/PD`1,@"N0!%/@JQ6J%JD7$D)-D`12X*L5JA:I%Y`` +M`1)"7Y`$4>"%%(*%$X/PD`10X(44@H43@Z/PJQ6J%JD7P`/``L`!$B1B_ZL: +MJANI'!(D8E_0`=`"T`,20DVK%>47)`'YY#46^L`#P`+``1(D8O^K&JH;J1R0 +M``$20B!?T`'0`M`#$D)-A12"A1.#P(/`@N#_A1F"A1B#X/[O7M""T(/PA12" +MA1.#H\"#P(+@_X49@H48@Z/@_N]>T(+0@_#E$27@)('U@N0TDO6#X/ZCX$Y@ +M.W42"W0!?@"H$@B`!<,SSC/.V/G_Y1$EX"2!]8+D-)+U@^!>_J/@7TY@!N42 +M)!"`7142Y1+#E`!0RH!6Y1$EX"3D]8+D-)7U@^#^H^!.8#UU$@]T`7X`J!(( +M@`7#,\XSSMCY_^41)>`DY/6"Y#25]8/@7OZCX%].8`B0EVGE$O"`$!42Y1+# +ME`!0R(`%Y)"7:?#E$27@).3U@N0TE?6#X/ZCX$Y@.^3U$G0!?@"H$@B`!<,S +MSC/.V/G_Y1$EX"3D]8+D-)7U@^!>_J/@7TY@")"7:N42\(!;!1+E$K00RH!2 +MY1$EX"2!]8+D-)+U@^#^H^!.8#GD]1)T`7X`J!((@`7#,\XSSMCY_^41)>`D +M@?6"Y#22]8/@7OZCX%].8`;E$B00@`H%$N42M`S,@`7DD)=J\)"7:>#_=?`) +MY1&0DR<20U_O\)"7:N#^=?`)Y1&0DR@20U_N\'2$)1'U@N0T!/6#X-.?0!^0 +MEVG@_W2$)1'U@N0TEO6#[_!TA"41]8+D-`3U@^_P=(0E$?6"Y#0$]8/@PYY0 +M'Y"7:N#_=(0E$?6"Y#26]8/O\'2$)1'U@N0T!/6#[_"0EVG@_].4$T`(D),B +M=`/P@"'OTY0+0`B0DR)T`O"`$^_3E`-`")"3(G0!\(`%Y)"3(O"0DR+@D`2Q +M\"(2)&+U:2+3$*\!P\#0D``!$D(@D)=Z\)```Q)"()"7;/`2)&)E:F`#$DWQ +MT-"2KR(2)&+U$<.4(%`5D``"$D(@_W0C)1'U@N0TE?6#[_`BY1&T(`J0``(2 +M0B"0DR'P(I```A)"()"7//#@8`3@]'`AHJ_D,_41PJ^0`$?@5/O]?T<21R!] +M0'\!$C%FY1$D_Y*O(I`"">#]$B1B_J\%[2Z0EX#PD``!$D(@_^TOD)>!\)`` +M`A)"(/_M+Y"7@O"0``,20B#_[2^0EX/PD``$$D(@_ZX%[2^0EX3P(N3U:9"7 +M?/#U:I"7>70,\)"7=_#DD)=Z\)"7=O"0EW7PD)=X!/"0EVWPY)"7>_"0EV_P +MD)=T=`?PY)"7;O"0EW+PHW0"\.20EW'PD)=L\"+DD)=[\)"7;O"0EWSP(N57 +M<#>0EWG@5`_3E`%0+)`"A^!P)I"7AN"T`A"0EWW@_J/@]8*.@^!@"(`/D`&O +MX'`)D)=QX&`#?P$B?P`BD``KX$0!\'_H?@,2,A60``C@1!#]?P@21R"0``G@ +M5/?]?PD21R"0`"C@5/[]?R@21R"0`"#@5/[]?R`21R"0`"7@1$#]?R421R"0 +M``G@5._]?PD"1R"0`"7@5+_]?R421R"0`"#@1`']?R`21R"0`"C@1`']?R@2 +M1R"0`/#@,.'YD``)X$0(_7\)$D<@D``(X%3O_7\($D<@D``KX%3^_7\K$D<@ +M?^A^`P(R%8]LD)>#$D9=Y6Q@$'0A+_6"Y#3\]8/@1!#P@`YT(2_U@N0T_/6# +MX%3O\)`$'W0!\"+OPY0@4#GO,.`7[<14\/WOPQ/^)*3U@N0T!/6#X%0/@!#O +MPQ/^)*3U@N0T!/6#X%3P\'2D+O6"Y#0$]8/@3?`BY/41=?`)Y1&0DRH20U_@ +M9`%@`N%AY1$EX"3`]8+D-)'U@^#^H^#3E`#NE`!0`N%AY1%U\`JD)`#Y=)`U +M\'46`?47B1CE$27@),#U@N0TD?6#X/^CX)"75L_PH^_PY1$EX"1C]8+D-)3U +M@^#_H^"0EUC/\*/O\'2$)1'U@N0T!/6#X%0_D)=2\.#^5!^C\'7P">41D),G +M$D-?X)"76_!T9"41]8+D-);U@^##E`5``H$[D)=;X/^0EU/@GT`3D)=;X)"7 +M4_#N5$#^D)=2\.].\)`$_>!D`7`ID)=3X/^004J3_G0C)1'U@N0TE?6#X,.> +M0`;OD$#:@#"0EU/@D$#V@">0EU/@_Y!!2I/^=",E$?6"Y#25]8/@PYY`!N^0 +M01*`!Y"74^"002Z3D)=:\)"76N!U\`:D)%#Y=$`U\'43__44B160EU+@D$'R +MD__3D)=9X)^0EUC@E`!`">3]KQ$2:5K!^.41)>`DX?6"Y#22]8/@]1FCX/4: +MJQ.J%*D5$B1B_WX`JQ:J%ZD8$D*7_:SP$B1[[R4:]1KN-1GU&:L3JA2I%9`` +M`1)"(/]^`*L6JA>I&)```A)"POVL\!(D>^\E&O4:[C49]1FK$ZH4J160``(2 +M0B#_?@"K%JH7J1B0``020L+]K/`2)'OO)1KU&NXU&?49JQ.J%*D5D``#$D(@ +M_WX`JQ:J%ZD8D``&$D+"_:SP$B1[[R4:]1KN-1GU&:L3JA2I%9``!!)"(/]^ +M`*L6JA>I&)``"!)"POVL\!(D>^\E&O4:[C49]1FK$ZH4J160``420B#_?@"0 +MEU;@_*/@_1(D>]/E&I_E&9Y`#.4:G_4:Y1F>]1F`!>3U&?4:Y1$EX"3A]8+D +M-)+U@^49\*/E&O"0EU+@)>`D9O6"Y#1!]8/#=`&3E1KDDY494`:O$?%MP`DGO6"Y#1!]8/3=`&3E1KDDY494`+!S'T!KQ$2:5K!S'1D)1'U@N0T +MEO6#X/QD!6`"H=:0DR+@_[0#"Y"74^##E!E`/8`N[[0""Y"74^##E!%`+H`? +MD),BX/^T`0N0EU/@PY0*0!N`#.]P$9"74^##E`-`#9"50W0!\(`%Y)"50_!T +M0R41]8+D-)3U@^#U&W0C)1'U@N0TE?6#X/_#E#!0`J&#D)5#X&0!8`*A@W1$ +M)1'U@N0TE?6#X&0*8%'O)`7_Y#/^="$E$?6"Y#22]8/@_=.?[F2`^'2`F%`R +M[20%_^0S_G0C)1'U@N0TE?6#X-.?[F2`^'2`F%`4=(0E$?6"Y#26]8/@_Y"7 +M4^!O8#UT(R41]8+D-)7U@^#_TY1"0`5U&P6`#N_3E#E`!74;`X`#=1L!="$E +M$?6"Y#22]8/O\'1$)1'U@N0TE8`I=&0E$?6"Y#26]8/D\'1$)1'U@N0TE?6# +MX`3P@!#D]1MT9"41]8+D-);U@^3PD)=3X/]TA"41]8+D-);U@^_P=$,E$?6" +MY#24]8/E&_!U\`GE$9"3*Q)#7^"T`1#D]1MT9"41]8+D-);U@^3PK1O!R.QD +M!F`"PI&'7P`N42I/6"A?"#$D+"_:SPY1*00@Z3_WX`$B1[[R4: +M]1KN-1GU&<.0EU7@E1J0EU3@E1E`!P42Y1*T!;WE$L,3]1+E&[0!!N42<$:` +M$^4;M`,5Y1)P!74;`X`YY1*T`05U&P&`+X`JY1NT!2CE$G`%=1L%@`WE$K0! +M!74;`X`#=1L!TY"76>"4`Y"76."4`$`#Y/4;TY"76>"4`Y"76."4`$`#Y/4; +M=$,E$?6"Y#24]8/E&_#]KQ$Q)'1D)1'U@N0TEO6#X-.4!71D4`XE$?6"Y#26 +M]8/@!/"`"R41]8+D-);U@^3PJQ:J%ZD8Y/7P$D+ZJQ:J%ZD8D``"Y/7P$D,9 +MD``$Y/7P$D,9D``&Y/7P$D,9D``(Y/7P$D,9Y1$EX"3`]8+D-)'U@^3PH_#E +M$27@)&/U@N0TE/6#Y/"C\.41)>`DH_6"Y#24]8/D\*/P!1'E$<.4(%`"(6S#E!!`(>PD\/]T`7X`J`<(@`7#,\XSSMCY +M_Y"77>!>_J/@7TYP(^S#E!!0.70!?@"H!`B`!<,SSC/.V/G_D)=?X%[^H^!? +M3F`<[&038`CL9!)@`[P1"9"77>`PX`)\&*T$C1R`-`R`BY"77.#\;7!I=*4I +M]8+D-);U@^WP=?`)Z9"3*1)#7^"T`0SE'"#F!^U$0/4<@`.O'"+M)>`DGO6" +MY#1!]8/DD_YT`9/_[27@)&;U@N0T0?6#=`&3+__DDS[#$_[O$__I)>`DX?6" +MY#22]8/N\*/O\(!;[=.<0%:0EUS@_W2E*?6"Y#26]8/O\*T'CQSM)>`DGO6" +MY#1!]8/DD_YT`9/_[27@)&;U@N0T0?6#=`&3+__DDS[#$_[O$__I)>`DX?6" +MY#22]8/N\*/O\*\<(G0!*?6"Y#22]8/D\.4<1(#_=(0I]8+D-`3U@^_P(JH' +M=(0J]8+D-`3U@^!4?_M4'_F0EU[P=?`)ZI"3*!)#7^"0EV#P=?`)ZI"3)Q)# +M7^"0EV'P_.HEX"3D]8+D-)7U@^#_H^"0EV+/\*/O\.HEX"2!]8+D-)+U@^#_ +MH^"0EV3/\*/O\.G3G$`)D)=AX)"77O#[[7`"09V0EU_M\.LPY@F0EU[@^Z/@ +M%/"0EU_@<`)!G9"77N#_TY0`4`)!G>20EUWP[Q20EUSPD)=@X/F0EUS@_M.9 +M0'+NE!!`)>XD\/]T`7X`J`<(@`7#,\XSSMCY_Y"79.#\H^#][%[^[5].<"N0 +MEUS@_\.4$%`V=`%^`*@'"(`%PS/.,\[8^?^0EV+@_*/@_>Q>_NU?3F`5D)=< +MX/NCX`3PD)=?X/^0EUW@;V`(D)=##GU`,D)=`DX?6"Y#22]8/N\*/O\'2$*O6"Y#0$]8/K\/\BD`1$=!'P +MHW3P\*-T#_"CY/#]=*0M]8+D-`3U@^3P#;T0\.3]=?`*[9"0`!)#7^3PH_!U +M\`KMD)`"$D-?Y/"C\'7P"NV0D`020U_D\*/P=?`*[9"0!A)#7^3PH_!U\`KM +MD)`($D-?Y/"C\'2$+?6"Y#26]8-T$_!T1"WU@N0TE?6#Y/!T0RWU@N0TE/6# +MY/#M)>`DP/6"Y#21]8/D\*/P[27@)&/U@N0TE/6#Y/"C\.TEX"3C]8+D-)3U +M@^3PH_#M)>`DH_6"Y#24]8/D\*/P[27@)&3U@N0TE?6#Y/"C\.TEX"2D]8+D +M-)7U@^3PH_!T1"WU@N0TEO6#Y/!T)"WU@N0TEO6#Y/!T9"WU@N0TEO6#Y/"0 +M0<23_G0!D_^008QT`9,O_^23/L,3_N\3_^TEX"3A]8+D-)+U@^[PH^_P=?`) +M[9"3*A)#7W0!\'7P">V0DRD20U]T`?!TP2WU@N0TDO6#=`SP=?`)[9"3)1)# +M7W3_\*/P=?`)[9"3(Q)#7^3PHW0/\'7P">V0DR<20U]T$_!U\`GMD),H$D-? +MY/!TA"WU@N0T!/6#=!/P#>UD(&`"80\BD`8T=/_PY*/PH_"C\"(BY)"7A?"B +MKS.0EU/PD`"`X"#A&A(R*Q(R*Y"74N!D`?#@)*V0`<3P=&RC\(#?D`8P=`'P +MPJ^0`(#@1(#P$D36D)=3X"3_DJ\BCA&/$HL3BA2)%>20EU+P[Y``,?`21-;E +M$50#_Y``,N!4_$_P$D36D``SX%1_\!)$UI``,^`@YPZ0EU+@PY1D4`7@!/"` +MZY"74N##E&10$)``,."K$ZH4J1420DU_`2)_`"+D]28B?PNQON]E)F`0Y2:T +M`07D]2:``W4F`7\!(G\`(N4C9`%P0+%;OP$%?P$21.:0`$;@1`3]?T821R"0 +M`$3@5/O]?T021R"0`$;@5/O]?T821R!_`K&^CR>0`_PTY0'4$?@_W0!J`<(@`+#,]C\]/^0`$;@7_`21-:0EZ7@_70! +M?@"H!0B`!<,SSC/.V/G_D`!$X/OD_N];J`4(@`;.HN<3SA/8^/^`1)"7I>`D +M^/#@_W0!J`<(@`+#,]C\$D3.D)>EX/UT`7X`J`4(@`7#,\XSSMCY_Y``0N#[ +MY/[O6Z@%"(`&SJ+G$\X3V/C_T-"2KR+DD)>=\*/PD`7XX'`/H^!P"Z/@<`>C +MX'`#?P$BTY"7GN"4Z)"7G>"4`T`#?P`B?S)^`!(R%9"7G>1U\`$20H&`QI`` +M$>!$"?`21-:0EQT20U.0@)82)0A_>'X($BL(D)3]_Q(P+)"7A^"T`1&0@&@2)10``RV5Y/U_`1(P+")_>'X($B)ED)<= +M$B4(?P1^#!(B99"7(1(E"'\`?@@2(F60ER42)0B0EX?@D)<=M`$-$D-3[U3' +M_^U4Q_V`!Q)#4^]4Q__LD("6$B4(?WA^"!(K")"7(1)#4^]4#__LD("6$B4( +M?P1^#!(K")"7)1)#4^]$`O_LD("6$B4(?P!^"!(K"']P?@X2(F60ERD2)0B0 +M@)82)10`&R6@?W!^#A(K")"`:!(E%`````#D_?\2,"R0EX?@M`$1D(!H$B44 +M`````.3]?P$2,"R0`!'@5/;P`D36D)>'X)"7+?`B[W`"(;&0ERW@8`*A?)"7 +M&1)#4Y"`EA(E"'^,?@@2*PB0EL420U.0@)82)0A_1'X($BL(D);)$D-3D("6 +M$B4(?UQ^"!(K")"6S1)#4Y"`EA(E"']L?@X2*PB0EM$20U.0@)82)0A_<'X. +M$BL(D);5$D-3D("6$B4(?W1^#A(K")"6V1)#4Y"`EA(E"']X?@X2*PB0EMT2 +M0U.0@)82)0A_?'X.$BL(D);A$D-3D("6$B4(?X!^#A(K")"6Y1)#4Y"`EA(E +M"'^$?@X2*PB0END20U.0@)82)0A_B'X.$BL(D);M$D-3D("6$B4(?XQ^#A(K +M")"6\1)#4Y"`EA(E"'_0?@X2*PB0EO420U.0@)82)0A_U'X.$BL(D);Y$D-3 +MD("6$B4(?]A^#A(K")"6_1)#4Y"`EA(E"'_9$B4(D)>9$D-3[43`_>R0EYD2)0B0EYD20U.0@)82)0A_C'X( +M$BL(D("6$B44``$``']$?@@2*PB0@)82)10`VR6D?UQ^"!(K")"`EA(E%"#; +M):1_;'X.$BL(D("6$B44(-LEI']P?@X2*PB0@)82)10$&R6D?W1^#A(K")"` +MEA(E%`0;):1_>'X.$BL(D("6$B44!!LEI']\?@X2*PB0@)82)10$&R6D?X!^ +M#A(K")"`EA(E%&/;):1_A'X.$BL(D("6$B44!!LEI'^(?@X2*PB0@)82)10@ +MVR6D?XQ^#A(K")"`EA(E%"#;):1_T'X.$BL(D("6$B44(-LEI'_4?@X2*PB0 +M@)82)10@VR6D?]A^#A(K")"`EA(E%``;):1_W'X.$BL(D("6$B44`!LEI'_@ +M?@X2*PB0@)82)10DVR6D?^Q^#A(K"'\$?@P2(F60EYD2)0B0EYD20U/D_^R0 +MEYD2)0B0EYD20U/O1!'_[)"7F1(E")"7F1)#4Y"`EA(E"'\$?@P2*PA_!'X- +M$B)ED)>9$B4(D)>9$D-3[U3P_^R0EYD2)0B0EYD20U/O1`'_[)"7F1(E")"7 +MF1)#4Y"`EA(E"'\$?@T2*PA_#'X)$B)ED)>9$B4(D)>9$D-3Y/_LD)>9$B4( +MD)>9$D-3[T01_^R0EYD2)0B0EYD20U.0@)82)0A_#'X)$BL(?PQ^"1(B99"7 +MF1(E")"7F1)#4^U4#_WL5/#\D)>9$B4(D)>9$D-3[400_>Q$`?R0EYD2)0B0 +MEYD20U.0@)82)0A_#'X)$BL(?P1^"!(B99"7F1(E")"7F1)#4^]4\/_LD)>9 +M$B4(D)>9$D-3[T0!_^R0EYD2)0B0EYD20U.0@)82)0A_!'X($BL(Y)"7+?`B +MTQ"O`?[_#3E`=09>#_=`&H!PB``L,SV/ST_Y``1^!?\!)$ +MUI"7G^#_=`&H!PB``L,SV/S_D`!&X$_P$D36D)>@X&`6D)>?X/]T`:@'"(`" +MPS/8_/^0`$6`:)"7G^#_=`&H!PB``L,SV/ST_Y``18!MD)>?X"3X\.#_=`&H +M!PB``L,SV/S$5/`21,Z0EY_@_W0!J`<(@`+#,]C\_Y``0^!/\!)$UI"7H.!@ +M&Y"7G^#_=`&H!PB``L,SV/S$5/#_D`!"X$^`&I"7G^#_=`&H!PB``L,SV/S$ +M5/#T_Y``0N!?\!)$UM#0DJ\BBQ&*$HD3D``"$D(@D)<[\.`PX$N0ES)T`?!_ +M@'X($B)ED)D`!'X%3S_7]'$D<@D`!(X%3S_7]($D<@D`!&X%3O_7]& +M$D<@Y)"7./`BY/U_11)'()`$_>3PH_"0ESSPD)="\)"71?"0ET/PD)=&\)"7 +M1/"0ET?PD)!$P/U_40)'()"73.!D`6`)D)`$\(`DD)=#X,.4 +M_U`&X`3PY(`1D)=$X,.4_U`,X`3PY)"70_"0ET+PD`!$X##C,I"71>##E/]0 +M!>`$\(`DD)=&X,.4_U`&X`3PY(`1D)='X,.4_U`,X`3PY)"71O"0ET7PD`3] +MX$0!\"*0``(20B"0ESKPD``!$D(@)>`EX)"7.?`2)&(EX"7@D)<]\)`%8."0 +METCPD`5AX)"72?"0!6+@D)=*\)`%8^"0ETOPHJ_D,Y"77?#"KY"7.>#_$DIB +MD)==X"3_DJ^0ESK@<`(AB9"7.>!P`B&)D)<]X'`"(8FBK^0SD)==\,*OD)=, +M=`'PD)==X"3_DJ\21Q>0`$;@1`']?T821R"0ES+@8!60ESX20U.0@)82)0A_ +M@'X($BL(@`:0!2)T?_"0`$7@5._]?T421R"0!8?@9(#PD)=(X)`%A/"0ETG@ +MD`6%\)"72N"0!8;PD)=+X)`%A_"BK^0SD)==\,*OD`$\X$0@\'T@Y/\2,;>` +M+9"7.N!P+Y"73!)'%I``1N!4_OU_1A)'()`%(N3PHJ\SD)==\,*O?2#D_Q(Q +-29"77>`D_Y*O(@"'%P`` +` +end diff --git a/sys/contrib/dev/rtwn/rtwn-rtl8192cfwU_B.fw.uu b/sys/contrib/dev/rtwn/rtwn-rtl8192cfwU_B.fw.uu new file mode 100644 index 000000000000..f10422445ca6 --- /dev/null +++ b/sys/contrib/dev/rtwn/rtwn-rtl8192cfwU_B.fw.uu @@ -0,0 +1,366 @@ +begin 444 rtwn-rtl8192cfwU_B.fw.uu +MPH@"`%@``@`'%11$K#\!`,S,S,P````````````````"19L````````````` +M`````````EE4```````````````````````````````````````````````` +M`````````````F2,```````"2[(```4$`P(``P8%!`,`!`8%!`(`!`@'!@0` +M!@H)"`8`"`H)"`0`"`H)"`(`"`H)"```"!(1$`@`$!H9&!``&"(A(!@`("(A +M(!``("(A(`@`("(A'`@`("(A%`@`("(@&`@`(#$P(!``,#$P&```,#$O$!`` +M,#$L$!``,#$H$```,#$@$```,#$0$```,`0$!`4$!`0%!04&!@0$!`4%!08& +M!`0%!04%!@8$!`4%!04&!PH+#1`$!04&!@D,$0@("0D*#!`1!`0$!00$!0<' +M!P@*!`0$!`8*"PT%!0<'"`L-#P0$!`4'!PD)#`X0$@8'"0H,#A$3"0D)"0P. +M$1,````````````D)BH8&AT?(2`"@`,@!0`&0`>`",`$L`4`!X`+0`^@$L`9`!]```@`" +M``0`"``,`!(`&``D`#``2`!@`&P`*``\`%``9`"@`,@`\`$8`&0`H`#P`6@! +M]`)8`R`#Z`("`@("`@,#!`0%!P(#!`H,#A`2!0<'"`L2)#P!`0$!`0(#!`4& +M!P@!`@,$!08'"`4&!P@)"@L,(!X<&!`8````````````````NP$,Y8(I]8+E +M@SKU@^`B4`;I)8+XYB*[_@;I)8+XXB+E@BGU@N6#.O6#Y),BNP$&B8**@_`B +M4`+W(KO^`?,B^+L!#>6"*?6"Y8,Z]8/H\")0!NDE@LCV(KO^!>DE@LCR(L7P +M^*/@*/#%\/CE@A6"<`(5@^`X\"*[`0J)@HJ#X/7PH^`B4`:'\`GG&2*[_@?C +M]?`)XQDBB8**@^23]?!T`9,BNP$0Y8(I]8+E@SKU@^#U\*/@(E`)Z26"^(;P +M".8BN_X*Z26"^.+U\`CB(N6#*O6#Z9/U\*/IDR*[`0J)@HJ#\.7PH_`B4`;W +M":?P&2*[_@;SY?`)\QDB^+L!$>6"*?6"Y8,Z]8/H\.7PH_`B4`GI)8+(]@BF +M\"*[_@GI)8+(\N7P"/(B[TO_[DK^[4G][$C\(N#\H^#]H^#^H^#_(J0E@O6" +MY?`U@_6#(N#[H^#ZH^#Y(OC@^Z.CX/DE\/#E@A6"<`(5@^#Z./`BZ_"CZO"C +MZ?`BT(/0@OCDDW`2=`&3<`VCHY/X=`&3]8*(@^1S=`*3:&#OHZ.C@-_0@]"" +M^.23]D`6`(D`&Y=`'P@&[E)50#8`B0`;ET`O"`8.4C5`_3 +ME`)`")`!N70$\(!/Y24PX@B0`;ET"/"`0N4E,.0(D`&Y=!#P@#60DE?@8`B0 +M`;ET(/"`)Y"27.!@")`!N72`\(`9Y29@!Y`!N>3P@`Z0`;GD\)`!N'0$\'\! +M(I`!N'0$\'\`(@)%`P)%!GT!?PS3$*\!P\#0CV>-:.5G5`__Y2)4#V]@4B5`__OP0.Y6<@X@D21'SO +M8!022C/E(E0/_[\""1)+@N]@`Q)+,=#0DJ\B`D79`E%WY).C^.23HT`#]H`! +M\@C?](`IY).C^%0')`S(PS/$5`]$(,B#0`3T5H`!1O;?Y(`+`0($"!`@0("0 +M2T3D?@&38+RC_U0_,.4)5!_^Y).C8`$.SU3`)>!@J$"XY).C^N23H_CDDZ/( +MQ8+(RL6#RO"CR,6"R,K%@\K?Z=[G@+[D_^4D8'7E(60!<&_E)!1@*R3]8"`4\.!@!*/@8!20DE7@<`B0DF/@D))5\'\!@`)_`>]@.D,E +M$.20DH/PD))6X'7P`Z3_D))?X"^0DH3PY/O]?U1^`1)+EY`!5W0%\.4B5`_# +ME`10!WT!?P0210TBY2%D`7!GY21@8^4D9`)@!N4D9`5P)Y`&J^"0DE7PD`:J +MX)"28_"0DE7@<`>0DF/@_X`%D))5X/^0DE7O\)"25^!@`N3PY)"25O"0!5AT +M`_"0`5?D\)`!/'0"\%,E_5,E[^4D%"3]4`*``Q)'""+DD)(0\)`&J>"0DA#P +MX%3`<`E3)?Y3)?T22WN0DA#@,.850R4!D))DX&0"8`422LR`"!))\X`#4R7^ +MD)(0X##G)T,E`N20DH/PD));X)"2A/#D^_U_5'X!$DN7D`%7=`7PD))E=`'P +M(E,E_2+O9`%P,'UX?P(2-G5]`G\#$C9UD`%7Y/"0`3QT`O`210GD_Q)8II`& +M!.!4?_"0!@K@5/CP(I`!-G1[\*-T`O!]>_\2-N9]`G\#$C;FD`8$X$2`\)`& +M"N!$!_`22W#E(2#@!>20DE?P(I"2*1)#BQ)+9)"2*1)#:Q(IV?4D%&`.%&`? +M%&`Q)`-P1'\!@#V0DBD20VN0``(20B#]Y/\22F6`*9"2*1)#:Y```A)"(/U_ +M`1)*91^`%)"2*1)#:Y```A)"(/U_`A)*9>3_$D=T(N3U)?4D=2,,=2(,D))D +M\)"28O"0DF'PD))C!/"0DE7PY)"29?"0DE?PD))?=`7PY)"25O"0DEWPHW0# +M\)"26O"C=`7PD))9=!3PD))@=`7PY)"26/"0DE3PD))]\)"27/`B$DM5[V0! +M8`B0`;ET`?"`1Y"28N!@")`!N70"\(`YD))AX&`(D`&Y=`3P@"OE(U0/TY0$ +M0`B0`;ET"/"`&N4F8`B0`;ET(/"`#I`!N>3PD`&X=`CP?P$BD`&X=`CP?P`B +MY)"2%O#E)&!)D))EX&`-Y/!3)?WE)50'<#B`,Y"25N`$\%,E[Y"2%N#_D)): +MX"__Y#/^D))6X-.?[F2`^'2`F$`-Y2&T`0NCX'`'X`3P(A)+>R+E)!0D_5`" +M@$>0DF3@8"P210GDD)*#\)"26>"0DH3PY/O]?UA^`1)+EY`!6W0%\)`&DG0! +M\)"28O"`$.4B5`_#E`10!WT!?P0210WD_Q)8IB+3$*\!P\#0CV.0!!W@8"20 +M!2+@]69T__`2=F6_`0V0DGC@_WT!$E@*$D/GD`4BY6;P@`V0DGC@_WT!$E@* +M$D/GD`0?="#PT-"2KR*0`5_D\)`!/'0(\.20DH/PD))9X)"2A/#D^_U_7'X! +M$DN7D`%?=`7PD`:2=`+PD))A%/#E(E0/PY0,4`,210DBD`$W=`+PD`4B=/_P +M$G9E[W`&D`'(=/WP?0)_`Q(VYN4D8`5_`1)8IA)W&U,B\$,B`B+O)/Y@"P1P +M(I"28W0!\(`6[7`*D))@X)"28_"`!9"28^WPD))CX)"25?`B[V`/="$M]8+D +M-/SU@^!$$/`B="$M]8+D-/SU@^!4[_`BD`8$X%2_\.]@"N4AM`$%Y/\22:A3 +M(O!#(@PBD`0=X'`4D))WX/_D_1)8"HYICVJ0!!]T(/`BD)*I[_`2=J:0DJG@ +M8`60!2+D\%,B\$,B!"*0!@3@1$#PY2&T`05_`1))J%,B\$,B!"+E(S#F$N4C +M5`__D`$OX%2`3V2`\%,COR)3(O!#(@$22X422X93(O!#(@(B09)U`$&2J`!! +MDJH`09*B``"0!!O@5']D?W\!8`)_`"+DD))E\)"25O#U)2*0DEW@H^"0!5CP +M(GT!KR,"10U_`"(B(O"0DEG@D)*$\.3[_7]8?@'3$*\!P\#0D)*#X/NCX/5$ +MY/5%$C6KT-"2KR+`X,#PP(/`@L#0==``P`#``<`"P`/`!,`%P`;`!W4.`%.1 +MWY`!/.!5,/4TH^!5,?4UH^!5,O4VH^!5,_4WY30PX`:0`3QT`?#E-##A")`! +M/'0"\#$$Y30PXBR0`3QT!/#E)&`BD`:2X##@%)"2@^1QAY`!6W0%\)`&DG0! +M\(`'D))BY/!Q>^4T,.,\D`$\=`CPY21@,I`&DN`PX220DH/D\)"26>"0DH3P +MY/O]?UQ^`7&7D`%?=`7PD`:2=`+P@`>0DF'D\'%[Y30PY`B0`3QT$/"1]N4T +M,.4)D`$\="#P$E._Y34PX!:0`3UT`?"0`(/@]2.0`;OE(_!Q&7%[Y34PX@:0 +M`3UT!/#E-3#D!I`!/700\.4V,.`&D`$^=`'PY38PX0:0`3YT`O#0!]`&T`70 +M!-`#T`+0`=``T-#0@M"#T/#0X#+E7F0!<#OQN[\!!'\!\:^0`$;@1`3]?T:Q +M0I``1.!4^_U_1+%"D`!&X%3[_7]&L4)_`O'ZCV*0`20DC_PD)([$D-3 +MD("%$BI_?X!^"!(OV9``1>!$[_U_1;%"D`!%X%3O_7]%L4*0`$;@1!#]?T:` +M.)"2/W0!\)"211)#4Y"`A1(J?W^`?@@2+]F0`$7@1"#]?T6Q0I``1>!$$/U_ +M1;%"D`!&X$00_7]&L4(BD``"$D(@D))!\)```1)"("7@)>"0DD#P$BG9)>`E +MX)"21/"0!6#@D))/\)`%8>"0DE#PD`5BX)"24?"0!6/@D))2\**OY#.0DB7P +MPJ^0DD#@_Q)3;9"2)>`D_Y*OD))!X'`"X0:0DD#@<`+A!I"21.!P`N$&HJ_D +M,Y"2)?#"KY"24W0!\)"2)>`D_Y*OL3F0`$;@1`']?T:Q0I"2.>!@%9"211)# +M4Y"`A1(J?W^`?@@2+]F`!I`%(G1_\)``1>!4[_U_1;%"D`6'X&2`\)"23^"0 +M!83PD))0X)`%A?"0DE'@D`6&\)"24N"0!8?PHJ_D,Y"2)?#"KY`!/.!$(/!] +M(.3_$C<`@"N0DD'@<"V0DE.Q.)``1N!4_OU_1K%"D`4BY/"BKS.0DB7PPJ]] +M(.3_$C:2D)(EX"3_DJ\BD`$\=/_PH_"C\)`!-/"C\*/PH_#]?U2Q0GW_?U6Q +M0GW_?U:Q0GW_?U>A0I`!,.3PH_"C\*/PD`$X\*/PH_"C\/U_4+%"Y/U_4;%" +MY/U_4K%"Y/U_4Z%"D`!)X)"2J_#@5`_P1/#]?TFQ0I"2J^!$L/U_2:%"D`'* +MY6'P[V`"\9$B?POQ^N]E86`0Y6&T`07D]6&``W5A`7\!(G\`(N20DGOPD`"` +MX$2`_7^`H4+@7_#3$*\!P\#0?Q#?_M#0DJ\BTQ"O`0DJS@_70!?@"H!0B`!<,SSC/.V/G_D`!$ +MX/OD_N];J`4(@`;.HN<3SA/8^/^`3)"2K.`D^/#@_W0!J`<(@`+#,]C\]/^0 +M`$/@7_`23^J0DJS@_70!?@"H!0B`!<,SSC/.V/G_D`!"X/OD_N];J`4(@`;. +MHN<3SA/8^/_0T)*O(I`"A._PH^[PHW0%\"+OCO`20[I0RP!`4/,`@%$>`0!1 +M,@(`44H$````46?M5#]P!/[_@`1^`']`[RW_[CS^[W@&SL,3SA/8^7@&PS/. +M,\[8^8`F[51_<`3^_X`$?@!_@.\M_^X\_N]X!\[#$\X3V/EX!\,SSC/.V/G] +MK`:`2>UP!/[_@`1^`7\`[RWN/'T`_(`U[%0!37`$_O^`!'X"?P#O+>X\PQ-] +M`(`:[%0#37`$_O^`!'X$?P#O+>X\$Q-4/WT`)>`EX/RN!*\%(I`!Y'18\*-T +M`O`BY)"2%_"C\'6.`A)/U]&ED))\[_#1F9"2?N_PT>V0DG/N\*/O\.3U5?4A +M$G#6T9`22$(2,CW1A1)/.O$%T<#1B='5T811)Q)^=)"2&>79\,*OD`"`X$1` +M\!)/ZG7H`T.HA=*O,6R0DA?@9`'PY54PY`G"KU-5[]*OD77E53#F%L*O4U6_ +MTJ\2:;R0DD/@_V`#M`$"46N0DD/@<`,2?M)1/Y`!O>4B\)"29."0`;SP@+60 +MDJ/@5/[PY)"2I?"0DJ/@5'_PHW0*\"*0!C3@8"4435_^7X!$G8# +MOP$)D`8UX%0/\(`$@`#!LN20!C3P(I"2.N##E!10!>`$\&$CD)(ZX&048`)A +M(Y"22>!P)9"23.!P'Y"22N!P&9"23>!P$Y"22^!P#9"23N!P!Y`$_>!4_O"0 +MDDG@D`1$\)"22N"0!$7PD))+X)`$1O"CY/"0DDS@D`1(\)"23>"0!$GPD)). +MX)`$2O"CY/"0DC7@D`1,\)"2-N"0!$WPD)(WX)`$3O"0DCC@D`1/\.20DCKP +MD)(U!/#DH_"C\*/PD)))\*/PH_"C\*/PH_"0!6#@D)(:\)`%8>"0DAOPD`5B +MX)"2'/"0!6/@D)(=\)"24N#_D)(=X/[3GU`+D))2X,.>TY0!0!"0DD#@M`$" +M@`.0DD3@_W%M(I`%8."0DD_PD`5AX)"24/"0!6+@D))1\)`%8^"0DE+PPW3_ +MG_Z0DE#@TYY`'N`O\*/@M/\/Y/"CX+3_`^3P(I"24H`#D))1X`3P(I"24.`O +M\"*0DD'@9`%@`H%TD`!&X$0!_7]&$DU"D))3X'`RD)(YX&`5D))%$D-3D("% +M$BI_?X!^"!(OV8`&D`4B='_PD))`X/]Q;9"24W0!$DTX@$"0DE/@9`%P.)"2 +M1.#_<6WDD))3\)``1>!$`?U_11)-0I"2.>!@%9"2.Q)#4Y"`A1(J?W^`?@@2 +M+]F`!9`%(N3PD`6'X&2`\)"23^"0!83PD))0X)`%A?"0DE'@D`6&\)"24N"0 +M!8?P(M,0KP'#P-"0`DG4?&W4@`7L! +M>I)Y'+'"D)(\)"2J.!U\`20`=,20U_@D)(?\.]4?_][`7J2>1T27 +MJ1^0DH@20XNO(!4@[V`>D)*(Y'7P`1)#=!(IV?^0DH7D=?`!$D-T[Q)"38#; +MJQJJ&ZDB1]U(`)[`7H!>:"QPI"2CA)#:XL=BAZ)'Y"2BQ)#:Q(IV?_$ +M5`_U('L!>@%YHK'"D`&O=/_PD)*JX`3PD`'+X&2`\-#0DJ\B(N3U82*0`61T +MH/`BD))^X)"2#_`BD`#SX'\`,.,"?P$BD``"X%3@?P%@`G\`(I`&-'3_\.2C +M\*/PH_`BD`#SX##B#9`%0700\)`%6O"CY/`B=3`?=3$!Y/4RD`$XY3#PH^4Q +M\*/E,O`BD))^X+0!#)``\N`PYP5^_7\S(G[]?R\B=2@SY/4I=2H']2N0`3#E +M*/"CY2GPH^4J\*/E*_`BD)(0X%3P1`/P5`]$@/![`'H`>5:0DHX20XL+>I)Y +M$,$1TQ"O`931$=#0DJ\BTQ"O`I)Y9GT"\430T)*O +M(H^"CH.CHZ/D\"+D]5Y_8'X!@.W3$*\!P\#0D`0=X&`:D`4BX%208`>0`<;@ +M1$#PD`''X##AY'\`@`)_`=#0DJ\BTQ"O`_PD)*7X&`?HZ/@ +M_R0/]8+D-/SU@^!$@/!T$"_U@N0T_/6#X$2`\)"2F*/@__TD"/6"Y#3\]8/D +M\'0)+?6"Y#3\]8/@5/#P="$O]8+D-/SU@^!4]_"0DIC@_J/@_]#0DJ\B[V`+ +MD))^X+0!$.3_@`F0DG[@M`$%?P$2=^4B$E?0`33@52CU+*/@52GU+:/@52KU+J/@52OU +M+^4L(.`"0=^0`31T`?"%T4V%TDZ%TT^%U%"%U5&%UE*%UU.%V53E5%1`PQ/_ +MY5-4(&]P`D&515!__Y0@EX"3$]8+D-(WU +M@^2/\!)"@>535!__Y0@EX"2`]8+D-(?U@^2/\!)"@>4)TY0$0`-U"01U\`KE +M")"$`!)#7W7P`N4)$D-?X/ZCX/_E4U0?+__D/OYU\`KE")"$`!)#7W7P`N4) +M$D-?[O"C[_#E5"#F(^535!__Y0@EX"3$]8+D-(SU@^2/\!)"@>5/,.535!_U#:L) +MKPB1F^4D%"3]4`*`.I"29.!@*Y`!6^3PD`$\=`3P$DM5[V0!<"&0DH,22X>0 +M`5MT!?"0!I)T`?"0DF+P@`D22U6_`0,22WOE+##A(9`!-'0"\(715H725X73 +M6(7468756H766X777(7971)7(^4L,.,&D`$T=`CPY2PPY`F0`31T$/!#51#E +M+##E)I`!S^`PY1_@5-_PD`$T="#P=:@`=>@`$D]ED``#X%3[\!)/ZH#^Y2PP +MY@:0`31T0/#E+C#@%)"2?70!\)`!-O`21AZ199"2?>3PY2XPX0N0`39T`O!# +M54`1U^4N,.()D`$V=`3P$D::Y2XPXSB0`39T"/#E(60!<"SE)&`HD`%7Y/"0 +M`3QT`O"0DH/D\)"26^"0DH3PY/O]?U1^`1)+EY`!5W0%\.4N,.0KD`$V=!#P +MY2&T`2#E)&`4E5`=P`Q)+>^4N,.4?D`$V +M="#PY2&T`13E)&`0D))DX&0"8`422LR``Q))\^4N,.8;D`$V=$#PY2&T`1#E +M)&`,4R7^Y254!W`#$DM[Y2\PX0F0`3=T`O`225?0!]`&T`70!-`#T`+0`=`` +MT-#0@M"#T/#0X#*0DJ/@,.`NY2&T`2F0DJ+@!/#@M`H+D)*EX`3PY)"2HO"0 +MDJ7@_Y"2I.#3GU`'L9'DD)*E\"*/"HT+Y0M4'Y"2$O!T`2_U@N0TB/6#X)"2 +M$/"0!/W@D)(3M`$%=`/P@`-T`?"0DA/@_^O#GT`$KPJ`/)"2$.`E#?^C\*/@ +MD$'6D_[OTYY`%'0!)0KU@N0TB/6#Y/"M"Z\*`E>`D)(1X/]T`24*]8+D-(CU +M@^_P(JT'=?`)[9"*2!)#7^#_D)(5\'1G+?6"Y#21]8/@5!^0DA3PTY]`!J/@ +MD)(4\)"2%.#_)>`DGO6"Y#1!]8/DD_IT`9/[[R7@)&;U@N0T0?6#=`&3*__D +MDSK#$_[O$__M)>`DPO6"Y#2)]8/N\*/O\*\%D)(4X/T25X"0DA3@_R+D_P)) +MJ)"2)1)#BQ(IV50!_Y"2H^!4_D_PX##@`K&1D)(E$D-K$BG9PQ,PX`J0``$2 +M0B"0DJ3P(I"2(A)#B^\20Y1>$`%>!P)>-`->/05>1@9>DP=>3@E>5PQ>8`U> +M:0Y>>QQ>&2U>(BY>A#!>*SL``%Z,D)(B$D-K`G-CD)(B$D-K`G-ID)(B +M$D-K`G.>D)(B$D-K`G/FD)(B$D-K`G0?D)(B$D-K`G0XD)(B$D-K`G+,D)(B +M$D-K@$:0DB(20VL"=("0DB(20VL"3?^0DB(20VL"?D&0DB(20VL"?6F0DB(2 +M0VL"#_=?`)D(I&$D-?K8*L@Y"2+.SPH^WP[W7P":0D1/ET +MBC7P^GL!HQ)#BY"2)Q)#:Y```Q)"(%0/_Y"2+A)#:^\20DV0DB<20VN0``(2 +M0B#_D)(N$D-KD``![Q)"7Y"2)Q)#:Y```1)"(/^0DBS@_*/@_?6"C(/O\!(I +MV8V"C(.C\)"2*N#^D)(EX/\D@O6"Y#2)]8/N\)"2)N#^=?`)[Y"*2A)#7^[P +M=?`)[Y"*2Q)#7W0!\)"2*^#^=?`)[Y"*3!)#7^[PCP_O)>`DQO6"Y#2/KX+U +M$(\1Y0]U\`*D)`+Y=(DU\'42`?43B11U\`GE#Y"*1A)#7Z^"A8,5CQ;E#W7P +M":0D1/ETBC7P=14/)>`DQO6" +MY#2/]8-T#_"C=/6`)^4/)>`DQO6"Y#2/]8-T#_"C=/"`$N4/)>`DQO6"Y#2/ +M]8/D\*-T#?#E#R7@)`+U@N0TB?6#Y/"C\"&5D`1'X*L2JA.I%!)"39`$1N"K +M$JH3J120``$20E^0!$7@A1&"A1"#\)`$1"&,D`1+X*L2JA.I%!)"39`$2N"K +M$JH3J120``$20E^0!$G@A1&"A1"#\)`$2(!8D`1/X*L2JA.I%!)"39`$3N"K +M$JH3J120``$20E^0!$W@A1&"A1"#\)`$3(`KD`13X*L2JA.I%!)"39`$4N"K +M$JH3J120``$20E^0!%'@A1&"A1"#\)`$4."%$8*%$(.C\*L2JA.I%,`#P`+` +M`1(IV?^K%ZH8J1D2*=E?T`'0`M`#$D)-JQ+E%"0!^>0U$_K``\`"P`$2*=G_ +MJQ>J&*D9D``!$D(@7]`!T`+0`Q)"3841@H40@\"#P(+@_X46@H45@^#^[U[0 +M@M"#\(41@H40@Z/`@\""X/^%%H*%%8.CX/[O7M""T(/PY0\EX"0"]8+D-(GU +M@^#^H^!.8$N0DC%T"_"0DC'@_\.4`%`"0=IT`7X`J`<(@`7#,\XSSMCY_^4/ +M)>`D`O6"Y#2)]8/@7OZCX%].8`J0DC'@)!"C\(!HD)(QX!3P@+OE#R7@),;U +M@N0TC_6#X/ZCX$Y@1Y"2,70/\)"2,>#_PY0`0#QT`7X`J`<(@`7#,\XSSMCY +M_^4/)>`DQO6"Y#2/]8/@7OZCX%].8`B0DC'@H_"`#9"2,>`4\("_Y)"2,O#E +M#R7@),;U@N0TC_6#X/ZCX$Y@1N20DC'PD)(QX/_#E!!``F&3=`%^`*@'"(`% +MPS/.,\[8^?_E#R7@),;U@N0TC_6#X%[^H^!?3F`&D)(QX(!CD)(QX`3P@+_E +M#R7@)`+U@N0TB?6#X/ZCX$Y@1N20DC'PD)(QX/_#E`Q0/'0!?@"H!PB`!<,S +MSC/.V/G_Y0\EX"0"]8+D-(GU@^!>_J/@7TY@")"2,>`D$(`)D)(QX`3P@+_D +MD)(S\)"2,N#_=?`)Y0^0BD@20U_O\)"2,^#^=?`)Y0^0BDD20U_N\.4/PY0@ +M4"QTA"4/]8+D-`3U@^#3GT`"@$=TA"4/]8+D-`3U@^##GE`(D)(SX*/P@#>` +M+72F)0_U@N0TD/6#X/^0DC+@_N_3GD`'D)(T[O"`%Y"2,^#^[\.>4`6C[O"` +M")"2,N"0DC3PD)(TX/VO#Q)7@)"2-.#_="8E#_6"Y#21]8/O\)"2,N#_TY03 +M0`>0BD-T`_`B[].4"T`'D(I#=`+P(N_3E`-`!Y"*0W0!\"+DD(I#\"+3$*\! +MP\#0Y/W\[S#@`GV`[\,3D/T0\*X$KP70T)*O(L#@P/#`@\""P-!UT`#``,`! +MP`+``\`$P`7`!L`'4Y'OD`!1X/^0`%7@7_4]D`!2X/^0`%;@7_4^Y3TPY`:0 +M`%5T$/#E/3#E!I``570@\.4],.8;D`!5=$#PD))"X%0#_[\#"Y"2/^!@!7\! +M$DU7Y3TPYQ60`%5T@/"0DD+@5`/_OP,%?P(235?E/C#@!I``5G0!\.4^,.$& +MD`!6=`+PY3XPX@:0`%9T!/#E/C#C!I``5G0(\-`'T`;0!=`$T`/0`M`!T`#0 +MT-""T(/0\-#@,N_#E"!0.>\PX!?MQ%3P_>_#$_XDI/6"Y#0$]8/@5`^`$._# +M$_XDI/6"Y#0$]8/@5/#P=*0N]8+D-`3U@^!-\"*M!^W#E"!0$W2$+?6"Y#0$ +M]8/@5'^0DBGP@!%TIBWU@N0TD/6#X%1_D)(I\)"2*>#Y5!^C\'7P">V0BD@2 +M0U_@_Y"2+/#M)>`D`O6"Y#2)]8/@^Z/@D)(MR_"CZ_#M)>`DQO6"Y#2/]8/@ +M^Z/@D)(OR_"CZ_"0DBK@_B7@)&;U@N0T0?6#Y)/Z=`&3^^TEX"3"]8+D-(GU +M@^KPH^OP[L.?0`+!^)"2*N#_=&XD\/]T`7X`J`<(@`7#,\XSSMCY_Y"2+>!>_J/@7TYP +M)Y"2*^#_PY004%ET`7X`J`<(@`7#,\XSSMCY_Y"2+^!>_J/@7TY@/)"2*^"T +M$0V0DB[@,.<&D)(K=!?PD)(KX/]D$V`$[[02#9"2+>`PX`:0DBMT&/"0DBO@ +MD)(J\)"2*?"`0I"2*^`$\,%6D)(LX/R0DBK@_VQP<71G+?6"Y#21]8/O\'7P +M">V0BDH20U_@M`$0Z2#F#)"2*N!$0)"2*?"``Z\!(I"2*N#_)>`DGO6"Y#1! +M]8/DD_IT`9/[[R7@)&;U@N0T0?6#=`&3*__DDSK#$_[O$__M)>`DPO6"Y#2) +M]8/N\*/O\(!FD)(JX-.<0%Z0DBS@_W1G+?6"Y#21]8/O\)"2*N_PD)(I\/RC +MX/\EX"2>]8+D-$'U@^23^G0!D_OO)>`D9O6"Y#1!]8-T`9,K_^23.L,3_N\3 +M_^TEX"3"]8+D-(GU@^[PH^_PKP0B=`$M]8+D-(CU@^3PKP60DBG@1(#]$E>` +MD)(IX$2`_R*L!^S#E"!0$W2$+/6"Y#0$]8/@5'^0DBGP@!%TIBSU@N0TD/6# +MX%1_D)(I\)"2*>!4'_^0DBSP=?`)[)"*21)#7^"0DB[P=?`)[)"*2!)#7^#^ +MD)(O\.PEX"3&]8+D-(_U@^#[H^"0DC#+\*/K\.PEX"0"]8+D-(GU@^#[H^"0 +MDC++\*/K\._3GD`,D)(OX)"2+/"0DBGP[7`"(6J0DBWM\)"2*>`PY@Z0DBS@ +MD)(I\)"2+>`4\)"2+>!P`B%JD)(LX/_3E`!0`B%JY)"2*_#O%)"2*O"0DB[@ +M_9"2*N#_TYU`;^^4$$`A[R3P_W0!?@"H!PB`!<,SSC/.V/G_D)(RX%[^H^!? +M3G`GD)(JX/_#E!!0-W0!?@"H!PB`!<,SSC/.V/G_D)(PX%[^H^!?3F`:D)(J +MX)"2*?"0DBO@!/"0DBW@_Y"2*^!O8`B0DBK@%/"`@Y"2+>#_D)(KX,.?4`^0 +MDBK@M04(D)(NX)"2*?"0DBG@_R7@))[U@N0T0?6#Y)/Z=`&3^^\EX"1F]8+D +M-$'U@W0!DRO_Y),ZPQ/^[Q/_["7@),+U@N0TB?6#[O"C[_"O!)"2*>#]$E>` +MD)(IX/\BY)"2&O"0DAK@_\.40$`#`G#5[[0@%)".Q>`$\)")`>#_D([%X+4' +M`N3PD)(:X/]U\`F0BDL20U_@9`%@`P)PS.\EX"2`]8+D-(?U@^#^H^#3E`#N +ME`!0`P)PS)"2&N"4($`)D([%X&`#`G#5D)(:X'7P"J0D`/ETA#7P=1(!]1.) +M%.#_)>`D@/6"Y#2']8/@_:/@D)(?S?"C[?#O)>`DQ/6"Y#2,]8/@_Z/@D)(A +MS_"C[_"0DAK@_\.4(%`3=(0O]8+D-`3U@^!4/Y"2&_"`%)"2&N`DIO6"Y#20 +M]8/@5#^0DAOPD)(;X/Y4'Z/PD)(:X/]U\`F0BD@20U_@D)(D\'3F+_6"Y#20 +M]8/@PY0%0`*A'I"2).#_D)(0`;OD$$2@`>0DAS@D$$N +MDY"2(_"0DB/@=?`&I"10^71`-?!U#__U$(D1D)(;X)!!\I/_TY"2(N"?D)(A +MX)0`0`V0DAK@_^3]$F?\`G!BD)(:X"7@),+U@N0TB?6#X/^CX)"2'<_PH^_P +MJP^J$*D1$BG9_WX`JQ*J$ZD4$D*7_:SP$BGRD)(=[H_P$D*!JP^J$*D1D``! +M$D(@_WX`JQ*J$ZD4D``"$D+"_:SP$BGRD)(=[H_P$D*!JP^J$*D1D``"$D(@ +M_WX`JQ*J$ZD4D``$$D+"_:SP$BGRD)(=[H_P$D*!JP^J$*D1D``#$D(@_WX` +MJQ*J$ZD4D``&$D+"_:SP$BGRD)(=[H_P$D*!JP^J$*D1D``$$D(@_WX`JQ*J +M$ZD4D``($D+"_:SP$BGRD)(=[H_P$D*!JP^J$*D1D``%$D(@_WX`D)(?X/RC +MX/T2*?+3D)(>X)^0DAW@GD`,H^"?\)"2'>">\(`'Y)"2'?"C\)"2'>#\H^#] +MD)(:X/\EX"3"]8+D-(GU@^SPH^WPD)(;X"7@)&;U@N0T0?6#Y)/Z=`&3^]/M +MF^R:0`8299L"<#"0DAO@)>`DGO6"Y#1!]8/DD_YT`9/_PY"2'N"?D)(=X)Y` +M`P)P,)"2&N#_?0$29_P"<#"0DAK@_R3F]8+D-)#U@^#\9`5@`L']D(I#X/ZT +M`PN0DAS@PY090#V`+NZT`@N0DAS@PY010"Z`'Y"*0^#^M`$+D)(20CH3PD)(:X/XDA/6"Y#2,]8/@D)(H +M\'1$+O6"Y#2.]8/@_L.4,%`*Y)"2*/!TYB_!IY".A.!D`6`"P9R0DAK@)(7U +M@N0TCO6#X&0*8%N0DAK@_^XD!?OD,_IT02_U@N0TB/6#X/_3F^ID@/AT@)A0 +M.)"2&N#^[R0%^^0S^G1$+O6"Y#2.]8/@TYOJ9(#X=("84!:0DAK@)";U@N0T +MD?6#X/^0DAS@;V!6D)(:X"1$]8+D-([U@^#_TY1"0`B0DBAT!?"`$>_3E#F0 +MDBA`!70#\(`#=`'PD)(:X/\D1/6"Y#2.]8/@_G1!+_6"Y#2(]8/N\)"2&N`D +MA?6"Y#2.@"^0DAK@_R3F]8+D-)#U@^3P=(4O]8+D-([U@^`$\(`4Y)"2*/"0 +MDAK@).;U@N0TD/6#Y/"0DAS@_I"2&N#_)";U@N0TD?6#[O"0DBC@_G2$+_6" +MY#2,]8/N\'7P">^0BDP20U_@M`$1Y)"2*/!TYB_U@N0TD/6#Y/"0DBC@_0)P +M+>QD!F`#`G`PD)(=\*/PD$(3D_]^`)"2'^#\H^#]$BGRD)(F[O"C[_"0DAK@ +M)(3U@N0TC/6#X)"2*/#DD)(E\)"2)>#_TY0$4$>K$JH3J11U\`+OI/6"A?"# +M$D+"_:SP[Y!"#I/_?@`2*?*0DAWNC_`20H&0DB;@_J/@_].0DA[@GY"2'>"> +M4`B0DB7@!/"`KY"2)>##$_"0DBC@_[0!#9"2)>!P79"2*`3P@%OOM`,=D)(E +MX/]P")"2*'0#\(!([[0!")"2*'0!\(`\@#60DBC@9`5P,I"2)>#_<`B0DBAT +M!?"`#^^0DBBT`05T`_"``W0!\-.0DB+@E`.0DB'@E`!`!>20DBCPTY"2(N"4 +M`Y"2(>"4`$`%Y)"2*/"0DBC@_9"2&N#_)(3U@N0TC/6#[?`295N0DAK@_R3F +M]8+D-)#U@^#3E`50#W3F+_6"Y#20]8/@!/"`#Y"2&N`DYO6"Y#20]8/D\*L2 +MJA.I%.3U\!)"^JL2JA.I%)```N3U\!)#&9``!.3U\!)#&9``!N3U\!)#&9`` +M".3U\!)#&9"2&N#_)>`D@/6"Y#2']8/D\*/P[R7@),3U@N0TC/6#Y/"C\.\E +MX"1$]8+D-(WU@^3PH_"0DAK@!/`":<$BD`1$=!'PHW3P\*-T#_"CY/"0DAKP +MD)(:X/_#E!!0%'2D+_6"Y#0$]8/D\)"2&N`$\(#BY)".Q?"0B0$$\.20DAKP +MD)(:X/_#E$!``D'+=?`*[Y"$`!)#7^3PH_!U\`KOD(0"$D-?Y/"C\'7P"N^0 +MA`020U_D\*/P=?`*[Y"$!A)#7^3PH_!U\`KOD(0($D-?Y/"C\'0F+_6"Y#21 +M]8-T$_!TA2_U@N0TCO6#Y/!TA"_U@N0TC/6#Y/#O)>`D@/6"Y#2']8/D\*/P +M[R7@),3U@N0TC/6#Y/"C\.\EX"3$]8+D-(WU@^3PH_#O)>`D1/6"Y#2-]8/D +M\*/P[R7@),;U@N0TCO6#Y/"C\.\EX"1&]8+D-(_U@^3PH_!TAB_U@N0TD/6# +MY/!T1B_U@N0TD/6#Y/!TYB_U@N0TD/6#Y/"00<23_G0!D_^008QT`9,O_^23 +M/L,3_N\3_Y"2&N#])>`DPO6"Y#2)]8/N\*/O\'7P">V0BDL20U]T`?!U\`GM +MD(I*$D-?=`'P=((M]8+D-(GU@W0,\'7P">V0BD820U]T__"C\'7P">V0BD02 +M0U_D\*-T#_!U\`GMD(I($D-?=!/P=?`)[9"*21)#7^3P[<.4(%`/=(0M]8+D +M-`3U@W03\(`-=*8M]8+D-)#U@W03\)"2&N`$\"$8(A(IV?_#E$!0%)```A)" +M(/YT1"_U@N0TCO6#[O`B[[1`"I```A)"()"*0O`BD``$$D(@_U0__N]4@,03 +M$Q-4`?VO!@)>J!(IV9")`?`BD)*:[O"C[_#DH_"C\)"2FN#^H^#U@HZ#X&`L +MPY"2G>"4Z)"2G."4`T`*D`'&X$00\'\`(I"2G.1U\`$20H%_"GX`$C=4@,9_ +M`2(2*=GU(2+3$*\!P\#0D)(E$BJ+`````)```1)"()"29/"0``,20B"0DE3P +M$D?3PH^_P@`^0DE]T!?"0DEWD\*-T`_"0 +MDEW@H^"0!5CP(A(IV9"27/!@!^3]?P0210V0DES@D`'G\"*0`@G@_1(IV?ZO +M!>TND))V\)```1)"(/_M+Y"2=_"0``(20B#_[2^0DGCPD``#$D(@_^TOD))Y +M\)``!!)"(/^N!>TOD))Z\"+3$*\!P\#0D)(E$D.+D)(E$D-KD``!$D+"^N7P +M)`#_Y#K^D)(E$D-KD``![H_P$D,9$BG9_V`LM5X6D)(E$D-KD``!$D+"96!P +M!.5?9?!@(Y"2)1)#:Y```1)"PO^N\)'X@!"0DB420VL2*=EE7F`#$E?3T-"2 +MKR*0DBCN\*/O\'5>`8Y?]6#D_7\+L3SD_7\"L3P23[OD_Q)/K^3U8I`!R>5B +M\)"2*.#\H^#][/N-1.3U17T!?V!^`0(UJ],0KP'#P-"0DBOM\)"2*N_PTY0' +M4$^CX'`:D)(JX/]T`:@'"(`"PS/8_/3_D`!'X%_P@!>0DBK@_W0!J`<(@`+# +M,]C\_Y``1^!/\!)/ZI"2*N#_=`&H!PB``L,SV/ST_Y``1H!:D)(JX"3X\*/@ +M`$\(#KD)(:X,.49%`0D``PX*L1JA*I$Q)" +M37\!(G\`(N20DJ;PH_"0!?C@<`^CX'`+H^!P!Z/@<`-_`2+3D)*GX)3HD)*F +MX)0#0`-_`")_,GX`$C=4D)*FY'7P`1)"@8#&D)'_$D-3D("%$BI_?WA^"!(O +MV9"2`Q)#4Y"`A1(J?W\$?@P2+]F0D@<20U.0@(42*G]_`'X($B_9D)(+$D-3 +MD("%$BI_?W!^#A(OV9"`61(JBP`#+97D_?\2-(&0DG[@M`$1D(!9$BJ+``,M +ME>3]?P$2-($B?WA^"!(GWI"1_Q(J?W\$?@P2)]Z0D@,2*G]_`'X($B?>D)(' +M$BI_D))^X)"1_[0!#1)#4^]4Q__M5,?]@`<20U/O5,?_[)"`A1(J?W]X?@@2 +M+]F0D@,20U/O5`__[)"`A1(J?W\$?@P2+]F0D@<20U/O1`+_[)"`A1(J?W\` +M?@@2+]E_<'X.$B?>D)(+$BI_D("%$BJ+`!LEH']P?@X2+]F0@%D2*HL````` +MY/W_$C2!D))^X+0!$9"`61(JBP````#D_7\!$C2!(N]P`P)YG9"2#^!@`P)] +M:)"1^Q)#4Y"`A1(J?W^,?@@2+]F0D:<20U.0@(42*G]_1'X($B_9D)&K$D-3 +MD("%$BI_?UQ^"!(OV9"1KQ)#4Y"`A1(J?W]L?@X2+]F0D;,20U.0@(42*G]_ +M<'X.$B_9D)&W$D-3D("%$BI_?W1^#A(OV9"1NQ)#4Y"`A1(J?W]X?@X2+]F0 +MD;\20U.0@(42*G]_?'X.$B_9D)'#$D-3D("%$BI_?X!^#A(OV9"1QQ)#4Y"` +MA1(J?W^$?@X2+]F0D,20U.0@(42 +M*G]_X'X.$B_9D)'G$D-3D("%$BI_?^Q^#A(OV9"1ZQ)#4Y"`A1(J?W\$?@P2 +M+]F0D>\20U.0@(42*G]_!'X-$B_9D)'S$D-3D("%$BI_?PQ^"1(OV9"1]Q)# +M4Y"`A1(J?W\$?@@2+]F0D@]T`?`BD)(/X&0!8`*A:'^,?@@2)]Z0D?L2*G]_ +M1'X($B?>D)&G$BI_?UQ^"!(GWI"1JQ(J?W]L?@X2)]Z0D:\2*G]_<'X.$B?> +MD)&S$BI_?W1^#A(GWI"1MQ(J?W]X?@X2)]Z0D;L2*G]_?'X.$B?>D)&_$BI_ +M?X!^#A(GWI"1PQ(J?W^$?@X2)]Z0D<<2*G]_B'X.$B?>D)'+$BI_?XQ^#A(G +MWI"1SQ(J?W_0?@X2)]Z0D=,2*G]_U'X.$B?>D)'7$BI_?]A^#A(GWI"1VQ(J +M?W_D)'C$BI_?^Q^#A(GWI"1YQ(J?W\$?@P2 +M)]Z0D>L2*G]_!'X-$B?>D)'O$BI_?PQ^"1(GWI"1\Q(J?W\$?@@2)]Z0D?<2 +M*G]_C'X($B?>D)*>$BI_D)*>$D-3[43`_>R0DIX2*G^0DIX20U.0@(42*G]_ +MC'X($B_9D("%$BJ+``$``']$?@@2+]F0@(42*HL`VR6D?UQ^"!(OV9"`A1(J +MBR#;):1_;'X.$B_9D("%$BJ+(-LEI']P?@X2+]F0@(42*HL$&R6D?W1^#A(O +MV9"`A1(JBP0;):1_>'X.$B_9D("%$BJ+!!LEI']\?@X2+]F0@(42*HL$&R6D +M?X!^#A(OV9"`A1(JBV/;):1_A'X.$B_9D("%$BJ+!!LEI'^(?@X2+]F0@(42 +M*HL@VR6D?XQ^#A(OV9"`A1(JBR#;):1_T'X.$B_9D("%$BJ+(-LEI'_4?@X2 +M+]F0@(42*HL@VR6D?]A^#A(OV9"`A1(JBP`;):1_W'X.$B_9D("%$BJ+`!LE +MI'_@?@X2+]F0@(42*HLDVR6D?^Q^#A(OV7\$?@P2)]Z0DIX2*G^0DIX20U/D +M_^R0DIX2*G^0DIX20U/O1!'_[)"2GA(J?Y"2GA)#4Y"`A1(J?W\$?@P2+]E_ +M!'X-$B?>D)*>$BI_D)*>$D-3[U3P_^R0DIX2*G^0DIX20U/O1`'_[)"2GA(J +M?Y"2GA)#4Y"`A1(J?W\$?@T2+]E_#'X)$B?>D)*>$BI_D)*>$D-3Y/_LD)*> +M$BI_D)*>$D-3[T01_^R0DIX2*G^0DIX20U.0@(42*G]_#'X)$B_9?PQ^"1(G +MWI"2GA(J?Y"2GA)#4^U4#_WL5/#\D)*>$BI_D)*>$D-3[400_>Q$`?R0DIX2 +M*G^0DIX20U.0@(42*G]_#'X)$B_9?P1^"!(GWI"2GA(J?Y"2GA)#4^]4\/_L +MD)*>$BI_D)*>$D-3[T0!_^R0DIX2*G^0DIX20U.0@(42*G]_!'X($B_9Y)"2 +M#_`BBP^*$(D1D``"$D(@D))"\.`PX$N0DCET`?!_@'X($B?>D)([$BI_JP^J +M$*D1D``!$D(@_^3\_?YX&A(J;*@$J06J!JL'D)([$D-3[%0#_!)#1I"211(J +M?Y`%(N3P@"WDD)(Y\'^`?@@2)][L5`/\[$3`_)"2.Q(J?Y"2.Q)#4Y"`A1(J +M?W^`?@@2+]F0DD+@,.$;?0Q_1Q)-0I``2.!$#/U_2!)-0I``1N!$$(`>D`!' +MX%3S_7]'$DU"D`!(X%3S_7]($DU"D`!&X%3O_7]&$DU"Y)"2/_`BD``"$D(@ +MD))#\.!@!.#T<"&BK^0S]0_"KY``1^!4^_U_1Q)-0GU`?P$2-J_E#R3_DJ\B +MY/U_11)-0I`$_>3PH_"0DD/PD)))\)"23/"0DDKPD))-\)"22_"0DD[PD)(U +M!/#DH_"C\*/PD)(Z\)"2/_"0DD'PD))3\)"21/"0DD#PD)(Y\)``4>!$P/U_ +M40)-0I"24^!D`6`(D))!X&`"X:F0DC7@PY3_4`7@!/"`.Y"2-N##E/]0!N`$ +M\.2`*)"2-^##E/]0"N`$\.20DC;P@!60DCC@PY3_4!#@!/#DD)(W\)"2-O"0 +MDC7PD`!$X%0,8';@,.(RD)))X,.4_U`%X`3P@"20DDK@PY3_4`;@!/#D@!&0 +MDDO@PY3_4`S@!/#DD))*\)"22?"0`$3@,.,RD)),X,.4_U`%X`3P@"20DDW@ +JPY3_4`;@!/#D@!&0DD[@PY3_4`S@!/#DD))-\)"23/"0!/W@1`'P(GP. +` +end From bcaed14bd9582e57b096d9bf69683098ff314c9b Mon Sep 17 00:00:00 2001 From: Adrian Chadd Date: Thu, 31 Dec 2015 22:32:36 +0000 Subject: [PATCH 35/37] [rtwn] bring over initial rtwn driver. This is a port from openbsd. It's incomplete and unstable, but it's better than nothing. I have no plans to MFC this until it's complete and stable. Submitted by: kevlo --- sys/dev/rtwn/if_rtwn.c | 3490 +++++++++++++++++++++++++++++++++++++ sys/dev/rtwn/if_rtwnreg.h | 2106 ++++++++++++++++++++++ 2 files changed, 5596 insertions(+) create mode 100644 sys/dev/rtwn/if_rtwn.c create mode 100644 sys/dev/rtwn/if_rtwnreg.h diff --git a/sys/dev/rtwn/if_rtwn.c b/sys/dev/rtwn/if_rtwn.c new file mode 100644 index 000000000000..6fedf7dd7bb7 --- /dev/null +++ b/sys/dev/rtwn/if_rtwn.c @@ -0,0 +1,3490 @@ +/* $OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * Driver for Realtek RTL8188CE + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#define RTWN_DEBUG +#ifdef RTWN_DEBUG +#define DPRINTF(x) do { if (sc->sc_debug > 0) printf x; } while (0) +#define DPRINTFN(n, x) do { if (sc->sc_debug >= (n)) printf x; } while (0) +#else +#define DPRINTF(x) +#define DPRINTFN(n, x) +#endif + +/* + * PCI configuration space registers. + */ +#define RTWN_PCI_IOBA 0x10 /* i/o mapped base */ +#define RTWN_PCI_MMBA 0x18 /* memory mapped base */ + +#define RTWN_INT_ENABLE (R92C_IMR_ROK | R92C_IMR_VODOK | R92C_IMR_VIDOK | \ + R92C_IMR_BEDOK | R92C_IMR_BKDOK | R92C_IMR_MGNTDOK | \ + R92C_IMR_HIGHDOK | R92C_IMR_BDOK | R92C_IMR_RDU | \ + R92C_IMR_RXFOVW) + +struct rtwn_ident { + uint16_t vendor; + uint16_t device; + const char *name; +}; + + +static const struct rtwn_ident rtwn_ident_table[] = { + { 0x10ec, 0x8176, "Realtek RTL8188CE" }, + { 0, 0, NULL } +}; + + +static void rtwn_dma_map_addr(void *, bus_dma_segment_t *, int, int); +static void rtwn_setup_rx_desc(struct rtwn_softc *, struct r92c_rx_desc *, + bus_addr_t, size_t, int); +static int rtwn_alloc_rx_list(struct rtwn_softc *); +static void rtwn_reset_rx_list(struct rtwn_softc *); +static void rtwn_free_rx_list(struct rtwn_softc *); +static int rtwn_alloc_tx_list(struct rtwn_softc *, int); +static void rtwn_reset_tx_list(struct rtwn_softc *, int); +static void rtwn_free_tx_list(struct rtwn_softc *, int); +static struct ieee80211vap *rtwn_vap_create(struct ieee80211com *, + const char [IFNAMSIZ], int, enum ieee80211_opmode, int, + const uint8_t [IEEE80211_ADDR_LEN], + const uint8_t [IEEE80211_ADDR_LEN]); +static void rtwn_vap_delete(struct ieee80211vap *); +static void rtwn_write_1(struct rtwn_softc *, uint16_t, uint8_t); +static void rtwn_write_2(struct rtwn_softc *, uint16_t, uint16_t); +static void rtwn_write_4(struct rtwn_softc *, uint16_t, uint32_t); +static uint8_t rtwn_read_1(struct rtwn_softc *, uint16_t); +static uint16_t rtwn_read_2(struct rtwn_softc *, uint16_t); +static uint32_t rtwn_read_4(struct rtwn_softc *, uint16_t); +static int rtwn_fw_cmd(struct rtwn_softc *, uint8_t, const void *, int); +static void rtwn_rf_write(struct rtwn_softc *, int, uint8_t, uint32_t); +static uint32_t rtwn_rf_read(struct rtwn_softc *, int, uint8_t); +static int rtwn_llt_write(struct rtwn_softc *, uint32_t, uint32_t); +static uint8_t rtwn_efuse_read_1(struct rtwn_softc *, uint16_t); +static void rtwn_efuse_read(struct rtwn_softc *); +static int rtwn_read_chipid(struct rtwn_softc *); +static void rtwn_read_rom(struct rtwn_softc *); +static int rtwn_ra_init(struct rtwn_softc *); +static void rtwn_tsf_sync_enable(struct rtwn_softc *); +static void rtwn_set_led(struct rtwn_softc *, int, int); +static void rtwn_calib_to(void *); +static int rtwn_newstate(struct ieee80211vap *, enum ieee80211_state, int); +static int rtwn_updateedca(struct ieee80211com *); +static void rtwn_update_avgrssi(struct rtwn_softc *, int, int8_t); +static int8_t rtwn_get_rssi(struct rtwn_softc *, int, void *); +static void rtwn_rx_frame(struct rtwn_softc *, struct r92c_rx_desc *, + struct rtwn_rx_data *, int); +static int rtwn_tx(struct rtwn_softc *, struct mbuf *, + struct ieee80211_node *); +static void rtwn_tx_done(struct rtwn_softc *, int); +static int rtwn_raw_xmit(struct ieee80211_node *, struct mbuf *, + const struct ieee80211_bpf_params *); +static int rtwn_transmit(struct ieee80211com *, struct mbuf *); +static void rtwn_parent(struct ieee80211com *); +static void rtwn_start(struct rtwn_softc *sc); +static void rtwn_watchdog(void *); +static int rtwn_power_on(struct rtwn_softc *); +static int rtwn_llt_init(struct rtwn_softc *); +static void rtwn_fw_reset(struct rtwn_softc *); +static void rtwn_fw_loadpage(struct rtwn_softc *, int, const uint8_t *, + int); +static int rtwn_load_firmware(struct rtwn_softc *); +static int rtwn_dma_init(struct rtwn_softc *); +static void rtwn_mac_init(struct rtwn_softc *); +static void rtwn_bb_init(struct rtwn_softc *); +static void rtwn_rf_init(struct rtwn_softc *); +static void rtwn_cam_init(struct rtwn_softc *); +static void rtwn_pa_bias_init(struct rtwn_softc *); +static void rtwn_rxfilter_init(struct rtwn_softc *); +static void rtwn_edca_init(struct rtwn_softc *); +static void rtwn_write_txpower(struct rtwn_softc *, int, uint16_t[]); +static void rtwn_get_txpower(struct rtwn_softc *, int, + struct ieee80211_channel *, struct ieee80211_channel *, + uint16_t[]); +static void rtwn_set_txpower(struct rtwn_softc *, + struct ieee80211_channel *, struct ieee80211_channel *); +static void rtwn_scan_start(struct ieee80211com *); +static void rtwn_scan_end(struct ieee80211com *); +static void rtwn_set_channel(struct ieee80211com *); +static void rtwn_update_mcast(struct ieee80211com *); +static void rtwn_set_chan(struct rtwn_softc *, + struct ieee80211_channel *, struct ieee80211_channel *); +static int rtwn_iq_calib_chain(struct rtwn_softc *, int, uint16_t[2], + uint16_t[2]); +static void rtwn_iq_calib_run(struct rtwn_softc *, int, uint16_t[2][2], + uint16_t[2][2]); +static int rtwn_iq_calib_compare_results(uint16_t[2][2], uint16_t[2][2], + uint16_t[2][2], uint16_t[2][2], int); +static void rtwn_iq_calib_write_results(struct rtwn_softc *, uint16_t[2], + uint16_t[2], int); +static void rtwn_iq_calib(struct rtwn_softc *); +static void rtwn_lc_calib(struct rtwn_softc *); +static void rtwn_temp_calib(struct rtwn_softc *); +static void rtwn_init_locked(struct rtwn_softc *); +static void rtwn_init(struct rtwn_softc *); +static void rtwn_stop_locked(struct rtwn_softc *); +static void rtwn_stop(struct rtwn_softc *); +static void rtwn_intr(void *); +static void rtwn_hw_reset(void *, int); + +/* Aliases. */ +#define rtwn_bb_write rtwn_write_4 +#define rtwn_bb_read rtwn_read_4 + +static int rtwn_probe(device_t); +static int rtwn_attach(device_t); +static int rtwn_detach(device_t); +static int rtwn_shutdown(device_t); +static int rtwn_suspend(device_t); +static int rtwn_resume(device_t); + +static device_method_t rtwn_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, rtwn_probe), + DEVMETHOD(device_attach, rtwn_attach), + DEVMETHOD(device_detach, rtwn_detach), + DEVMETHOD(device_shutdown, rtwn_shutdown), + DEVMETHOD(device_suspend, rtwn_suspend), + DEVMETHOD(device_resume, rtwn_resume), + + DEVMETHOD_END +}; + +static driver_t rtwn_driver = { + "rtwn", + rtwn_methods, + sizeof (struct rtwn_softc) +}; +static devclass_t rtwn_devclass; + +DRIVER_MODULE(rtwn, pci, rtwn_driver, rtwn_devclass, NULL, NULL); + +MODULE_VERSION(rtwn, 1); + +MODULE_DEPEND(rtwn, pci, 1, 1, 1); +MODULE_DEPEND(rtwn, wlan, 1, 1, 1); +MODULE_DEPEND(rtwn, firmware, 1, 1, 1); + +static int +rtwn_probe(device_t dev) +{ + const struct rtwn_ident *ident; + + for (ident = rtwn_ident_table; ident->name != NULL; ident++) { + if (pci_get_vendor(dev) == ident->vendor && + pci_get_device(dev) == ident->device) { + device_set_desc(dev, ident->name); + return (BUS_PROBE_DEFAULT); + } + } + return (ENXIO); +} + +static int +rtwn_attach(device_t dev) +{ + struct rtwn_softc *sc = device_get_softc(dev); + struct ieee80211com *ic = &sc->sc_ic; + uint32_t lcsr; + uint8_t bands; + int i, count, error, rid; + + sc->sc_dev = dev; + sc->sc_debug = 0; + + /* + * Get the offset of the PCI Express Capability Structure in PCI + * Configuration Space. + */ + error = pci_find_cap(dev, PCIY_EXPRESS, &sc->sc_cap_off); + if (error != 0) { + device_printf(dev, "PCIe capability structure not found!\n"); + return (error); + } + + /* Enable bus-mastering. */ + pci_enable_busmaster(dev); + + rid = PCIR_BAR(2); + sc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, + RF_ACTIVE); + if (sc->mem == NULL) { + device_printf(dev, "can't map mem space\n"); + return (ENOMEM); + } + sc->sc_st = rman_get_bustag(sc->mem); + sc->sc_sh = rman_get_bushandle(sc->mem); + + /* Install interrupt handler. */ + count = 1; + rid = 0; + if (pci_alloc_msi(dev, &count) == 0) + rid = 1; + sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE | + (rid != 0 ? 0 : RF_SHAREABLE)); + if (sc->irq == NULL) { + device_printf(dev, "can't map interrupt\n"); + return (ENXIO); + } + + RTWN_LOCK_INIT(sc); + callout_init_mtx(&sc->calib_to, &sc->sc_mtx, 0); + callout_init_mtx(&sc->watchdog_to, &sc->sc_mtx, 0); + TASK_INIT(&sc->sc_reinit_task, 0, rtwn_hw_reset, sc); + mbufq_init(&sc->sc_snd, ifqmaxlen); + + error = rtwn_read_chipid(sc); + if (error != 0) { + device_printf(dev, "unsupported test chip\n"); + goto fail; + } + + /* Disable PCIe Active State Power Management (ASPM). */ + lcsr = pci_read_config(sc->sc_dev, sc->sc_cap_off + PCIER_LINK_CTL, 4); + lcsr &= ~PCIEM_LINK_CTL_ASPMC; + pci_write_config(sc->sc_dev, sc->sc_cap_off + PCIER_LINK_CTL, lcsr, 4); + + /* Allocate Tx/Rx buffers. */ + error = rtwn_alloc_rx_list(sc); + if (error != 0) { + device_printf(dev, "could not allocate Rx buffers\n"); + goto fail; + } + for (i = 0; i < RTWN_NTXQUEUES; i++) { + error = rtwn_alloc_tx_list(sc, i); + if (error != 0) { + device_printf(dev, "could not allocate Tx buffers\n"); + goto fail; + } + } + + /* Determine number of Tx/Rx chains. */ + if (sc->chip & RTWN_CHIP_92C) { + sc->ntxchains = (sc->chip & RTWN_CHIP_92C_1T2R) ? 1 : 2; + sc->nrxchains = 2; + } else { + sc->ntxchains = 1; + sc->nrxchains = 1; + } + rtwn_read_rom(sc); + + device_printf(sc->sc_dev, "MAC/BB RTL%s, RF 6052 %dT%dR\n", + (sc->chip & RTWN_CHIP_92C) ? "8192CE" : "8188CE", + sc->ntxchains, sc->nrxchains); + + ic->ic_softc = sc; + ic->ic_name = device_get_nameunit(dev); + ic->ic_opmode = IEEE80211_M_STA; + ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ + + /* set device capabilities */ + ic->ic_caps = + IEEE80211_C_STA /* station mode */ + | IEEE80211_C_MONITOR /* monitor mode */ + | IEEE80211_C_SHPREAMBLE /* short preamble supported */ + | IEEE80211_C_SHSLOT /* short slot time supported */ + | IEEE80211_C_WPA /* capable of WPA1+WPA2 */ + | IEEE80211_C_BGSCAN /* capable of bg scanning */ + | IEEE80211_C_WME /* 802.11e */ + ; + + bands = 0; + setbit(&bands, IEEE80211_MODE_11B); + setbit(&bands, IEEE80211_MODE_11G); + ieee80211_init_channels(ic, NULL, &bands); + + ieee80211_ifattach(ic); + + ic->ic_wme.wme_update = rtwn_updateedca; + ic->ic_update_mcast = rtwn_update_mcast; + ic->ic_scan_start =rtwn_scan_start; + ic->ic_scan_end = rtwn_scan_end; + ic->ic_set_channel = rtwn_set_channel; + ic->ic_raw_xmit = rtwn_raw_xmit; + ic->ic_transmit = rtwn_transmit; + ic->ic_parent = rtwn_parent; + ic->ic_vap_create = rtwn_vap_create; + ic->ic_vap_delete = rtwn_vap_delete; + + ieee80211_radiotap_attach(ic, + &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), + RTWN_TX_RADIOTAP_PRESENT, + &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), + RTWN_RX_RADIOTAP_PRESENT); + + /* + * Hook our interrupt after all initialization is complete. + */ + error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET | INTR_MPSAFE, + NULL, rtwn_intr, sc, &sc->sc_ih); + if (error != 0) { + device_printf(dev, "can't establish interrupt, error %d\n", + error); + goto fail; + } + + if (bootverbose) + ieee80211_announce(ic); + + return (0); + +fail: + rtwn_detach(dev); + return (error); +} + + +static int +rtwn_detach(device_t dev) +{ + struct rtwn_softc *sc = device_get_softc(dev); + int i; + + if (sc->sc_ic.ic_softc != NULL) { + ieee80211_draintask(&sc->sc_ic, &sc->sc_reinit_task); + rtwn_stop(sc); + + callout_drain(&sc->calib_to); + callout_drain(&sc->watchdog_to); + ieee80211_ifdetach(&sc->sc_ic); + mbufq_drain(&sc->sc_snd); + } + + /* Uninstall interrupt handler. */ + if (sc->irq != NULL) { + bus_teardown_intr(dev, sc->irq, sc->sc_ih); + bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->irq), + sc->irq); + pci_release_msi(dev); + } + + /* Free Tx/Rx buffers. */ + for (i = 0; i < RTWN_NTXQUEUES; i++) + rtwn_free_tx_list(sc, i); + rtwn_free_rx_list(sc); + + if (sc->mem != NULL) + bus_release_resource(dev, SYS_RES_MEMORY, + rman_get_rid(sc->mem), sc->mem); + + RTWN_LOCK_DESTROY(sc); + return (0); +} + +static int +rtwn_shutdown(device_t dev) +{ + + return (0); +} + +static int +rtwn_suspend(device_t dev) +{ + return (0); +} + +static int +rtwn_resume(device_t dev) +{ + + return (0); +} + +static void +rtwn_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nsegs, int error) +{ + + if (error != 0) + return; + KASSERT(nsegs == 1, ("too many DMA segments, %d should be 1", nsegs)); + *(bus_addr_t *)arg = segs[0].ds_addr; +} + +static void +rtwn_setup_rx_desc(struct rtwn_softc *sc, struct r92c_rx_desc *desc, + bus_addr_t addr, size_t len, int idx) +{ + + memset(desc, 0, sizeof(*desc)); + desc->rxdw0 = htole32(SM(R92C_RXDW0_PKTLEN, len) | + ((idx == RTWN_RX_LIST_COUNT - 1) ? R92C_RXDW0_EOR : 0)); + desc->rxbufaddr = htole32(addr); + bus_space_barrier(sc->sc_st, sc->sc_sh, 0, sc->sc_mapsize, + BUS_SPACE_BARRIER_WRITE); + desc->rxdw0 |= htole32(R92C_RXDW0_OWN); +} + +static int +rtwn_alloc_rx_list(struct rtwn_softc *sc) +{ + struct rtwn_rx_ring *rx_ring = &sc->rx_ring; + struct rtwn_rx_data *rx_data; + bus_size_t size; + int i, error; + + /* Allocate Rx descriptors. */ + size = sizeof(struct r92c_rx_desc) * RTWN_RX_LIST_COUNT; + error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, + size, 1, size, 0, NULL, NULL, &rx_ring->desc_dmat); + if (error != 0) { + device_printf(sc->sc_dev, "could not create rx desc DMA tag\n"); + goto fail; + } + + error = bus_dmamem_alloc(rx_ring->desc_dmat, (void **)&rx_ring->desc, + BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT, + &rx_ring->desc_map); + if (error != 0) { + device_printf(sc->sc_dev, "could not allocate rx desc\n"); + goto fail; + } + error = bus_dmamap_load(rx_ring->desc_dmat, rx_ring->desc_map, + rx_ring->desc, size, rtwn_dma_map_addr, &rx_ring->paddr, 0); + if (error != 0) { + device_printf(sc->sc_dev, "could not load rx desc DMA map\n"); + goto fail; + } + bus_dmamap_sync(rx_ring->desc_dmat, rx_ring->desc_map, + BUS_DMASYNC_PREWRITE); + + /* Create RX buffer DMA tag. */ + error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, + 1, MCLBYTES, 0, NULL, NULL, &rx_ring->data_dmat); + if (error != 0) { + device_printf(sc->sc_dev, "could not create rx buf DMA tag\n"); + goto fail; + } + + /* Allocate Rx buffers. */ + for (i = 0; i < RTWN_RX_LIST_COUNT; i++) { + rx_data = &rx_ring->rx_data[i]; + error = bus_dmamap_create(rx_ring->data_dmat, 0, &rx_data->map); + if (error != 0) { + device_printf(sc->sc_dev, + "could not create rx buf DMA map\n"); + goto fail; + } + + rx_data->m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); + if (rx_data->m == NULL) { + device_printf(sc->sc_dev, + "could not allocate rx mbuf\n"); + error = ENOMEM; + goto fail; + } + + error = bus_dmamap_load(rx_ring->data_dmat, rx_data->map, + mtod(rx_data->m, void *), MCLBYTES, rtwn_dma_map_addr, + &rx_data->paddr, BUS_DMA_NOWAIT); + if (error != 0) { + device_printf(sc->sc_dev, + "could not load rx buf DMA map"); + goto fail; + } + + rtwn_setup_rx_desc(sc, &rx_ring->desc[i], rx_data->paddr, + MCLBYTES, i); + } + return (0); + +fail: + rtwn_free_rx_list(sc); + return (error); +} + +static void +rtwn_reset_rx_list(struct rtwn_softc *sc) +{ + struct rtwn_rx_ring *rx_ring = &sc->rx_ring; + struct rtwn_rx_data *rx_data; + int i; + + for (i = 0; i < RTWN_RX_LIST_COUNT; i++) { + rx_data = &rx_ring->rx_data[i]; + rtwn_setup_rx_desc(sc, &rx_ring->desc[i], rx_data->paddr, + MCLBYTES, i); + } +} + +static void +rtwn_free_rx_list(struct rtwn_softc *sc) +{ + struct rtwn_rx_ring *rx_ring = &sc->rx_ring; + struct rtwn_rx_data *rx_data; + int i; + + if (rx_ring->desc_dmat != NULL) { + if (rx_ring->desc != NULL) { + bus_dmamap_unload(rx_ring->desc_dmat, + rx_ring->desc_map); + bus_dmamem_free(rx_ring->desc_dmat, rx_ring->desc, + rx_ring->desc_map); + rx_ring->desc = NULL; + } + bus_dma_tag_destroy(rx_ring->desc_dmat); + rx_ring->desc_dmat = NULL; + } + + for (i = 0; i < RTWN_RX_LIST_COUNT; i++) { + rx_data = &rx_ring->rx_data[i]; + + if (rx_data->m != NULL) { + bus_dmamap_unload(rx_ring->data_dmat, rx_data->map); + m_freem(rx_data->m); + rx_data->m = NULL; + } + bus_dmamap_destroy(rx_ring->data_dmat, rx_data->map); + rx_data->map = NULL; + } + if (rx_ring->data_dmat != NULL) { + bus_dma_tag_destroy(rx_ring->data_dmat); + rx_ring->data_dmat = NULL; + } +} + +static int +rtwn_alloc_tx_list(struct rtwn_softc *sc, int qid) +{ + struct rtwn_tx_ring *tx_ring = &sc->tx_ring[qid]; + struct rtwn_tx_data *tx_data; + bus_size_t size; + int i, error; + + size = sizeof(struct r92c_tx_desc) * RTWN_TX_LIST_COUNT; + error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), PAGE_SIZE, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, + size, 1, size, 0, NULL, NULL, &tx_ring->desc_dmat); + if (error != 0) { + device_printf(sc->sc_dev, "could not create tx ring DMA tag\n"); + goto fail; + } + + error = bus_dmamem_alloc(tx_ring->desc_dmat, (void **)&tx_ring->desc, + BUS_DMA_NOWAIT | BUS_DMA_ZERO, &tx_ring->desc_map); + if (error != 0) { + device_printf(sc->sc_dev, "can't map tx ring DMA memory\n"); + goto fail; + } + error = bus_dmamap_load(tx_ring->desc_dmat, tx_ring->desc_map, + tx_ring->desc, size, rtwn_dma_map_addr, &tx_ring->paddr, + BUS_DMA_NOWAIT); + if (error != 0) { + device_printf(sc->sc_dev, "could not load desc DMA map\n"); + goto fail; + } + + error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, + 1, MCLBYTES, 0, NULL, NULL, &tx_ring->data_dmat); + if (error != 0) { + device_printf(sc->sc_dev, "could not create tx buf DMA tag\n"); + goto fail; + } + + for (i = 0; i < RTWN_TX_LIST_COUNT; i++) { + struct r92c_tx_desc *desc = &tx_ring->desc[i]; + + /* setup tx desc */ + desc->nextdescaddr = htole32(tx_ring->paddr + + + sizeof(struct r92c_tx_desc) + * ((i + 1) % RTWN_TX_LIST_COUNT)); + tx_data = &tx_ring->tx_data[i]; + error = bus_dmamap_create(tx_ring->data_dmat, 0, &tx_data->map); + if (error != 0) { + device_printf(sc->sc_dev, + "could not create tx buf DMA map\n"); + goto fail; + } + tx_data->m = NULL; + tx_data->ni = NULL; + } + return (0); + +fail: + rtwn_free_tx_list(sc, qid); + return (error); +} + +static void +rtwn_reset_tx_list(struct rtwn_softc *sc, int qid) +{ + struct rtwn_tx_ring *tx_ring = &sc->tx_ring[qid]; + int i; + + for (i = 0; i < RTWN_TX_LIST_COUNT; i++) { + struct r92c_tx_desc *desc = &tx_ring->desc[i]; + struct rtwn_tx_data *tx_data = &tx_ring->tx_data[i]; + + memset(desc, 0, sizeof(*desc) - + (sizeof(desc->reserved) + sizeof(desc->nextdescaddr64) + + sizeof(desc->nextdescaddr))); + + if (tx_data->m != NULL) { + bus_dmamap_unload(tx_ring->data_dmat, tx_data->map); + m_freem(tx_data->m); + tx_data->m = NULL; + } + if (tx_data->ni != NULL) { + ieee80211_free_node(tx_data->ni); + tx_data->ni = NULL; + } + } + + bus_dmamap_sync(tx_ring->desc_dmat, tx_ring->desc_map, + BUS_DMASYNC_POSTWRITE); + + sc->qfullmsk &= ~(1 << qid); + tx_ring->queued = 0; + tx_ring->cur = 0; +} + +static void +rtwn_free_tx_list(struct rtwn_softc *sc, int qid) +{ + struct rtwn_tx_ring *tx_ring = &sc->tx_ring[qid]; + struct rtwn_tx_data *tx_data; + int i; + + if (tx_ring->desc_dmat != NULL) { + if (tx_ring->desc != NULL) { + bus_dmamap_unload(tx_ring->desc_dmat, + tx_ring->desc_map); + bus_dmamem_free(tx_ring->desc_dmat, tx_ring->desc, + tx_ring->desc_map); + } + bus_dma_tag_destroy(tx_ring->desc_dmat); + } + + for (i = 0; i < RTWN_TX_LIST_COUNT; i++) { + tx_data = &tx_ring->tx_data[i]; + + if (tx_data->m != NULL) { + bus_dmamap_unload(tx_ring->data_dmat, tx_data->map); + m_freem(tx_data->m); + tx_data->m = NULL; + } + } + if (tx_ring->data_dmat != NULL) { + bus_dma_tag_destroy(tx_ring->data_dmat); + tx_ring->data_dmat = NULL; + } + + sc->qfullmsk &= ~(1 << qid); + tx_ring->queued = 0; + tx_ring->cur = 0; +} + + +static struct ieee80211vap * +rtwn_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, + enum ieee80211_opmode opmode, int flags, + const uint8_t bssid[IEEE80211_ADDR_LEN], + const uint8_t mac[IEEE80211_ADDR_LEN]) +{ + struct rtwn_vap *rvp; + struct ieee80211vap *vap; + + if (!TAILQ_EMPTY(&ic->ic_vaps)) + return (NULL); + + rvp = malloc(sizeof(struct rtwn_vap), M_80211_VAP, M_WAITOK | M_ZERO); + vap = &rvp->vap; + if (ieee80211_vap_setup(ic, vap, name, unit, opmode, + flags | IEEE80211_CLONE_NOBEACONS, bssid) != 0) { + /* out of memory */ + free(rvp, M_80211_VAP); + return (NULL); + } + + /* Override state transition machine. */ + rvp->newstate = vap->iv_newstate; + vap->iv_newstate = rtwn_newstate; + + /* Complete setup. */ + ieee80211_vap_attach(vap, ieee80211_media_change, + ieee80211_media_status, mac); + ic->ic_opmode = opmode; + return (vap); +} + +static void +rtwn_vap_delete(struct ieee80211vap *vap) +{ + struct rtwn_vap *rvp = RTWN_VAP(vap); + + ieee80211_vap_detach(vap); + free(rvp, M_80211_VAP); +} + +static void +rtwn_write_1(struct rtwn_softc *sc, uint16_t addr, uint8_t val) +{ + + bus_space_write_1(sc->sc_st, sc->sc_sh, addr, val); +} + +static void +rtwn_write_2(struct rtwn_softc *sc, uint16_t addr, uint16_t val) +{ + + val = htole16(val); + bus_space_write_2(sc->sc_st, sc->sc_sh, addr, val); +} + +static void +rtwn_write_4(struct rtwn_softc *sc, uint16_t addr, uint32_t val) +{ + + val = htole32(val); + bus_space_write_4(sc->sc_st, sc->sc_sh, addr, val); +} + +static uint8_t +rtwn_read_1(struct rtwn_softc *sc, uint16_t addr) +{ + + return (bus_space_read_1(sc->sc_st, sc->sc_sh, addr)); +} + +static uint16_t +rtwn_read_2(struct rtwn_softc *sc, uint16_t addr) +{ + + return (bus_space_read_2(sc->sc_st, sc->sc_sh, addr)); +} + +static uint32_t +rtwn_read_4(struct rtwn_softc *sc, uint16_t addr) +{ + + return (bus_space_read_4(sc->sc_st, sc->sc_sh, addr)); +} + +static int +rtwn_fw_cmd(struct rtwn_softc *sc, uint8_t id, const void *buf, int len) +{ + struct r92c_fw_cmd cmd; + int ntries; + + /* Wait for current FW box to be empty. */ + for (ntries = 0; ntries < 100; ntries++) { + if (!(rtwn_read_1(sc, R92C_HMETFR) & (1 << sc->fwcur))) + break; + DELAY(1); + } + if (ntries == 100) { + device_printf(sc->sc_dev, + "could not send firmware command %d\n", id); + return (ETIMEDOUT); + } + memset(&cmd, 0, sizeof(cmd)); + cmd.id = id; + if (len > 3) + cmd.id |= R92C_CMD_FLAG_EXT; + KASSERT(len <= sizeof(cmd.msg), ("rtwn_fw_cmd\n")); + memcpy(cmd.msg, buf, len); + + /* Write the first word last since that will trigger the FW. */ + rtwn_write_2(sc, R92C_HMEBOX_EXT(sc->fwcur), *((uint8_t *)&cmd + 4)); + rtwn_write_4(sc, R92C_HMEBOX(sc->fwcur), *((uint8_t *)&cmd + 0)); + + sc->fwcur = (sc->fwcur + 1) % R92C_H2C_NBOX; + + /* Give firmware some time for processing. */ + DELAY(2000); + + return (0); +} + +static void +rtwn_rf_write(struct rtwn_softc *sc, int chain, uint8_t addr, uint32_t val) +{ + rtwn_bb_write(sc, R92C_LSSI_PARAM(chain), + SM(R92C_LSSI_PARAM_ADDR, addr) | + SM(R92C_LSSI_PARAM_DATA, val)); +} + +static uint32_t +rtwn_rf_read(struct rtwn_softc *sc, int chain, uint8_t addr) +{ + uint32_t reg[R92C_MAX_CHAINS], val; + + reg[0] = rtwn_bb_read(sc, R92C_HSSI_PARAM2(0)); + if (chain != 0) + reg[chain] = rtwn_bb_read(sc, R92C_HSSI_PARAM2(chain)); + + rtwn_bb_write(sc, R92C_HSSI_PARAM2(0), + reg[0] & ~R92C_HSSI_PARAM2_READ_EDGE); + DELAY(1000); + + rtwn_bb_write(sc, R92C_HSSI_PARAM2(chain), + RW(reg[chain], R92C_HSSI_PARAM2_READ_ADDR, addr) | + R92C_HSSI_PARAM2_READ_EDGE); + DELAY(1000); + + rtwn_bb_write(sc, R92C_HSSI_PARAM2(0), + reg[0] | R92C_HSSI_PARAM2_READ_EDGE); + DELAY(1000); + + if (rtwn_bb_read(sc, R92C_HSSI_PARAM1(chain)) & R92C_HSSI_PARAM1_PI) + val = rtwn_bb_read(sc, R92C_HSPI_READBACK(chain)); + else + val = rtwn_bb_read(sc, R92C_LSSI_READBACK(chain)); + return (MS(val, R92C_LSSI_READBACK_DATA)); +} + +static int +rtwn_llt_write(struct rtwn_softc *sc, uint32_t addr, uint32_t data) +{ + int ntries; + + rtwn_write_4(sc, R92C_LLT_INIT, + SM(R92C_LLT_INIT_OP, R92C_LLT_INIT_OP_WRITE) | + SM(R92C_LLT_INIT_ADDR, addr) | + SM(R92C_LLT_INIT_DATA, data)); + /* Wait for write operation to complete. */ + for (ntries = 0; ntries < 20; ntries++) { + if (MS(rtwn_read_4(sc, R92C_LLT_INIT), R92C_LLT_INIT_OP) == + R92C_LLT_INIT_OP_NO_ACTIVE) + return (0); + DELAY(5); + } + return (ETIMEDOUT); +} + +static uint8_t +rtwn_efuse_read_1(struct rtwn_softc *sc, uint16_t addr) +{ + uint32_t reg; + int ntries; + + reg = rtwn_read_4(sc, R92C_EFUSE_CTRL); + reg = RW(reg, R92C_EFUSE_CTRL_ADDR, addr); + reg &= ~R92C_EFUSE_CTRL_VALID; + rtwn_write_4(sc, R92C_EFUSE_CTRL, reg); + /* Wait for read operation to complete. */ + for (ntries = 0; ntries < 100; ntries++) { + reg = rtwn_read_4(sc, R92C_EFUSE_CTRL); + if (reg & R92C_EFUSE_CTRL_VALID) + return (MS(reg, R92C_EFUSE_CTRL_DATA)); + DELAY(5); + } + device_printf(sc->sc_dev, + "could not read efuse byte at address 0x%x\n", addr); + return (0xff); +} + +static void +rtwn_efuse_read(struct rtwn_softc *sc) +{ + uint8_t *rom = (uint8_t *)&sc->rom; + uint16_t addr = 0; + uint32_t reg; + uint8_t off, msk; + int i; + + reg = rtwn_read_2(sc, R92C_SYS_ISO_CTRL); + if (!(reg & R92C_SYS_ISO_CTRL_PWC_EV12V)) { + rtwn_write_2(sc, R92C_SYS_ISO_CTRL, + reg | R92C_SYS_ISO_CTRL_PWC_EV12V); + } + reg = rtwn_read_2(sc, R92C_SYS_FUNC_EN); + if (!(reg & R92C_SYS_FUNC_EN_ELDR)) { + rtwn_write_2(sc, R92C_SYS_FUNC_EN, + reg | R92C_SYS_FUNC_EN_ELDR); + } + reg = rtwn_read_2(sc, R92C_SYS_CLKR); + if ((reg & (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) != + (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) { + rtwn_write_2(sc, R92C_SYS_CLKR, + reg | R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M); + } + memset(&sc->rom, 0xff, sizeof(sc->rom)); + while (addr < 512) { + reg = rtwn_efuse_read_1(sc, addr); + if (reg == 0xff) + break; + addr++; + off = reg >> 4; + msk = reg & 0xf; + for (i = 0; i < 4; i++) { + if (msk & (1 << i)) + continue; + rom[off * 8 + i * 2 + 0] = + rtwn_efuse_read_1(sc, addr); + addr++; + rom[off * 8 + i * 2 + 1] = + rtwn_efuse_read_1(sc, addr); + addr++; + } + } +#ifdef RTWN_DEBUG + if (sc->sc_debug >= 2) { + /* Dump ROM content. */ + printf("\n"); + for (i = 0; i < sizeof(sc->rom); i++) + printf("%02x:", rom[i]); + printf("\n"); + } +#endif +} + +static int +rtwn_read_chipid(struct rtwn_softc *sc) +{ + uint32_t reg; + + reg = rtwn_read_4(sc, R92C_SYS_CFG); + if (reg & R92C_SYS_CFG_TRP_VAUX_EN) + /* Unsupported test chip. */ + return (EIO); + + if (reg & R92C_SYS_CFG_TYPE_92C) { + sc->chip |= RTWN_CHIP_92C; + /* Check if it is a castrated 8192C. */ + if (MS(rtwn_read_4(sc, R92C_HPON_FSM), + R92C_HPON_FSM_CHIP_BONDING_ID) == + R92C_HPON_FSM_CHIP_BONDING_ID_92C_1T2R) + sc->chip |= RTWN_CHIP_92C_1T2R; + } + if (reg & R92C_SYS_CFG_VENDOR_UMC) { + sc->chip |= RTWN_CHIP_UMC; + if (MS(reg, R92C_SYS_CFG_CHIP_VER_RTL) == 0) + sc->chip |= RTWN_CHIP_UMC_A_CUT; + } + return (0); +} + +static void +rtwn_read_rom(struct rtwn_softc *sc) +{ + struct r92c_rom *rom = &sc->rom; + + /* Read full ROM image. */ + rtwn_efuse_read(sc); + + if (rom->id != 0x8129) + device_printf(sc->sc_dev, "invalid EEPROM ID 0x%x\n", rom->id); + + /* XXX Weird but this is what the vendor driver does. */ + sc->pa_setting = rtwn_efuse_read_1(sc, 0x1fa); + DPRINTF(("PA setting=0x%x\n", sc->pa_setting)); + + sc->board_type = MS(rom->rf_opt1, R92C_ROM_RF1_BOARD_TYPE); + + sc->regulatory = MS(rom->rf_opt1, R92C_ROM_RF1_REGULATORY); + DPRINTF(("regulatory type=%d\n", sc->regulatory)); + + IEEE80211_ADDR_COPY(sc->sc_ic.ic_macaddr, rom->macaddr); +} + +/* + * Initialize rate adaptation in firmware. + */ +static int +rtwn_ra_init(struct rtwn_softc *sc) +{ + static const uint8_t map[] = + { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 }; + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + struct ieee80211_node *ni = ieee80211_ref_node(vap->iv_bss); + struct ieee80211_rateset *rs = &ni->ni_rates; + struct r92c_fw_cmd_macid_cfg cmd; + uint32_t rates, basicrates; + uint8_t mode; + int maxrate, maxbasicrate, error, i, j; + + /* Get normal and basic rates mask. */ + rates = basicrates = 0; + maxrate = maxbasicrate = 0; + for (i = 0; i < rs->rs_nrates; i++) { + /* Convert 802.11 rate to HW rate index. */ + for (j = 0; j < nitems(map); j++) + if ((rs->rs_rates[i] & IEEE80211_RATE_VAL) == map[j]) + break; + if (j == nitems(map)) /* Unknown rate, skip. */ + continue; + rates |= 1 << j; + if (j > maxrate) + maxrate = j; + if (rs->rs_rates[i] & IEEE80211_RATE_BASIC) { + basicrates |= 1 << j; + if (j > maxbasicrate) + maxbasicrate = j; + } + } + if (ic->ic_curmode == IEEE80211_MODE_11B) + mode = R92C_RAID_11B; + else + mode = R92C_RAID_11BG; + DPRINTF(("mode=0x%x rates=0x%08x, basicrates=0x%08x\n", + mode, rates, basicrates)); + + /* Set rates mask for group addressed frames. */ + cmd.macid = RTWN_MACID_BC | RTWN_MACID_VALID; + cmd.mask = htole32(mode << 28 | basicrates); + error = rtwn_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd)); + if (error != 0) { + device_printf(sc->sc_dev, + "could not add broadcast station\n"); + return (error); + } + /* Set initial MRR rate. */ + DPRINTF(("maxbasicrate=%d\n", maxbasicrate)); + rtwn_write_1(sc, R92C_INIDATA_RATE_SEL(RTWN_MACID_BC), + maxbasicrate); + + /* Set rates mask for unicast frames. */ + cmd.macid = RTWN_MACID_BSS | RTWN_MACID_VALID; + cmd.mask = htole32(mode << 28 | rates); + error = rtwn_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd)); + if (error != 0) { + device_printf(sc->sc_dev, "could not add BSS station\n"); + return (error); + } + /* Set initial MRR rate. */ + DPRINTF(("maxrate=%d\n", maxrate)); + rtwn_write_1(sc, R92C_INIDATA_RATE_SEL(RTWN_MACID_BSS), + maxrate); + + /* Configure Automatic Rate Fallback Register. */ + if (ic->ic_curmode == IEEE80211_MODE_11B) { + if (rates & 0x0c) + rtwn_write_4(sc, R92C_ARFR(0), htole32(rates & 0x0d)); + else + rtwn_write_4(sc, R92C_ARFR(0), htole32(rates & 0x0f)); + } else + rtwn_write_4(sc, R92C_ARFR(0), htole32(rates & 0x0ff5)); + + /* Indicate highest supported rate. */ + ni->ni_txrate = rs->rs_rates[rs->rs_nrates - 1]; + return (0); +} + +static void +rtwn_tsf_sync_enable(struct rtwn_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + struct ieee80211_node *ni = vap->iv_bss; + uint64_t tsf; + + /* Enable TSF synchronization. */ + rtwn_write_1(sc, R92C_BCN_CTRL, + rtwn_read_1(sc, R92C_BCN_CTRL) & ~R92C_BCN_CTRL_DIS_TSF_UDT0); + + rtwn_write_1(sc, R92C_BCN_CTRL, + rtwn_read_1(sc, R92C_BCN_CTRL) & ~R92C_BCN_CTRL_EN_BCN); + + /* Set initial TSF. */ + memcpy(&tsf, ni->ni_tstamp.data, 8); + tsf = le64toh(tsf); + tsf = tsf - (tsf % (vap->iv_bss->ni_intval * IEEE80211_DUR_TU)); + tsf -= IEEE80211_DUR_TU; + rtwn_write_4(sc, R92C_TSFTR + 0, tsf); + rtwn_write_4(sc, R92C_TSFTR + 4, tsf >> 32); + + rtwn_write_1(sc, R92C_BCN_CTRL, + rtwn_read_1(sc, R92C_BCN_CTRL) | R92C_BCN_CTRL_EN_BCN); +} + +static void +rtwn_set_led(struct rtwn_softc *sc, int led, int on) +{ + uint8_t reg; + + if (led == RTWN_LED_LINK) { + reg = rtwn_read_1(sc, R92C_LEDCFG2) & 0xf0; + if (!on) + reg |= R92C_LEDCFG2_DIS; + else + reg |= R92C_LEDCFG2_EN; + rtwn_write_1(sc, R92C_LEDCFG2, reg); + sc->ledlink = on; /* Save LED state. */ + } +} + +static void +rtwn_calib_to(void *arg) +{ + struct rtwn_softc *sc = arg; + struct r92c_fw_cmd_rssi cmd; + + if (sc->avg_pwdb != -1) { + /* Indicate Rx signal strength to FW for rate adaptation. */ + memset(&cmd, 0, sizeof(cmd)); + cmd.macid = 0; /* BSS. */ + cmd.pwdb = sc->avg_pwdb; + DPRINTFN(3, ("sending RSSI command avg=%d\n", sc->avg_pwdb)); + rtwn_fw_cmd(sc, R92C_CMD_RSSI_SETTING, &cmd, sizeof(cmd)); + } + + /* Do temperature compensation. */ + rtwn_temp_calib(sc); + + callout_reset(&sc->calib_to, hz * 2, rtwn_calib_to, sc); +} + +static int +rtwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) +{ + struct rtwn_vap *rvp = RTWN_VAP(vap); + struct ieee80211com *ic = vap->iv_ic; + struct ieee80211_node *ni = vap->iv_bss; + struct rtwn_softc *sc = ic->ic_softc; + uint32_t reg; + + IEEE80211_UNLOCK(ic); + RTWN_LOCK(sc); + + if (vap->iv_state == IEEE80211_S_RUN) { + /* Stop calibration. */ + callout_stop(&sc->calib_to); + + /* Turn link LED off. */ + rtwn_set_led(sc, RTWN_LED_LINK, 0); + + /* Set media status to 'No Link'. */ + reg = rtwn_read_4(sc, R92C_CR); + reg = RW(reg, R92C_CR_NETTYPE, R92C_CR_NETTYPE_NOLINK); + rtwn_write_4(sc, R92C_CR, reg); + + /* Stop Rx of data frames. */ + rtwn_write_2(sc, R92C_RXFLTMAP2, 0); + + /* Rest TSF. */ + rtwn_write_1(sc, R92C_DUAL_TSF_RST, 0x03); + + /* Disable TSF synchronization. */ + rtwn_write_1(sc, R92C_BCN_CTRL, + rtwn_read_1(sc, R92C_BCN_CTRL) | + R92C_BCN_CTRL_DIS_TSF_UDT0); + + /* Reset EDCA parameters. */ + rtwn_write_4(sc, R92C_EDCA_VO_PARAM, 0x002f3217); + rtwn_write_4(sc, R92C_EDCA_VI_PARAM, 0x005e4317); + rtwn_write_4(sc, R92C_EDCA_BE_PARAM, 0x00105320); + rtwn_write_4(sc, R92C_EDCA_BK_PARAM, 0x0000a444); + } + switch (nstate) { + case IEEE80211_S_INIT: + /* Turn link LED off. */ + rtwn_set_led(sc, RTWN_LED_LINK, 0); + break; + case IEEE80211_S_SCAN: + if (vap->iv_state != IEEE80211_S_SCAN) { + /* Allow Rx from any BSSID. */ + rtwn_write_4(sc, R92C_RCR, + rtwn_read_4(sc, R92C_RCR) & + ~(R92C_RCR_CBSSID_DATA | R92C_RCR_CBSSID_BCN)); + + /* Set gain for scanning. */ + reg = rtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(0)); + reg = RW(reg, R92C_OFDM0_AGCCORE1_GAIN, 0x20); + rtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), reg); + + reg = rtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(1)); + reg = RW(reg, R92C_OFDM0_AGCCORE1_GAIN, 0x20); + rtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(1), reg); + } + + /* Make link LED blink during scan. */ + rtwn_set_led(sc, RTWN_LED_LINK, !sc->ledlink); + + /* Pause AC Tx queues. */ + rtwn_write_1(sc, R92C_TXPAUSE, + rtwn_read_1(sc, R92C_TXPAUSE) | 0x0f); + break; + case IEEE80211_S_AUTH: + /* Set initial gain under link. */ + reg = rtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(0)); + reg = RW(reg, R92C_OFDM0_AGCCORE1_GAIN, 0x32); + rtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), reg); + + reg = rtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(1)); + reg = RW(reg, R92C_OFDM0_AGCCORE1_GAIN, 0x32); + rtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(1), reg); + rtwn_set_chan(sc, ic->ic_curchan, NULL); + break; + case IEEE80211_S_RUN: + if (ic->ic_opmode == IEEE80211_M_MONITOR) { + /* Enable Rx of data frames. */ + rtwn_write_2(sc, R92C_RXFLTMAP2, 0xffff); + + /* Turn link LED on. */ + rtwn_set_led(sc, RTWN_LED_LINK, 1); + break; + } + + /* Set media status to 'Associated'. */ + reg = rtwn_read_4(sc, R92C_CR); + reg = RW(reg, R92C_CR_NETTYPE, R92C_CR_NETTYPE_INFRA); + rtwn_write_4(sc, R92C_CR, reg); + + /* Set BSSID. */ + rtwn_write_4(sc, R92C_BSSID + 0, LE_READ_4(&ni->ni_bssid[0])); + rtwn_write_4(sc, R92C_BSSID + 4, LE_READ_2(&ni->ni_bssid[4])); + + if (ic->ic_curmode == IEEE80211_MODE_11B) + rtwn_write_1(sc, R92C_INIRTS_RATE_SEL, 0); + else /* 802.11b/g */ + rtwn_write_1(sc, R92C_INIRTS_RATE_SEL, 3); + + /* Enable Rx of data frames. */ + rtwn_write_2(sc, R92C_RXFLTMAP2, 0xffff); + + /* Flush all AC queues. */ + rtwn_write_1(sc, R92C_TXPAUSE, 0); + + /* Set beacon interval. */ + rtwn_write_2(sc, R92C_BCN_INTERVAL, ni->ni_intval); + + /* Allow Rx from our BSSID only. */ + rtwn_write_4(sc, R92C_RCR, + rtwn_read_4(sc, R92C_RCR) | + R92C_RCR_CBSSID_DATA | R92C_RCR_CBSSID_BCN); + + /* Enable TSF synchronization. */ + rtwn_tsf_sync_enable(sc); + + rtwn_write_1(sc, R92C_SIFS_CCK + 1, 10); + rtwn_write_1(sc, R92C_SIFS_OFDM + 1, 10); + rtwn_write_1(sc, R92C_SPEC_SIFS + 1, 10); + rtwn_write_1(sc, R92C_MAC_SPEC_SIFS + 1, 10); + rtwn_write_1(sc, R92C_R2T_SIFS + 1, 10); + rtwn_write_1(sc, R92C_T2T_SIFS + 1, 10); + + /* Intialize rate adaptation. */ + rtwn_ra_init(sc); + /* Turn link LED on. */ + rtwn_set_led(sc, RTWN_LED_LINK, 1); + + sc->avg_pwdb = -1; /* Reset average RSSI. */ + /* Reset temperature calibration state machine. */ + sc->thcal_state = 0; + sc->thcal_lctemp = 0; + /* Start periodic calibration. */ + callout_reset(&sc->calib_to, hz * 2, rtwn_calib_to, sc); + break; + default: + break; + } + RTWN_UNLOCK(sc); + IEEE80211_LOCK(ic); + return (rvp->newstate(vap, nstate, arg)); +} + +static int +rtwn_updateedca(struct ieee80211com *ic) +{ + struct rtwn_softc *sc = ic->ic_softc; + const uint16_t aci2reg[WME_NUM_AC] = { + R92C_EDCA_BE_PARAM, + R92C_EDCA_BK_PARAM, + R92C_EDCA_VI_PARAM, + R92C_EDCA_VO_PARAM + }; + int aci, aifs, slottime; + + IEEE80211_LOCK(ic); + slottime = (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20; + for (aci = 0; aci < WME_NUM_AC; aci++) { + const struct wmeParams *ac = + &ic->ic_wme.wme_chanParams.cap_wmeParams[aci]; + /* AIFS[AC] = AIFSN[AC] * aSlotTime + aSIFSTime. */ + aifs = ac->wmep_aifsn * slottime + 10; + rtwn_write_4(sc, aci2reg[aci], + SM(R92C_EDCA_PARAM_TXOP, ac->wmep_txopLimit) | + SM(R92C_EDCA_PARAM_ECWMIN, ac->wmep_logcwmin) | + SM(R92C_EDCA_PARAM_ECWMAX, ac->wmep_logcwmax) | + SM(R92C_EDCA_PARAM_AIFS, aifs)); + } + IEEE80211_UNLOCK(ic); + return (0); +} + +static void +rtwn_update_avgrssi(struct rtwn_softc *sc, int rate, int8_t rssi) +{ + int pwdb; + + /* Convert antenna signal to percentage. */ + if (rssi <= -100 || rssi >= 20) + pwdb = 0; + else if (rssi >= 0) + pwdb = 100; + else + pwdb = 100 + rssi; + if (rate <= 3) { + /* CCK gain is smaller than OFDM/MCS gain. */ + pwdb += 6; + if (pwdb > 100) + pwdb = 100; + if (pwdb <= 14) + pwdb -= 4; + else if (pwdb <= 26) + pwdb -= 8; + else if (pwdb <= 34) + pwdb -= 6; + else if (pwdb <= 42) + pwdb -= 2; + } + if (sc->avg_pwdb == -1) /* Init. */ + sc->avg_pwdb = pwdb; + else if (sc->avg_pwdb < pwdb) + sc->avg_pwdb = ((sc->avg_pwdb * 19 + pwdb) / 20) + 1; + else + sc->avg_pwdb = ((sc->avg_pwdb * 19 + pwdb) / 20); + DPRINTFN(4, ("PWDB=%d EMA=%d\n", pwdb, sc->avg_pwdb)); +} + +static int8_t +rtwn_get_rssi(struct rtwn_softc *sc, int rate, void *physt) +{ + static const int8_t cckoff[] = { 16, -12, -26, -46 }; + struct r92c_rx_phystat *phy; + struct r92c_rx_cck *cck; + uint8_t rpt; + int8_t rssi; + + if (rate <= 3) { + cck = (struct r92c_rx_cck *)physt; + if (sc->sc_flags & RTWN_FLAG_CCK_HIPWR) { + rpt = (cck->agc_rpt >> 5) & 0x3; + rssi = (cck->agc_rpt & 0x1f) << 1; + } else { + rpt = (cck->agc_rpt >> 6) & 0x3; + rssi = cck->agc_rpt & 0x3e; + } + rssi = cckoff[rpt] - rssi; + } else { /* OFDM/HT. */ + phy = (struct r92c_rx_phystat *)physt; + rssi = ((le32toh(phy->phydw1) >> 1) & 0x7f) - 110; + } + return (rssi); +} + +static void +rtwn_rx_frame(struct rtwn_softc *sc, struct r92c_rx_desc *rx_desc, + struct rtwn_rx_data *rx_data, int desc_idx) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_frame *wh; + struct ieee80211_node *ni; + struct r92c_rx_phystat *phy = NULL; + uint32_t rxdw0, rxdw3; + struct mbuf *m, *m1; + bus_dma_segment_t segs[1]; + bus_addr_t physaddr; + uint8_t rate; + int8_t rssi = 0, nf; + int infosz, nsegs, pktlen, shift, error; + + rxdw0 = le32toh(rx_desc->rxdw0); + rxdw3 = le32toh(rx_desc->rxdw3); + + if (__predict_false(rxdw0 & (R92C_RXDW0_CRCERR | R92C_RXDW0_ICVERR))) { + /* + * This should not happen since we setup our Rx filter + * to not receive these frames. + */ + counter_u64_add(ic->ic_ierrors, 1); + return; + } + + pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN); + if (__predict_false(pktlen < sizeof(*wh) || pktlen > MCLBYTES)) { + counter_u64_add(ic->ic_ierrors, 1); + return; + } + + rate = MS(rxdw3, R92C_RXDW3_RATE); + infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8; + if (infosz > sizeof(struct r92c_rx_phystat)) + infosz = sizeof(struct r92c_rx_phystat); + shift = MS(rxdw0, R92C_RXDW0_SHIFT); + + /* Get RSSI from PHY status descriptor if present. */ + if (infosz != 0 && (rxdw0 & R92C_RXDW0_PHYST)) { + phy = mtod(rx_data->m, struct r92c_rx_phystat *); + rssi = rtwn_get_rssi(sc, rate, phy); + /* Update our average RSSI. */ + rtwn_update_avgrssi(sc, rate, rssi); + } + + DPRINTFN(5, ("Rx frame len=%d rate=%d infosz=%d shift=%d rssi=%d\n", + pktlen, rate, infosz, shift, rssi)); + + m1 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); + if (m1 == NULL) { + counter_u64_add(ic->ic_ierrors, 1); + return; + } + bus_dmamap_unload(sc->rx_ring.data_dmat, rx_data->map); + + error = bus_dmamap_load(sc->rx_ring.data_dmat, rx_data->map, + mtod(m1, void *), MCLBYTES, rtwn_dma_map_addr, + &physaddr, 0); + if (error != 0) { + m_freem(m1); + + if (bus_dmamap_load_mbuf_sg(sc->rx_ring.data_dmat, + rx_data->map, rx_data->m, segs, &nsegs, 0)) + panic("%s: could not load old RX mbuf", + device_get_name(sc->sc_dev)); + + /* Physical address may have changed. */ + rtwn_setup_rx_desc(sc, rx_desc, physaddr, MCLBYTES, desc_idx); + counter_u64_add(ic->ic_ierrors, 1); + return; + } + + /* Finalize mbuf. */ + m = rx_data->m; + rx_data->m = m1; + m->m_pkthdr.len = m->m_len = pktlen + infosz + shift; + + /* Update RX descriptor. */ + rtwn_setup_rx_desc(sc, rx_desc, physaddr, MCLBYTES, desc_idx); + + /* Get ieee80211 frame header. */ + if (rxdw0 & R92C_RXDW0_PHYST) + m_adj(m, infosz + shift); + else + m_adj(m, shift); + + nf = -95; + if (ieee80211_radiotap_active(ic)) { + struct rtwn_rx_radiotap_header *tap = &sc->sc_rxtap; + + tap->wr_flags = 0; + if (!(rxdw3 & R92C_RXDW3_HT)) { + switch (rate) { + /* CCK. */ + case 0: tap->wr_rate = 2; break; + case 1: tap->wr_rate = 4; break; + case 2: tap->wr_rate = 11; break; + case 3: tap->wr_rate = 22; break; + /* OFDM. */ + case 4: tap->wr_rate = 12; break; + case 5: tap->wr_rate = 18; break; + case 6: tap->wr_rate = 24; break; + case 7: tap->wr_rate = 36; break; + case 8: tap->wr_rate = 48; break; + case 9: tap->wr_rate = 72; break; + case 10: tap->wr_rate = 96; break; + case 11: tap->wr_rate = 108; break; + } + } else if (rate >= 12) { /* MCS0~15. */ + /* Bit 7 set means HT MCS instead of rate. */ + tap->wr_rate = 0x80 | (rate - 12); + } + tap->wr_dbm_antsignal = rssi; + tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq); + tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags); + } + + RTWN_UNLOCK(sc); + wh = mtod(m, struct ieee80211_frame *); + + /* Send the frame to the 802.11 layer. */ + ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh); + if (ni != NULL) { + (void)ieee80211_input(ni, m, rssi - nf, nf); + /* Node is no longer needed. */ + ieee80211_free_node(ni); + } else + (void)ieee80211_input_all(ic, m, rssi - nf, nf); + + RTWN_LOCK(sc); +} + +static int +rtwn_tx(struct rtwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211_frame *wh; + struct ieee80211_key *k = NULL; + struct rtwn_tx_ring *tx_ring; + struct rtwn_tx_data *data; + struct r92c_tx_desc *txd; + bus_dma_segment_t segs[1]; + uint16_t qos; + uint8_t raid, type, tid, qid; + int nsegs, error; + + wh = mtod(m, struct ieee80211_frame *); + type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + + /* Encrypt the frame if need be. */ + if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { + k = ieee80211_crypto_encap(ni, m); + if (k == NULL) { + m_freem(m); + return (ENOBUFS); + } + /* 802.11 header may have moved. */ + wh = mtod(m, struct ieee80211_frame *); + } + + if (IEEE80211_QOS_HAS_SEQ(wh)) { + qos = ((const struct ieee80211_qosframe *)wh)->i_qos[0]; + tid = qos & IEEE80211_QOS_TID; + } else { + qos = 0; + tid = 0; + } + + switch (type) { + case IEEE80211_FC0_TYPE_CTL: + case IEEE80211_FC0_TYPE_MGT: + qid = RTWN_VO_QUEUE; + break; + default: + qid = M_WME_GETAC(m); + break; + } + + /* Grab a Tx buffer from the ring. */ + tx_ring = &sc->tx_ring[qid]; + data = &tx_ring->tx_data[tx_ring->cur]; + if (data->m != NULL) { + m_freem(m); + return (ENOBUFS); + } + + /* Fill Tx descriptor. */ + txd = &tx_ring->desc[tx_ring->cur]; + if (htole32(txd->txdw0) & R92C_RXDW0_OWN) { + m_freem(m); + return (ENOBUFS); + } + txd->txdw0 = htole32( + SM(R92C_TXDW0_PKTLEN, m->m_pkthdr.len) | + SM(R92C_TXDW0_OFFSET, sizeof(*txd)) | + R92C_TXDW0_FSG | R92C_TXDW0_LSG); + if (IEEE80211_IS_MULTICAST(wh->i_addr1)) + txd->txdw0 |= htole32(R92C_TXDW0_BMCAST); + + txd->txdw1 = 0; + txd->txdw4 = 0; + txd->txdw5 = 0; + + /* XXX TODO: rate control; implement low-rate for EAPOL */ + if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && + type == IEEE80211_FC0_TYPE_DATA) { + if (ic->ic_curmode == IEEE80211_MODE_11B) + raid = R92C_RAID_11B; + else + raid = R92C_RAID_11BG; + txd->txdw1 |= htole32( + SM(R92C_TXDW1_MACID, RTWN_MACID_BSS) | + SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_BE) | + SM(R92C_TXDW1_RAID, raid) | + R92C_TXDW1_AGGBK); + + if (ic->ic_flags & IEEE80211_F_USEPROT) { + if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) { + txd->txdw4 |= htole32(R92C_TXDW4_CTS2SELF | + R92C_TXDW4_HWRTSEN); + } else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) { + txd->txdw4 |= htole32(R92C_TXDW4_RTSEN | + R92C_TXDW4_HWRTSEN); + } + } + + /* XXX TODO: implement rate control */ + + /* Send RTS at OFDM24. */ + txd->txdw4 |= htole32(SM(R92C_TXDW4_RTSRATE, 8)); + txd->txdw5 |= htole32(SM(R92C_TXDW5_RTSRATE_FBLIMIT, 0xf)); + /* Send data at OFDM54. */ + txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, 11)); + txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE_FBLIMIT, 0x1f)); + + } else { + txd->txdw1 |= htole32( + SM(R92C_TXDW1_MACID, 0) | + SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT) | + SM(R92C_TXDW1_RAID, R92C_RAID_11B)); + + /* Force CCK1. */ + txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE); + txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, 0)); + } + /* Set sequence number (already little endian). */ + txd->txdseq = *(uint16_t *)wh->i_seq; + + if (!qos) { + /* Use HW sequence numbering for non-QoS frames. */ + txd->txdw4 |= htole32(R92C_TXDW4_HWSEQ); + txd->txdseq |= htole16(0x8000); + } else + txd->txdw4 |= htole32(R92C_TXDW4_QOS); + + error = bus_dmamap_load_mbuf_sg(tx_ring->data_dmat, data->map, m, segs, + &nsegs, BUS_DMA_NOWAIT); + if (error != 0 && error != EFBIG) { + device_printf(sc->sc_dev, "can't map mbuf (error %d)\n", error); + m_freem(m); + return (error); + } + if (error != 0) { + struct mbuf *mnew; + + mnew = m_defrag(m, M_NOWAIT); + if (mnew == NULL) { + device_printf(sc->sc_dev, + "can't defragment mbuf\n"); + m_freem(m); + return (ENOBUFS); + } + m = mnew; + + error = bus_dmamap_load_mbuf_sg(tx_ring->data_dmat, data->map, + m, segs, &nsegs, BUS_DMA_NOWAIT); + if (error != 0) { + device_printf(sc->sc_dev, + "can't map mbuf (error %d)\n", error); + m_freem(m); + return (error); + } + } + + txd->txbufaddr = htole32(segs[0].ds_addr); + txd->txbufsize = htole16(m->m_pkthdr.len); + bus_space_barrier(sc->sc_st, sc->sc_sh, 0, sc->sc_mapsize, + BUS_SPACE_BARRIER_WRITE); + txd->txdw0 |= htole32(R92C_TXDW0_OWN); + + bus_dmamap_sync(tx_ring->desc_dmat, tx_ring->desc_map, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_sync(tx_ring->data_dmat, data->map, BUS_DMASYNC_POSTWRITE); + + data->m = m; + data->ni = ni; + + if (ieee80211_radiotap_active_vap(vap)) { + struct rtwn_tx_radiotap_header *tap = &sc->sc_txtap; + + tap->wt_flags = 0; + tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq); + tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags); + + ieee80211_radiotap_tx(vap, m); + } + + tx_ring->cur = (tx_ring->cur + 1) % RTWN_TX_LIST_COUNT; + tx_ring->queued++; + + if (tx_ring->queued >= (RTWN_TX_LIST_COUNT - 1)) + sc->qfullmsk |= (1 << qid); + + /* Kick TX. */ + rtwn_write_2(sc, R92C_PCIE_CTRL_REG, (1 << qid)); + return (0); +} + +static void +rtwn_tx_done(struct rtwn_softc *sc, int qid) +{ + struct rtwn_tx_ring *tx_ring = &sc->tx_ring[qid]; + struct rtwn_tx_data *tx_data; + struct r92c_tx_desc *tx_desc; + int i; + + bus_dmamap_sync(tx_ring->desc_dmat, tx_ring->desc_map, + BUS_DMASYNC_POSTREAD); + + for (i = 0; i < RTWN_TX_LIST_COUNT; i++) { + tx_data = &tx_ring->tx_data[i]; + if (tx_data->m == NULL) + continue; + + tx_desc = &tx_ring->desc[i]; + if (le32toh(tx_desc->txdw0) & R92C_TXDW0_OWN) + continue; + + bus_dmamap_unload(tx_ring->desc_dmat, tx_ring->desc_map); + + /* + * XXX TODO: figure out whether the transmit succeeded or not. + * .. and then notify rate control. + */ + ieee80211_tx_complete(tx_data->ni, tx_data->m, 0); + tx_data->ni = NULL; + tx_data->m = NULL; + + sc->sc_tx_timer = 0; + tx_ring->queued--; + } + + if (tx_ring->queued < (RTWN_TX_LIST_COUNT - 1)) + sc->qfullmsk &= ~(1 << qid); + rtwn_start(sc); +} + +static int +rtwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, + const struct ieee80211_bpf_params *params) +{ + struct ieee80211com *ic = ni->ni_ic; + struct rtwn_softc *sc = ic->ic_softc; + + RTWN_LOCK(sc); + + /* Prevent management frames from being sent if we're not ready. */ + if (!(sc->sc_flags & RTWN_RUNNING)) { + RTWN_UNLOCK(sc); + m_freem(m); + return (ENETDOWN); + } + + if (rtwn_tx(sc, m, ni) != 0) { + m_freem(m); + RTWN_UNLOCK(sc); + return (EIO); + } + sc->sc_tx_timer = 5; + RTWN_UNLOCK(sc); + return (0); +} + +static int +rtwn_transmit(struct ieee80211com *ic, struct mbuf *m) +{ + struct rtwn_softc *sc = ic->ic_softc; + int error; + + RTWN_LOCK(sc); + if ((sc->sc_flags & RTWN_RUNNING) == 0) { + RTWN_UNLOCK(sc); + return (ENXIO); + } + error = mbufq_enqueue(&sc->sc_snd, m); + if (error) { + RTWN_UNLOCK(sc); + return (error); + } + rtwn_start(sc); + RTWN_UNLOCK(sc); + return (0); +} + +static void +rtwn_parent(struct ieee80211com *ic) +{ + struct rtwn_softc *sc = ic->ic_softc; + int startall = 0; + + RTWN_LOCK(sc); + if (ic->ic_nrunning> 0) { + if (!(sc->sc_flags & RTWN_RUNNING)) { + rtwn_init_locked(sc); + startall = 1; + } + } else if (sc->sc_flags & RTWN_RUNNING) + rtwn_stop_locked(sc); + RTWN_UNLOCK(sc); + if (startall) + ieee80211_start_all(ic); +} + +static void +rtwn_start(struct rtwn_softc *sc) +{ + struct ieee80211_node *ni; + struct mbuf *m; + + RTWN_LOCK_ASSERT(sc); + + if ((sc->sc_flags & RTWN_RUNNING) == 0) + return; + + while (sc->qfullmsk == 0 && (m = mbufq_dequeue(&sc->sc_snd)) != NULL) { + ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; + if (rtwn_tx(sc, m, ni) != 0) { + if_inc_counter(ni->ni_vap->iv_ifp, + IFCOUNTER_OERRORS, 1); + ieee80211_free_node(ni); + continue; + } + sc->sc_tx_timer = 5; + } +} + +static void +rtwn_watchdog(void *arg) +{ + struct rtwn_softc *sc = arg; + struct ieee80211com *ic = &sc->sc_ic; + + RTWN_LOCK_ASSERT(sc); + + KASSERT(sc->sc_flags & RTWN_RUNNING, ("not running")); + + if (sc->sc_tx_timer != 0 && --sc->sc_tx_timer == 0) { + ic_printf(ic, "device timeout\n"); + ieee80211_runtask(ic, &sc->sc_reinit_task); + return; + } + callout_reset(&sc->watchdog_to, hz, rtwn_watchdog, sc); +} + +static int +rtwn_power_on(struct rtwn_softc *sc) +{ + uint32_t reg; + int ntries; + + /* Wait for autoload done bit. */ + for (ntries = 0; ntries < 1000; ntries++) { + if (rtwn_read_1(sc, R92C_APS_FSMCO) & R92C_APS_FSMCO_PFM_ALDN) + break; + DELAY(5); + } + if (ntries == 1000) { + device_printf(sc->sc_dev, + "timeout waiting for chip autoload\n"); + return (ETIMEDOUT); + } + + /* Unlock ISO/CLK/Power control register. */ + rtwn_write_1(sc, R92C_RSV_CTRL, 0); + + /* TODO: check if we need this for 8188CE */ + if (sc->board_type != R92C_BOARD_TYPE_DONGLE) { + /* bt coex */ + reg = rtwn_read_4(sc, R92C_APS_FSMCO); + reg |= (R92C_APS_FSMCO_SOP_ABG | + R92C_APS_FSMCO_SOP_AMB | + R92C_APS_FSMCO_XOP_BTCK); + rtwn_write_4(sc, R92C_APS_FSMCO, reg); + } + + /* Move SPS into PWM mode. */ + rtwn_write_1(sc, R92C_SPS0_CTRL, 0x2b); + + /* Set low byte to 0x0f, leave others unchanged. */ + rtwn_write_4(sc, R92C_AFE_XTAL_CTRL, + (rtwn_read_4(sc, R92C_AFE_XTAL_CTRL) & 0xffffff00) | 0x0f); + + /* TODO: check if we need this for 8188CE */ + if (sc->board_type != R92C_BOARD_TYPE_DONGLE) { + /* bt coex */ + reg = rtwn_read_4(sc, R92C_AFE_XTAL_CTRL); + reg &= (~0x00024800); /* XXX magic from linux */ + rtwn_write_4(sc, R92C_AFE_XTAL_CTRL, reg); + } + + rtwn_write_2(sc, R92C_SYS_ISO_CTRL, + (rtwn_read_2(sc, R92C_SYS_ISO_CTRL) & 0xff) | + R92C_SYS_ISO_CTRL_PWC_EV12V | R92C_SYS_ISO_CTRL_DIOR); + DELAY(200); + + /* TODO: linux does additional btcoex stuff here */ + + /* Auto enable WLAN. */ + rtwn_write_2(sc, R92C_APS_FSMCO, + rtwn_read_2(sc, R92C_APS_FSMCO) | R92C_APS_FSMCO_APFM_ONMAC); + for (ntries = 0; ntries < 1000; ntries++) { + if (!(rtwn_read_2(sc, R92C_APS_FSMCO) & + R92C_APS_FSMCO_APFM_ONMAC)) + break; + DELAY(5); + } + if (ntries == 1000) { + device_printf(sc->sc_dev, "timeout waiting for MAC auto ON\n"); + return (ETIMEDOUT); + } + + /* Enable radio, GPIO and LED functions. */ + rtwn_write_2(sc, R92C_APS_FSMCO, + R92C_APS_FSMCO_AFSM_PCIE | + R92C_APS_FSMCO_PDN_EN | + R92C_APS_FSMCO_PFM_ALDN); + /* Release RF digital isolation. */ + rtwn_write_2(sc, R92C_SYS_ISO_CTRL, + rtwn_read_2(sc, R92C_SYS_ISO_CTRL) & ~R92C_SYS_ISO_CTRL_DIOR); + + if (sc->chip & RTWN_CHIP_92C) + rtwn_write_1(sc, R92C_PCIE_CTRL_REG + 3, 0x77); + else + rtwn_write_1(sc, R92C_PCIE_CTRL_REG + 3, 0x22); + + rtwn_write_4(sc, R92C_INT_MIG, 0); + + if (sc->board_type != R92C_BOARD_TYPE_DONGLE) { + /* bt coex */ + reg = rtwn_read_4(sc, R92C_AFE_XTAL_CTRL + 2); + reg &= 0xfd; /* XXX magic from linux */ + rtwn_write_4(sc, R92C_AFE_XTAL_CTRL + 2, reg); + } + + rtwn_write_1(sc, R92C_GPIO_MUXCFG, + rtwn_read_1(sc, R92C_GPIO_MUXCFG) & ~R92C_GPIO_MUXCFG_RFKILL); + + reg = rtwn_read_1(sc, R92C_GPIO_IO_SEL); + if (!(reg & R92C_GPIO_IO_SEL_RFKILL)) { + device_printf(sc->sc_dev, + "radio is disabled by hardware switch\n"); + return (EPERM); + } + + /* Initialize MAC. */ + reg = rtwn_read_1(sc, R92C_APSD_CTRL); + rtwn_write_1(sc, R92C_APSD_CTRL, + rtwn_read_1(sc, R92C_APSD_CTRL) & ~R92C_APSD_CTRL_OFF); + for (ntries = 0; ntries < 200; ntries++) { + if (!(rtwn_read_1(sc, R92C_APSD_CTRL) & + R92C_APSD_CTRL_OFF_STATUS)) + break; + DELAY(500); + } + if (ntries == 200) { + device_printf(sc->sc_dev, + "timeout waiting for MAC initialization\n"); + return (ETIMEDOUT); + } + + /* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */ + reg = rtwn_read_2(sc, R92C_CR); + reg |= R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN | + R92C_CR_TXDMA_EN | R92C_CR_RXDMA_EN | R92C_CR_PROTOCOL_EN | + R92C_CR_SCHEDULE_EN | R92C_CR_MACTXEN | R92C_CR_MACRXEN | + R92C_CR_ENSEC; + rtwn_write_2(sc, R92C_CR, reg); + + rtwn_write_1(sc, 0xfe10, 0x19); + + return (0); +} + +static int +rtwn_llt_init(struct rtwn_softc *sc) +{ + int i, error; + + /* Reserve pages [0; R92C_TX_PAGE_COUNT]. */ + for (i = 0; i < R92C_TX_PAGE_COUNT; i++) { + if ((error = rtwn_llt_write(sc, i, i + 1)) != 0) + return (error); + } + /* NB: 0xff indicates end-of-list. */ + if ((error = rtwn_llt_write(sc, i, 0xff)) != 0) + return (error); + /* + * Use pages [R92C_TX_PAGE_COUNT + 1; R92C_TXPKTBUF_COUNT - 1] + * as ring buffer. + */ + for (++i; i < R92C_TXPKTBUF_COUNT - 1; i++) { + if ((error = rtwn_llt_write(sc, i, i + 1)) != 0) + return (error); + } + /* Make the last page point to the beginning of the ring buffer. */ + error = rtwn_llt_write(sc, i, R92C_TX_PAGE_COUNT + 1); + return (error); +} + +static void +rtwn_fw_reset(struct rtwn_softc *sc) +{ + uint16_t reg; + int ntries; + + /* Tell 8051 to reset itself. */ + rtwn_write_1(sc, R92C_HMETFR + 3, 0x20); + + /* Wait until 8051 resets by itself. */ + for (ntries = 0; ntries < 100; ntries++) { + reg = rtwn_read_2(sc, R92C_SYS_FUNC_EN); + if (!(reg & R92C_SYS_FUNC_EN_CPUEN)) + goto sleep; + DELAY(50); + } + /* Force 8051 reset. */ + rtwn_write_2(sc, R92C_SYS_FUNC_EN, reg & ~R92C_SYS_FUNC_EN_CPUEN); +sleep: + /* + * We must sleep for one second to let the firmware settle. + * Accessing registers too early will hang the whole system. + */ + if (msleep(®, &sc->sc_mtx, 0, "rtwnrst", hz)) { + device_printf(sc->sc_dev, "timeout waiting for firmware " + "initialization to complete\n"); + } +} + +static void +rtwn_fw_loadpage(struct rtwn_softc *sc, int page, const uint8_t *buf, int len) +{ + uint32_t reg; + int off, mlen, i; + + reg = rtwn_read_4(sc, R92C_MCUFWDL); + reg = RW(reg, R92C_MCUFWDL_PAGE, page); + rtwn_write_4(sc, R92C_MCUFWDL, reg); + + DELAY(5); + + off = R92C_FW_START_ADDR; + while (len > 0) { + if (len > 196) + mlen = 196; + else if (len > 4) + mlen = 4; + else + mlen = 1; + for (i = 0; i < mlen; i++) + rtwn_write_1(sc, off++, buf[i]); + buf += mlen; + len -= mlen; + } +} + +static int +rtwn_load_firmware(struct rtwn_softc *sc) +{ + const struct firmware *fw; + const struct r92c_fw_hdr *hdr; + const char *name; + const u_char *ptr; + size_t len; + uint32_t reg; + int mlen, ntries, page, error = 0; + + /* Read firmware image from the filesystem. */ + if ((sc->chip & (RTWN_CHIP_UMC_A_CUT | RTWN_CHIP_92C)) == + RTWN_CHIP_UMC_A_CUT) + name = "rtwn-rtl8192cfwU"; + else + name = "rtwn-rtl8192cfwU_B"; + RTWN_UNLOCK(sc); + fw = firmware_get(name); + RTWN_LOCK(sc); + if (fw == NULL) { + device_printf(sc->sc_dev, + "could not read firmware %s\n", name); + return (ENOENT); + } + len = fw->datasize; + if (len < sizeof(*hdr)) { + device_printf(sc->sc_dev, "firmware too short\n"); + error = EINVAL; + goto fail; + } + ptr = fw->data; + hdr = (const struct r92c_fw_hdr *)ptr; + /* Check if there is a valid FW header and skip it. */ + if ((le16toh(hdr->signature) >> 4) == 0x88c || + (le16toh(hdr->signature) >> 4) == 0x92c) { + DPRINTF(("FW V%d.%d %02d-%02d %02d:%02d\n", + le16toh(hdr->version), le16toh(hdr->subversion), + hdr->month, hdr->date, hdr->hour, hdr->minute)); + ptr += sizeof(*hdr); + len -= sizeof(*hdr); + } + + if (rtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RAM_DL_SEL) + rtwn_fw_reset(sc); + + /* Enable FW download. */ + rtwn_write_2(sc, R92C_SYS_FUNC_EN, + rtwn_read_2(sc, R92C_SYS_FUNC_EN) | + R92C_SYS_FUNC_EN_CPUEN); + rtwn_write_1(sc, R92C_MCUFWDL, + rtwn_read_1(sc, R92C_MCUFWDL) | R92C_MCUFWDL_EN); + rtwn_write_1(sc, R92C_MCUFWDL + 2, + rtwn_read_1(sc, R92C_MCUFWDL + 2) & ~0x08); + + /* Reset the FWDL checksum. */ + rtwn_write_1(sc, R92C_MCUFWDL, + rtwn_read_1(sc, R92C_MCUFWDL) | R92C_MCUFWDL_CHKSUM_RPT); + + for (page = 0; len > 0; page++) { + mlen = MIN(len, R92C_FW_PAGE_SIZE); + rtwn_fw_loadpage(sc, page, ptr, mlen); + ptr += mlen; + len -= mlen; + } + + /* Disable FW download. */ + rtwn_write_1(sc, R92C_MCUFWDL, + rtwn_read_1(sc, R92C_MCUFWDL) & ~R92C_MCUFWDL_EN); + rtwn_write_1(sc, R92C_MCUFWDL + 1, 0); + + /* Wait for checksum report. */ + for (ntries = 0; ntries < 1000; ntries++) { + if (rtwn_read_4(sc, R92C_MCUFWDL) & R92C_MCUFWDL_CHKSUM_RPT) + break; + DELAY(5); + } + if (ntries == 1000) { + device_printf(sc->sc_dev, + "timeout waiting for checksum report\n"); + error = ETIMEDOUT; + goto fail; + } + + reg = rtwn_read_4(sc, R92C_MCUFWDL); + reg = (reg & ~R92C_MCUFWDL_WINTINI_RDY) | R92C_MCUFWDL_RDY; + rtwn_write_4(sc, R92C_MCUFWDL, reg); + /* Wait for firmware readiness. */ + for (ntries = 0; ntries < 2000; ntries++) { + if (rtwn_read_4(sc, R92C_MCUFWDL) & R92C_MCUFWDL_WINTINI_RDY) + break; + DELAY(50); + } + if (ntries == 1000) { + device_printf(sc->sc_dev, + "timeout waiting for firmware readiness\n"); + error = ETIMEDOUT; + goto fail; + } +fail: + firmware_put(fw, FIRMWARE_UNLOAD); + return (error); +} + +static int +rtwn_dma_init(struct rtwn_softc *sc) +{ + uint32_t reg; + int error; + + /* Initialize LLT table. */ + error = rtwn_llt_init(sc); + if (error != 0) + return error; + + /* Set number of pages for normal priority queue. */ + rtwn_write_2(sc, R92C_RQPN_NPQ, 0); + rtwn_write_4(sc, R92C_RQPN, + /* Set number of pages for public queue. */ + SM(R92C_RQPN_PUBQ, R92C_PUBQ_NPAGES) | + /* Set number of pages for high priority queue. */ + SM(R92C_RQPN_HPQ, R92C_HPQ_NPAGES) | + /* Set number of pages for low priority queue. */ + SM(R92C_RQPN_LPQ, R92C_LPQ_NPAGES) | + /* Load values. */ + R92C_RQPN_LD); + + rtwn_write_1(sc, R92C_TXPKTBUF_BCNQ_BDNY, R92C_TX_PAGE_BOUNDARY); + rtwn_write_1(sc, R92C_TXPKTBUF_MGQ_BDNY, R92C_TX_PAGE_BOUNDARY); + rtwn_write_1(sc, R92C_TXPKTBUF_WMAC_LBK_BF_HD, R92C_TX_PAGE_BOUNDARY); + rtwn_write_1(sc, R92C_TRXFF_BNDY, R92C_TX_PAGE_BOUNDARY); + rtwn_write_1(sc, R92C_TDECTRL + 1, R92C_TX_PAGE_BOUNDARY); + + reg = rtwn_read_2(sc, R92C_TRXDMA_CTRL); + reg &= ~R92C_TRXDMA_CTRL_QMAP_M; + reg |= 0xF771; + rtwn_write_2(sc, R92C_TRXDMA_CTRL, reg); + + rtwn_write_4(sc, R92C_TCR, R92C_TCR_CFENDFORM | (1 << 12) | (1 << 13)); + + /* Configure Tx DMA. */ + rtwn_write_4(sc, R92C_BKQ_DESA, sc->tx_ring[RTWN_BK_QUEUE].paddr); + rtwn_write_4(sc, R92C_BEQ_DESA, sc->tx_ring[RTWN_BE_QUEUE].paddr); + rtwn_write_4(sc, R92C_VIQ_DESA, sc->tx_ring[RTWN_VI_QUEUE].paddr); + rtwn_write_4(sc, R92C_VOQ_DESA, sc->tx_ring[RTWN_VO_QUEUE].paddr); + rtwn_write_4(sc, R92C_BCNQ_DESA, sc->tx_ring[RTWN_BEACON_QUEUE].paddr); + rtwn_write_4(sc, R92C_MGQ_DESA, sc->tx_ring[RTWN_MGNT_QUEUE].paddr); + rtwn_write_4(sc, R92C_HQ_DESA, sc->tx_ring[RTWN_HIGH_QUEUE].paddr); + + /* Configure Rx DMA. */ + rtwn_write_4(sc, R92C_RX_DESA, sc->rx_ring.paddr); + + /* Set Tx/Rx transfer page boundary. */ + rtwn_write_2(sc, R92C_TRXFF_BNDY + 2, 0x27ff); + + /* Set Tx/Rx transfer page size. */ + rtwn_write_1(sc, R92C_PBP, + SM(R92C_PBP_PSRX, R92C_PBP_128) | + SM(R92C_PBP_PSTX, R92C_PBP_128)); + return (0); +} + +static void +rtwn_mac_init(struct rtwn_softc *sc) +{ + int i; + + /* Write MAC initialization values. */ + for (i = 0; i < nitems(rtl8192ce_mac); i++) + rtwn_write_1(sc, rtl8192ce_mac[i].reg, rtl8192ce_mac[i].val); +} + +static void +rtwn_bb_init(struct rtwn_softc *sc) +{ + const struct rtwn_bb_prog *prog; + uint32_t reg; + int i; + + /* Enable BB and RF. */ + rtwn_write_2(sc, R92C_SYS_FUNC_EN, + rtwn_read_2(sc, R92C_SYS_FUNC_EN) | + R92C_SYS_FUNC_EN_BBRSTB | R92C_SYS_FUNC_EN_BB_GLB_RST | + R92C_SYS_FUNC_EN_DIO_RF); + + rtwn_write_2(sc, R92C_AFE_PLL_CTRL, 0xdb83); + + rtwn_write_1(sc, R92C_RF_CTRL, + R92C_RF_CTRL_EN | R92C_RF_CTRL_RSTB | R92C_RF_CTRL_SDMRSTB); + + rtwn_write_1(sc, R92C_SYS_FUNC_EN, + R92C_SYS_FUNC_EN_DIO_PCIE | R92C_SYS_FUNC_EN_PCIEA | + R92C_SYS_FUNC_EN_PPLL | R92C_SYS_FUNC_EN_BB_GLB_RST | + R92C_SYS_FUNC_EN_BBRSTB); + + rtwn_write_1(sc, R92C_AFE_XTAL_CTRL + 1, 0x80); + + rtwn_write_4(sc, R92C_LEDCFG0, + rtwn_read_4(sc, R92C_LEDCFG0) | 0x00800000); + + /* Select BB programming. */ + prog = (sc->chip & RTWN_CHIP_92C) ? + &rtl8192ce_bb_prog_2t : &rtl8192ce_bb_prog_1t; + + /* Write BB initialization values. */ + for (i = 0; i < prog->count; i++) { + rtwn_bb_write(sc, prog->regs[i], prog->vals[i]); + DELAY(1); + } + + if (sc->chip & RTWN_CHIP_92C_1T2R) { + /* 8192C 1T only configuration. */ + reg = rtwn_bb_read(sc, R92C_FPGA0_TXINFO); + reg = (reg & ~0x00000003) | 0x2; + rtwn_bb_write(sc, R92C_FPGA0_TXINFO, reg); + + reg = rtwn_bb_read(sc, R92C_FPGA1_TXINFO); + reg = (reg & ~0x00300033) | 0x00200022; + rtwn_bb_write(sc, R92C_FPGA1_TXINFO, reg); + + reg = rtwn_bb_read(sc, R92C_CCK0_AFESETTING); + reg = (reg & ~0xff000000) | 0x45 << 24; + rtwn_bb_write(sc, R92C_CCK0_AFESETTING, reg); + + reg = rtwn_bb_read(sc, R92C_OFDM0_TRXPATHENA); + reg = (reg & ~0x000000ff) | 0x23; + rtwn_bb_write(sc, R92C_OFDM0_TRXPATHENA, reg); + + reg = rtwn_bb_read(sc, R92C_OFDM0_AGCPARAM1); + reg = (reg & ~0x00000030) | 1 << 4; + rtwn_bb_write(sc, R92C_OFDM0_AGCPARAM1, reg); + + reg = rtwn_bb_read(sc, 0xe74); + reg = (reg & ~0x0c000000) | 2 << 26; + rtwn_bb_write(sc, 0xe74, reg); + reg = rtwn_bb_read(sc, 0xe78); + reg = (reg & ~0x0c000000) | 2 << 26; + rtwn_bb_write(sc, 0xe78, reg); + reg = rtwn_bb_read(sc, 0xe7c); + reg = (reg & ~0x0c000000) | 2 << 26; + rtwn_bb_write(sc, 0xe7c, reg); + reg = rtwn_bb_read(sc, 0xe80); + reg = (reg & ~0x0c000000) | 2 << 26; + rtwn_bb_write(sc, 0xe80, reg); + reg = rtwn_bb_read(sc, 0xe88); + reg = (reg & ~0x0c000000) | 2 << 26; + rtwn_bb_write(sc, 0xe88, reg); + } + + /* Write AGC values. */ + for (i = 0; i < prog->agccount; i++) { + rtwn_bb_write(sc, R92C_OFDM0_AGCRSSITABLE, + prog->agcvals[i]); + DELAY(1); + } + + if (rtwn_bb_read(sc, R92C_HSSI_PARAM2(0)) & + R92C_HSSI_PARAM2_CCK_HIPWR) + sc->sc_flags |= RTWN_FLAG_CCK_HIPWR; +} + +static void +rtwn_rf_init(struct rtwn_softc *sc) +{ + const struct rtwn_rf_prog *prog; + uint32_t reg, type; + int i, j, idx, off; + + /* Select RF programming based on board type. */ + if (!(sc->chip & RTWN_CHIP_92C)) { + if (sc->board_type == R92C_BOARD_TYPE_MINICARD) + prog = rtl8188ce_rf_prog; + else if (sc->board_type == R92C_BOARD_TYPE_HIGHPA) + prog = rtl8188ru_rf_prog; + else + prog = rtl8188cu_rf_prog; + } else + prog = rtl8192ce_rf_prog; + + for (i = 0; i < sc->nrxchains; i++) { + /* Save RF_ENV control type. */ + idx = i / 2; + off = (i % 2) * 16; + reg = rtwn_bb_read(sc, R92C_FPGA0_RFIFACESW(idx)); + type = (reg >> off) & 0x10; + + /* Set RF_ENV enable. */ + reg = rtwn_bb_read(sc, R92C_FPGA0_RFIFACEOE(i)); + reg |= 0x100000; + rtwn_bb_write(sc, R92C_FPGA0_RFIFACEOE(i), reg); + DELAY(1); + /* Set RF_ENV output high. */ + reg = rtwn_bb_read(sc, R92C_FPGA0_RFIFACEOE(i)); + reg |= 0x10; + rtwn_bb_write(sc, R92C_FPGA0_RFIFACEOE(i), reg); + DELAY(1); + /* Set address and data lengths of RF registers. */ + reg = rtwn_bb_read(sc, R92C_HSSI_PARAM2(i)); + reg &= ~R92C_HSSI_PARAM2_ADDR_LENGTH; + rtwn_bb_write(sc, R92C_HSSI_PARAM2(i), reg); + DELAY(1); + reg = rtwn_bb_read(sc, R92C_HSSI_PARAM2(i)); + reg &= ~R92C_HSSI_PARAM2_DATA_LENGTH; + rtwn_bb_write(sc, R92C_HSSI_PARAM2(i), reg); + DELAY(1); + + /* Write RF initialization values for this chain. */ + for (j = 0; j < prog[i].count; j++) { + if (prog[i].regs[j] >= 0xf9 && + prog[i].regs[j] <= 0xfe) { + /* + * These are fake RF registers offsets that + * indicate a delay is required. + */ + DELAY(50); + continue; + } + rtwn_rf_write(sc, i, prog[i].regs[j], + prog[i].vals[j]); + DELAY(1); + } + + /* Restore RF_ENV control type. */ + reg = rtwn_bb_read(sc, R92C_FPGA0_RFIFACESW(idx)); + reg &= ~(0x10 << off) | (type << off); + rtwn_bb_write(sc, R92C_FPGA0_RFIFACESW(idx), reg); + + /* Cache RF register CHNLBW. */ + sc->rf_chnlbw[i] = rtwn_rf_read(sc, i, R92C_RF_CHNLBW); + } + + if ((sc->chip & (RTWN_CHIP_UMC_A_CUT | RTWN_CHIP_92C)) == + RTWN_CHIP_UMC_A_CUT) { + rtwn_rf_write(sc, 0, R92C_RF_RX_G1, 0x30255); + rtwn_rf_write(sc, 0, R92C_RF_RX_G2, 0x50a00); + } +} + +static void +rtwn_cam_init(struct rtwn_softc *sc) +{ + /* Invalidate all CAM entries. */ + rtwn_write_4(sc, R92C_CAMCMD, + R92C_CAMCMD_POLLING | R92C_CAMCMD_CLR); +} + +static void +rtwn_pa_bias_init(struct rtwn_softc *sc) +{ + uint8_t reg; + int i; + + for (i = 0; i < sc->nrxchains; i++) { + if (sc->pa_setting & (1 << i)) + continue; + rtwn_rf_write(sc, i, R92C_RF_IPA, 0x0f406); + rtwn_rf_write(sc, i, R92C_RF_IPA, 0x4f406); + rtwn_rf_write(sc, i, R92C_RF_IPA, 0x8f406); + rtwn_rf_write(sc, i, R92C_RF_IPA, 0xcf406); + } + if (!(sc->pa_setting & 0x10)) { + reg = rtwn_read_1(sc, 0x16); + reg = (reg & ~0xf0) | 0x90; + rtwn_write_1(sc, 0x16, reg); + } +} + +static void +rtwn_rxfilter_init(struct rtwn_softc *sc) +{ + /* Initialize Rx filter. */ + /* TODO: use better filter for monitor mode. */ + rtwn_write_4(sc, R92C_RCR, + R92C_RCR_AAP | R92C_RCR_APM | R92C_RCR_AM | R92C_RCR_AB | + R92C_RCR_APP_ICV | R92C_RCR_AMF | R92C_RCR_HTC_LOC_CTRL | + R92C_RCR_APP_MIC | R92C_RCR_APP_PHYSTS); + /* Accept all multicast frames. */ + rtwn_write_4(sc, R92C_MAR + 0, 0xffffffff); + rtwn_write_4(sc, R92C_MAR + 4, 0xffffffff); + /* Accept all management frames. */ + rtwn_write_2(sc, R92C_RXFLTMAP0, 0xffff); + /* Reject all control frames. */ + rtwn_write_2(sc, R92C_RXFLTMAP1, 0x0000); + /* Accept all data frames. */ + rtwn_write_2(sc, R92C_RXFLTMAP2, 0xffff); +} + +static void +rtwn_edca_init(struct rtwn_softc *sc) +{ + + rtwn_write_2(sc, R92C_SPEC_SIFS, 0x1010); + rtwn_write_2(sc, R92C_MAC_SPEC_SIFS, 0x1010); + rtwn_write_2(sc, R92C_SIFS_CCK, 0x1010); + rtwn_write_2(sc, R92C_SIFS_OFDM, 0x0e0e); + rtwn_write_4(sc, R92C_EDCA_BE_PARAM, 0x005ea42b); + rtwn_write_4(sc, R92C_EDCA_BK_PARAM, 0x0000a44f); + rtwn_write_4(sc, R92C_EDCA_VI_PARAM, 0x005e4322); + rtwn_write_4(sc, R92C_EDCA_VO_PARAM, 0x002f3222); +} + +static void +rtwn_write_txpower(struct rtwn_softc *sc, int chain, + uint16_t power[RTWN_RIDX_COUNT]) +{ + uint32_t reg; + + /* Write per-CCK rate Tx power. */ + if (chain == 0) { + reg = rtwn_bb_read(sc, R92C_TXAGC_A_CCK1_MCS32); + reg = RW(reg, R92C_TXAGC_A_CCK1, power[0]); + rtwn_bb_write(sc, R92C_TXAGC_A_CCK1_MCS32, reg); + reg = rtwn_bb_read(sc, R92C_TXAGC_B_CCK11_A_CCK2_11); + reg = RW(reg, R92C_TXAGC_A_CCK2, power[1]); + reg = RW(reg, R92C_TXAGC_A_CCK55, power[2]); + reg = RW(reg, R92C_TXAGC_A_CCK11, power[3]); + rtwn_bb_write(sc, R92C_TXAGC_B_CCK11_A_CCK2_11, reg); + } else { + reg = rtwn_bb_read(sc, R92C_TXAGC_B_CCK1_55_MCS32); + reg = RW(reg, R92C_TXAGC_B_CCK1, power[0]); + reg = RW(reg, R92C_TXAGC_B_CCK2, power[1]); + reg = RW(reg, R92C_TXAGC_B_CCK55, power[2]); + rtwn_bb_write(sc, R92C_TXAGC_B_CCK1_55_MCS32, reg); + reg = rtwn_bb_read(sc, R92C_TXAGC_B_CCK11_A_CCK2_11); + reg = RW(reg, R92C_TXAGC_B_CCK11, power[3]); + rtwn_bb_write(sc, R92C_TXAGC_B_CCK11_A_CCK2_11, reg); + } + /* Write per-OFDM rate Tx power. */ + rtwn_bb_write(sc, R92C_TXAGC_RATE18_06(chain), + SM(R92C_TXAGC_RATE06, power[ 4]) | + SM(R92C_TXAGC_RATE09, power[ 5]) | + SM(R92C_TXAGC_RATE12, power[ 6]) | + SM(R92C_TXAGC_RATE18, power[ 7])); + rtwn_bb_write(sc, R92C_TXAGC_RATE54_24(chain), + SM(R92C_TXAGC_RATE24, power[ 8]) | + SM(R92C_TXAGC_RATE36, power[ 9]) | + SM(R92C_TXAGC_RATE48, power[10]) | + SM(R92C_TXAGC_RATE54, power[11])); + /* Write per-MCS Tx power. */ + rtwn_bb_write(sc, R92C_TXAGC_MCS03_MCS00(chain), + SM(R92C_TXAGC_MCS00, power[12]) | + SM(R92C_TXAGC_MCS01, power[13]) | + SM(R92C_TXAGC_MCS02, power[14]) | + SM(R92C_TXAGC_MCS03, power[15])); + rtwn_bb_write(sc, R92C_TXAGC_MCS07_MCS04(chain), + SM(R92C_TXAGC_MCS04, power[16]) | + SM(R92C_TXAGC_MCS05, power[17]) | + SM(R92C_TXAGC_MCS06, power[18]) | + SM(R92C_TXAGC_MCS07, power[19])); + rtwn_bb_write(sc, R92C_TXAGC_MCS11_MCS08(chain), + SM(R92C_TXAGC_MCS08, power[20]) | + SM(R92C_TXAGC_MCS09, power[21]) | + SM(R92C_TXAGC_MCS10, power[22]) | + SM(R92C_TXAGC_MCS11, power[23])); + rtwn_bb_write(sc, R92C_TXAGC_MCS15_MCS12(chain), + SM(R92C_TXAGC_MCS12, power[24]) | + SM(R92C_TXAGC_MCS13, power[25]) | + SM(R92C_TXAGC_MCS14, power[26]) | + SM(R92C_TXAGC_MCS15, power[27])); +} + +static void +rtwn_get_txpower(struct rtwn_softc *sc, int chain, + struct ieee80211_channel *c, struct ieee80211_channel *extc, + uint16_t power[RTWN_RIDX_COUNT]) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct r92c_rom *rom = &sc->rom; + uint16_t cckpow, ofdmpow, htpow, diff, max; + const struct rtwn_txpwr *base; + int ridx, chan, group; + + /* Determine channel group. */ + chan = ieee80211_chan2ieee(ic, c); /* XXX center freq! */ + if (chan <= 3) + group = 0; + else if (chan <= 9) + group = 1; + else + group = 2; + + /* Get original Tx power based on board type and RF chain. */ + if (!(sc->chip & RTWN_CHIP_92C)) { + if (sc->board_type == R92C_BOARD_TYPE_HIGHPA) + base = &rtl8188ru_txagc[chain]; + else + base = &rtl8192cu_txagc[chain]; + } else + base = &rtl8192cu_txagc[chain]; + + memset(power, 0, RTWN_RIDX_COUNT * sizeof(power[0])); + if (sc->regulatory == 0) { + for (ridx = 0; ridx <= 3; ridx++) + power[ridx] = base->pwr[0][ridx]; + } + for (ridx = 4; ridx < RTWN_RIDX_COUNT; ridx++) { + if (sc->regulatory == 3) { + power[ridx] = base->pwr[0][ridx]; + /* Apply vendor limits. */ + if (extc != NULL) + max = rom->ht40_max_pwr[group]; + else + max = rom->ht20_max_pwr[group]; + max = (max >> (chain * 4)) & 0xf; + if (power[ridx] > max) + power[ridx] = max; + } else if (sc->regulatory == 1) { + if (extc == NULL) + power[ridx] = base->pwr[group][ridx]; + } else if (sc->regulatory != 2) + power[ridx] = base->pwr[0][ridx]; + } + + /* Compute per-CCK rate Tx power. */ + cckpow = rom->cck_tx_pwr[chain][group]; + for (ridx = 0; ridx <= 3; ridx++) { + power[ridx] += cckpow; + if (power[ridx] > R92C_MAX_TX_PWR) + power[ridx] = R92C_MAX_TX_PWR; + } + + htpow = rom->ht40_1s_tx_pwr[chain][group]; + if (sc->ntxchains > 1) { + /* Apply reduction for 2 spatial streams. */ + diff = rom->ht40_2s_tx_pwr_diff[group]; + diff = (diff >> (chain * 4)) & 0xf; + htpow = (htpow > diff) ? htpow - diff : 0; + } + + /* Compute per-OFDM rate Tx power. */ + diff = rom->ofdm_tx_pwr_diff[group]; + diff = (diff >> (chain * 4)) & 0xf; + ofdmpow = htpow + diff; /* HT->OFDM correction. */ + for (ridx = 4; ridx <= 11; ridx++) { + power[ridx] += ofdmpow; + if (power[ridx] > R92C_MAX_TX_PWR) + power[ridx] = R92C_MAX_TX_PWR; + } + + /* Compute per-MCS Tx power. */ + if (extc == NULL) { + diff = rom->ht20_tx_pwr_diff[group]; + diff = (diff >> (chain * 4)) & 0xf; + htpow += diff; /* HT40->HT20 correction. */ + } + for (ridx = 12; ridx <= 27; ridx++) { + power[ridx] += htpow; + if (power[ridx] > R92C_MAX_TX_PWR) + power[ridx] = R92C_MAX_TX_PWR; + } +#ifdef RTWN_DEBUG + if (sc->sc_debug >= 4) { + /* Dump per-rate Tx power values. */ + printf("Tx power for chain %d:\n", chain); + for (ridx = 0; ridx < RTWN_RIDX_COUNT; ridx++) + printf("Rate %d = %u\n", ridx, power[ridx]); + } +#endif +} + +static void +rtwn_set_txpower(struct rtwn_softc *sc, struct ieee80211_channel *c, + struct ieee80211_channel *extc) +{ + uint16_t power[RTWN_RIDX_COUNT]; + int i; + + for (i = 0; i < sc->ntxchains; i++) { + /* Compute per-rate Tx power values. */ + rtwn_get_txpower(sc, i, c, extc, power); + /* Write per-rate Tx power values to hardware. */ + rtwn_write_txpower(sc, i, power); + } +} + +static void +rtwn_scan_start(struct ieee80211com *ic) +{ + + /* XXX do nothing? */ +} + +static void +rtwn_scan_end(struct ieee80211com *ic) +{ + + /* XXX do nothing? */ +} + +static void +rtwn_set_channel(struct ieee80211com *ic) +{ + struct rtwn_softc *sc = ic->ic_softc; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + + RTWN_LOCK(sc); + if (vap->iv_state == IEEE80211_S_SCAN) { + /* Make link LED blink during scan. */ + rtwn_set_led(sc, RTWN_LED_LINK, !sc->ledlink); + } + rtwn_set_chan(sc, ic->ic_curchan, NULL); + RTWN_UNLOCK(sc); +} + +static void +rtwn_update_mcast(struct ieee80211com *ic) +{ + + /* XXX do nothing? */ +} + +static void +rtwn_set_chan(struct rtwn_softc *sc, struct ieee80211_channel *c, + struct ieee80211_channel *extc) +{ + struct ieee80211com *ic = &sc->sc_ic; + u_int chan; + int i; + + chan = ieee80211_chan2ieee(ic, c); /* XXX center freq! */ + if (chan == 0 || chan == IEEE80211_CHAN_ANY) { + device_printf(sc->sc_dev, + "%s: invalid channel %x\n", __func__, chan); + return; + } + + /* Set Tx power for this new channel. */ + rtwn_set_txpower(sc, c, extc); + + for (i = 0; i < sc->nrxchains; i++) { + rtwn_rf_write(sc, i, R92C_RF_CHNLBW, + RW(sc->rf_chnlbw[i], R92C_RF_CHNLBW_CHNL, chan)); + } +#ifndef IEEE80211_NO_HT + if (extc != NULL) { + uint32_t reg; + + /* Is secondary channel below or above primary? */ + int prichlo = c->ic_freq < extc->ic_freq; + + rtwn_write_1(sc, R92C_BWOPMODE, + rtwn_read_1(sc, R92C_BWOPMODE) & ~R92C_BWOPMODE_20MHZ); + + reg = rtwn_read_1(sc, R92C_RRSR + 2); + reg = (reg & ~0x6f) | (prichlo ? 1 : 2) << 5; + rtwn_write_1(sc, R92C_RRSR + 2, reg); + + rtwn_bb_write(sc, R92C_FPGA0_RFMOD, + rtwn_bb_read(sc, R92C_FPGA0_RFMOD) | R92C_RFMOD_40MHZ); + rtwn_bb_write(sc, R92C_FPGA1_RFMOD, + rtwn_bb_read(sc, R92C_FPGA1_RFMOD) | R92C_RFMOD_40MHZ); + + /* Set CCK side band. */ + reg = rtwn_bb_read(sc, R92C_CCK0_SYSTEM); + reg = (reg & ~0x00000010) | (prichlo ? 0 : 1) << 4; + rtwn_bb_write(sc, R92C_CCK0_SYSTEM, reg); + + reg = rtwn_bb_read(sc, R92C_OFDM1_LSTF); + reg = (reg & ~0x00000c00) | (prichlo ? 1 : 2) << 10; + rtwn_bb_write(sc, R92C_OFDM1_LSTF, reg); + + rtwn_bb_write(sc, R92C_FPGA0_ANAPARAM2, + rtwn_bb_read(sc, R92C_FPGA0_ANAPARAM2) & + ~R92C_FPGA0_ANAPARAM2_CBW20); + + reg = rtwn_bb_read(sc, 0x818); + reg = (reg & ~0x0c000000) | (prichlo ? 2 : 1) << 26; + rtwn_bb_write(sc, 0x818, reg); + + /* Select 40MHz bandwidth. */ + rtwn_rf_write(sc, 0, R92C_RF_CHNLBW, + (sc->rf_chnlbw[0] & ~0xfff) | chan); + } else +#endif + { + rtwn_write_1(sc, R92C_BWOPMODE, + rtwn_read_1(sc, R92C_BWOPMODE) | R92C_BWOPMODE_20MHZ); + + rtwn_bb_write(sc, R92C_FPGA0_RFMOD, + rtwn_bb_read(sc, R92C_FPGA0_RFMOD) & ~R92C_RFMOD_40MHZ); + rtwn_bb_write(sc, R92C_FPGA1_RFMOD, + rtwn_bb_read(sc, R92C_FPGA1_RFMOD) & ~R92C_RFMOD_40MHZ); + + rtwn_bb_write(sc, R92C_FPGA0_ANAPARAM2, + rtwn_bb_read(sc, R92C_FPGA0_ANAPARAM2) | + R92C_FPGA0_ANAPARAM2_CBW20); + + /* Select 20MHz bandwidth. */ + rtwn_rf_write(sc, 0, R92C_RF_CHNLBW, + (sc->rf_chnlbw[0] & ~0xfff) | R92C_RF_CHNLBW_BW20 | chan); + } +} + +static int +rtwn_iq_calib_chain(struct rtwn_softc *sc, int chain, uint16_t tx[2], + uint16_t rx[2]) +{ + uint32_t status; + int offset = chain * 0x20; + + if (chain == 0) { /* IQ calibration for chain 0. */ + /* IQ calibration settings for chain 0. */ + rtwn_bb_write(sc, 0xe30, 0x10008c1f); + rtwn_bb_write(sc, 0xe34, 0x10008c1f); + rtwn_bb_write(sc, 0xe38, 0x82140102); + + if (sc->ntxchains > 1) { + rtwn_bb_write(sc, 0xe3c, 0x28160202); /* 2T */ + /* IQ calibration settings for chain 1. */ + rtwn_bb_write(sc, 0xe50, 0x10008c22); + rtwn_bb_write(sc, 0xe54, 0x10008c22); + rtwn_bb_write(sc, 0xe58, 0x82140102); + rtwn_bb_write(sc, 0xe5c, 0x28160202); + } else + rtwn_bb_write(sc, 0xe3c, 0x28160502); /* 1T */ + + /* LO calibration settings. */ + rtwn_bb_write(sc, 0xe4c, 0x001028d1); + /* We're doing LO and IQ calibration in one shot. */ + rtwn_bb_write(sc, 0xe48, 0xf9000000); + rtwn_bb_write(sc, 0xe48, 0xf8000000); + + } else { /* IQ calibration for chain 1. */ + /* We're doing LO and IQ calibration in one shot. */ + rtwn_bb_write(sc, 0xe60, 0x00000002); + rtwn_bb_write(sc, 0xe60, 0x00000000); + } + + /* Give LO and IQ calibrations the time to complete. */ + DELAY(1000); + + /* Read IQ calibration status. */ + status = rtwn_bb_read(sc, 0xeac); + + if (status & (1 << (28 + chain * 3))) + return (0); /* Tx failed. */ + /* Read Tx IQ calibration results. */ + tx[0] = (rtwn_bb_read(sc, 0xe94 + offset) >> 16) & 0x3ff; + tx[1] = (rtwn_bb_read(sc, 0xe9c + offset) >> 16) & 0x3ff; + if (tx[0] == 0x142 || tx[1] == 0x042) + return (0); /* Tx failed. */ + + if (status & (1 << (27 + chain * 3))) + return (1); /* Rx failed. */ + /* Read Rx IQ calibration results. */ + rx[0] = (rtwn_bb_read(sc, 0xea4 + offset) >> 16) & 0x3ff; + rx[1] = (rtwn_bb_read(sc, 0xeac + offset) >> 16) & 0x3ff; + if (rx[0] == 0x132 || rx[1] == 0x036) + return (1); /* Rx failed. */ + + return (3); /* Both Tx and Rx succeeded. */ +} + +static void +rtwn_iq_calib_run(struct rtwn_softc *sc, int n, uint16_t tx[2][2], + uint16_t rx[2][2]) +{ + /* Registers to save and restore during IQ calibration. */ + struct iq_cal_regs { + uint32_t adda[16]; + uint8_t txpause; + uint8_t bcn_ctrl; + uint8_t ustime_tsf; + uint32_t gpio_muxcfg; + uint32_t ofdm0_trxpathena; + uint32_t ofdm0_trmuxpar; + uint32_t fpga0_rfifacesw1; + } iq_cal_regs; + static const uint16_t reg_adda[16] = { + 0x85c, 0xe6c, 0xe70, 0xe74, + 0xe78, 0xe7c, 0xe80, 0xe84, + 0xe88, 0xe8c, 0xed0, 0xed4, + 0xed8, 0xedc, 0xee0, 0xeec + }; + int i, chain; + uint32_t hssi_param1; + + if (n == 0) { + for (i = 0; i < nitems(reg_adda); i++) + iq_cal_regs.adda[i] = rtwn_bb_read(sc, reg_adda[i]); + + iq_cal_regs.txpause = rtwn_read_1(sc, R92C_TXPAUSE); + iq_cal_regs.bcn_ctrl = rtwn_read_1(sc, R92C_BCN_CTRL); + iq_cal_regs.ustime_tsf = rtwn_read_1(sc, R92C_USTIME_TSF); + iq_cal_regs.gpio_muxcfg = rtwn_read_4(sc, R92C_GPIO_MUXCFG); + } + + if (sc->ntxchains == 1) { + rtwn_bb_write(sc, reg_adda[0], 0x0b1b25a0); + for (i = 1; i < nitems(reg_adda); i++) + rtwn_bb_write(sc, reg_adda[i], 0x0bdb25a0); + } else { + for (i = 0; i < nitems(reg_adda); i++) + rtwn_bb_write(sc, reg_adda[i], 0x04db25a4); + } + + hssi_param1 = rtwn_bb_read(sc, R92C_HSSI_PARAM1(0)); + if (!(hssi_param1 & R92C_HSSI_PARAM1_PI)) { + rtwn_bb_write(sc, R92C_HSSI_PARAM1(0), + hssi_param1 | R92C_HSSI_PARAM1_PI); + rtwn_bb_write(sc, R92C_HSSI_PARAM1(1), + hssi_param1 | R92C_HSSI_PARAM1_PI); + } + + if (n == 0) { + iq_cal_regs.ofdm0_trxpathena = + rtwn_bb_read(sc, R92C_OFDM0_TRXPATHENA); + iq_cal_regs.ofdm0_trmuxpar = + rtwn_bb_read(sc, R92C_OFDM0_TRMUXPAR); + iq_cal_regs.fpga0_rfifacesw1 = + rtwn_bb_read(sc, R92C_FPGA0_RFIFACESW(1)); + } + + rtwn_bb_write(sc, R92C_OFDM0_TRXPATHENA, 0x03a05600); + rtwn_bb_write(sc, R92C_OFDM0_TRMUXPAR, 0x000800e4); + rtwn_bb_write(sc, R92C_FPGA0_RFIFACESW(1), 0x22204000); + if (sc->ntxchains > 1) { + rtwn_bb_write(sc, R92C_LSSI_PARAM(0), 0x00010000); + rtwn_bb_write(sc, R92C_LSSI_PARAM(1), 0x00010000); + } + + rtwn_write_1(sc, R92C_TXPAUSE, 0x3f); + rtwn_write_1(sc, R92C_BCN_CTRL, iq_cal_regs.bcn_ctrl & ~(0x08)); + rtwn_write_1(sc, R92C_USTIME_TSF, iq_cal_regs.ustime_tsf & ~(0x08)); + rtwn_write_1(sc, R92C_GPIO_MUXCFG, + iq_cal_regs.gpio_muxcfg & ~(0x20)); + + rtwn_bb_write(sc, 0x0b68, 0x00080000); + if (sc->ntxchains > 1) + rtwn_bb_write(sc, 0x0b6c, 0x00080000); + + rtwn_bb_write(sc, 0x0e28, 0x80800000); + rtwn_bb_write(sc, 0x0e40, 0x01007c00); + rtwn_bb_write(sc, 0x0e44, 0x01004800); + + rtwn_bb_write(sc, 0x0b68, 0x00080000); + + for (chain = 0; chain < sc->ntxchains; chain++) { + if (chain > 0) { + /* Put chain 0 on standby. */ + rtwn_bb_write(sc, 0x0e28, 0x00); + rtwn_bb_write(sc, R92C_LSSI_PARAM(0), 0x00010000); + rtwn_bb_write(sc, 0x0e28, 0x80800000); + + /* Enable chain 1. */ + for (i = 0; i < nitems(reg_adda); i++) + rtwn_bb_write(sc, reg_adda[i], 0x0b1b25a4); + } + + /* Run IQ calibration twice. */ + for (i = 0; i < 2; i++) { + int ret; + + ret = rtwn_iq_calib_chain(sc, chain, + tx[chain], rx[chain]); + if (ret == 0) { + DPRINTF(("%s: chain %d: Tx failed.\n", + __func__, chain)); + tx[chain][0] = 0xff; + tx[chain][1] = 0xff; + rx[chain][0] = 0xff; + rx[chain][1] = 0xff; + } else if (ret == 1) { + DPRINTF(("%s: chain %d: Rx failed.\n", + __func__, chain)); + rx[chain][0] = 0xff; + rx[chain][1] = 0xff; + } else if (ret == 3) { + DPRINTF(("%s: chain %d: Both Tx and Rx " + "succeeded.\n", __func__, chain)); + } + } + + DPRINTF(("%s: results for run %d chain %d: tx[0]=0x%x, " + "tx[1]=0x%x rx[0]=0x%x rx[1]=0x%x\n", __func__, n, chain, + tx[chain][0], tx[chain][1], rx[chain][0], rx[chain][1])); + } + + rtwn_bb_write(sc, R92C_OFDM0_TRXPATHENA, + iq_cal_regs.ofdm0_trxpathena); + rtwn_bb_write(sc, R92C_FPGA0_RFIFACESW(1), + iq_cal_regs.fpga0_rfifacesw1); + rtwn_bb_write(sc, R92C_OFDM0_TRMUXPAR, iq_cal_regs.ofdm0_trmuxpar); + + rtwn_bb_write(sc, 0x0e28, 0x00); + rtwn_bb_write(sc, R92C_LSSI_PARAM(0), 0x00032ed3); + if (sc->ntxchains > 1) + rtwn_bb_write(sc, R92C_LSSI_PARAM(1), 0x00032ed3); + + if (n != 0) { + if (!(hssi_param1 & R92C_HSSI_PARAM1_PI)) { + rtwn_bb_write(sc, R92C_HSSI_PARAM1(0), hssi_param1); + rtwn_bb_write(sc, R92C_HSSI_PARAM1(1), hssi_param1); + } + + for (i = 0; i < nitems(reg_adda); i++) + rtwn_bb_write(sc, reg_adda[i], iq_cal_regs.adda[i]); + + rtwn_write_1(sc, R92C_TXPAUSE, iq_cal_regs.txpause); + rtwn_write_1(sc, R92C_BCN_CTRL, iq_cal_regs.bcn_ctrl); + rtwn_write_1(sc, R92C_USTIME_TSF, iq_cal_regs.ustime_tsf); + rtwn_write_4(sc, R92C_GPIO_MUXCFG, iq_cal_regs.gpio_muxcfg); + } +} + +#define RTWN_IQ_CAL_MAX_TOLERANCE 5 +static int +rtwn_iq_calib_compare_results(uint16_t tx1[2][2], uint16_t rx1[2][2], + uint16_t tx2[2][2], uint16_t rx2[2][2], int ntxchains) +{ + int chain, i, tx_ok[2], rx_ok[2]; + + tx_ok[0] = tx_ok[1] = rx_ok[0] = rx_ok[1] = 0; + for (chain = 0; chain < ntxchains; chain++) { + for (i = 0; i < 2; i++) { + if (tx1[chain][i] == 0xff || tx2[chain][i] == 0xff || + rx1[chain][i] == 0xff || rx2[chain][i] == 0xff) + continue; + + tx_ok[chain] = (abs(tx1[chain][i] - tx2[chain][i]) <= + RTWN_IQ_CAL_MAX_TOLERANCE); + + rx_ok[chain] = (abs(rx1[chain][i] - rx2[chain][i]) <= + RTWN_IQ_CAL_MAX_TOLERANCE); + } + } + + if (ntxchains > 1) + return (tx_ok[0] && tx_ok[1] && rx_ok[0] && rx_ok[1]); + else + return (tx_ok[0] && rx_ok[0]); +} +#undef RTWN_IQ_CAL_MAX_TOLERANCE + +static void +rtwn_iq_calib_write_results(struct rtwn_softc *sc, uint16_t tx[2], + uint16_t rx[2], int chain) +{ + uint32_t reg, val, x; + long y, tx_c; + + if (tx[0] == 0xff || tx[1] == 0xff) + return; + + reg = rtwn_bb_read(sc, R92C_OFDM0_TXIQIMBALANCE(chain)); + val = ((reg >> 22) & 0x3ff); + x = tx[0]; + if (x & 0x0200) + x |= 0xfc00; + reg = (((x * val) >> 8) & 0x3ff); + rtwn_bb_write(sc, R92C_OFDM0_TXIQIMBALANCE(chain), reg); + + reg = rtwn_bb_read(sc, R92C_OFDM0_ECCATHRESHOLD); + if (((x * val) >> 7) & 0x01) + reg |= 0x80000000; + else + reg &= ~0x80000000; + rtwn_bb_write(sc, R92C_OFDM0_ECCATHRESHOLD, reg); + + y = tx[1]; + if (y & 0x00000200) + y |= 0xfffffc00; + tx_c = (y * val) >> 8; + reg = rtwn_bb_read(sc, R92C_OFDM0_TXAFE(chain)); + reg |= ((((tx_c & 0x3c0) >> 6) << 24) & 0xf0000000); + rtwn_bb_write(sc, R92C_OFDM0_TXAFE(chain), reg); + + reg = rtwn_bb_read(sc, R92C_OFDM0_TXIQIMBALANCE(chain)); + reg |= (((tx_c & 0x3f) << 16) & 0x003F0000); + rtwn_bb_write(sc, R92C_OFDM0_TXIQIMBALANCE(chain), reg); + + reg = rtwn_bb_read(sc, R92C_OFDM0_ECCATHRESHOLD); + if (((y * val) >> 7) & 0x01) + reg |= 0x20000000; + else + reg &= ~0x20000000; + rtwn_bb_write(sc, R92C_OFDM0_ECCATHRESHOLD, reg); + + if (rx[0] == 0xff || rx[1] == 0xff) + return; + + reg = rtwn_bb_read(sc, R92C_OFDM0_RXIQIMBALANCE(chain)); + reg |= (rx[0] & 0x3ff); + rtwn_bb_write(sc, R92C_OFDM0_RXIQIMBALANCE(chain), reg); + reg |= (((rx[1] & 0x03f) << 8) & 0xFC00); + rtwn_bb_write(sc, R92C_OFDM0_RXIQIMBALANCE(chain), reg); + + if (chain == 0) { + reg = rtwn_bb_read(sc, R92C_OFDM0_RXIQEXTANTA); + reg |= (((rx[1] & 0xf) >> 6) & 0x000f); + rtwn_bb_write(sc, R92C_OFDM0_RXIQEXTANTA, reg); + } else { + reg = rtwn_bb_read(sc, R92C_OFDM0_AGCRSSITABLE); + reg |= ((((rx[1] & 0xf) >> 6) << 12) & 0xf000); + rtwn_bb_write(sc, R92C_OFDM0_AGCRSSITABLE, reg); + } +} + +#define RTWN_IQ_CAL_NRUN 3 +static void +rtwn_iq_calib(struct rtwn_softc *sc) +{ + uint16_t tx[RTWN_IQ_CAL_NRUN][2][2], rx[RTWN_IQ_CAL_NRUN][2][2]; + int n, valid; + + valid = 0; + for (n = 0; n < RTWN_IQ_CAL_NRUN; n++) { + rtwn_iq_calib_run(sc, n, tx[n], rx[n]); + + if (n == 0) + continue; + + /* Valid results remain stable after consecutive runs. */ + valid = rtwn_iq_calib_compare_results(tx[n - 1], rx[n - 1], + tx[n], rx[n], sc->ntxchains); + if (valid) + break; + } + + if (valid) { + rtwn_iq_calib_write_results(sc, tx[n][0], rx[n][0], 0); + if (sc->ntxchains > 1) + rtwn_iq_calib_write_results(sc, tx[n][1], rx[n][1], 1); + } +} +#undef RTWN_IQ_CAL_NRUN + +static void +rtwn_lc_calib(struct rtwn_softc *sc) +{ + uint32_t rf_ac[2]; + uint8_t txmode; + int i; + + txmode = rtwn_read_1(sc, R92C_OFDM1_LSTF + 3); + if ((txmode & 0x70) != 0) { + /* Disable all continuous Tx. */ + rtwn_write_1(sc, R92C_OFDM1_LSTF + 3, txmode & ~0x70); + + /* Set RF mode to standby mode. */ + for (i = 0; i < sc->nrxchains; i++) { + rf_ac[i] = rtwn_rf_read(sc, i, R92C_RF_AC); + rtwn_rf_write(sc, i, R92C_RF_AC, + RW(rf_ac[i], R92C_RF_AC_MODE, + R92C_RF_AC_MODE_STANDBY)); + } + } else { + /* Block all Tx queues. */ + rtwn_write_1(sc, R92C_TXPAUSE, 0xff); + } + /* Start calibration. */ + rtwn_rf_write(sc, 0, R92C_RF_CHNLBW, + rtwn_rf_read(sc, 0, R92C_RF_CHNLBW) | R92C_RF_CHNLBW_LCSTART); + + /* Give calibration the time to complete. */ + DELAY(100); + + /* Restore configuration. */ + if ((txmode & 0x70) != 0) { + /* Restore Tx mode. */ + rtwn_write_1(sc, R92C_OFDM1_LSTF + 3, txmode); + /* Restore RF mode. */ + for (i = 0; i < sc->nrxchains; i++) + rtwn_rf_write(sc, i, R92C_RF_AC, rf_ac[i]); + } else { + /* Unblock all Tx queues. */ + rtwn_write_1(sc, R92C_TXPAUSE, 0x00); + } +} + +static void +rtwn_temp_calib(struct rtwn_softc *sc) +{ + int temp; + + if (sc->thcal_state == 0) { + /* Start measuring temperature. */ + rtwn_rf_write(sc, 0, R92C_RF_T_METER, 0x60); + sc->thcal_state = 1; + return; + } + sc->thcal_state = 0; + + /* Read measured temperature. */ + temp = rtwn_rf_read(sc, 0, R92C_RF_T_METER) & 0x1f; + if (temp == 0) /* Read failed, skip. */ + return; + DPRINTFN(2, ("temperature=%d\n", temp)); + + /* + * Redo IQ and LC calibration if temperature changed significantly + * since last calibration. + */ + if (sc->thcal_lctemp == 0) { + /* First calibration is performed in rtwn_init(). */ + sc->thcal_lctemp = temp; + } else if (abs(temp - sc->thcal_lctemp) > 1) { + DPRINTF(("IQ/LC calib triggered by temp: %d -> %d\n", + sc->thcal_lctemp, temp)); + rtwn_iq_calib(sc); + rtwn_lc_calib(sc); + /* Record temperature of last calibration. */ + sc->thcal_lctemp = temp; + } +} + +static void +rtwn_init_locked(struct rtwn_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + uint32_t reg; + uint8_t macaddr[IEEE80211_ADDR_LEN]; + int i, error; + + RTWN_LOCK_ASSERT(sc); + + /* Init firmware commands ring. */ + sc->fwcur = 0; + + /* Power on adapter. */ + error = rtwn_power_on(sc); + if (error != 0) { + device_printf(sc->sc_dev, "could not power on adapter\n"); + goto fail; + } + + /* Initialize DMA. */ + error = rtwn_dma_init(sc); + if (error != 0) { + device_printf(sc->sc_dev, "could not initialize DMA\n"); + goto fail; + } + + /* Set info size in Rx descriptors (in 64-bit words). */ + rtwn_write_1(sc, R92C_RX_DRVINFO_SZ, 4); + + /* Disable interrupts. */ + rtwn_write_4(sc, R92C_HISR, 0x00000000); + rtwn_write_4(sc, R92C_HIMR, 0x00000000); + + /* Set MAC address. */ + IEEE80211_ADDR_COPY(macaddr, vap ? vap->iv_myaddr : ic->ic_macaddr); + for (i = 0; i < IEEE80211_ADDR_LEN; i++) + rtwn_write_1(sc, R92C_MACID + i, macaddr[i]); + + /* Set initial network type. */ + reg = rtwn_read_4(sc, R92C_CR); + reg = RW(reg, R92C_CR_NETTYPE, R92C_CR_NETTYPE_INFRA); + rtwn_write_4(sc, R92C_CR, reg); + + rtwn_rxfilter_init(sc); + + reg = rtwn_read_4(sc, R92C_RRSR); + reg = RW(reg, R92C_RRSR_RATE_BITMAP, R92C_RRSR_RATE_ALL); + rtwn_write_4(sc, R92C_RRSR, reg); + + /* Set short/long retry limits. */ + rtwn_write_2(sc, R92C_RL, + SM(R92C_RL_SRL, 0x07) | SM(R92C_RL_LRL, 0x07)); + + /* Initialize EDCA parameters. */ + rtwn_edca_init(sc); + + /* Set data and response automatic rate fallback retry counts. */ + rtwn_write_4(sc, R92C_DARFRC + 0, 0x01000000); + rtwn_write_4(sc, R92C_DARFRC + 4, 0x07060504); + rtwn_write_4(sc, R92C_RARFRC + 0, 0x01000000); + rtwn_write_4(sc, R92C_RARFRC + 4, 0x07060504); + + rtwn_write_2(sc, R92C_FWHW_TXQ_CTRL, 0x1f80); + + /* Set ACK timeout. */ + rtwn_write_1(sc, R92C_ACKTO, 0x40); + + /* Initialize beacon parameters. */ + rtwn_write_2(sc, R92C_TBTT_PROHIBIT, 0x6404); + rtwn_write_1(sc, R92C_DRVERLYINT, 0x05); + rtwn_write_1(sc, R92C_BCNDMATIM, 0x02); + rtwn_write_2(sc, R92C_BCNTCFG, 0x660f); + + /* Setup AMPDU aggregation. */ + rtwn_write_4(sc, R92C_AGGLEN_LMT, 0x99997631); /* MCS7~0 */ + rtwn_write_1(sc, R92C_AGGR_BREAK_TIME, 0x16); + + rtwn_write_1(sc, R92C_BCN_MAX_ERR, 0xff); + rtwn_write_1(sc, R92C_BCN_CTRL, R92C_BCN_CTRL_DIS_TSF_UDT0); + + rtwn_write_4(sc, R92C_PIFS, 0x1c); + rtwn_write_4(sc, R92C_MCUTST_1, 0x0); + + /* Load 8051 microcode. */ + error = rtwn_load_firmware(sc); + if (error != 0) + goto fail; + + /* Initialize MAC/BB/RF blocks. */ + rtwn_mac_init(sc); + rtwn_bb_init(sc); + rtwn_rf_init(sc); + + /* Turn CCK and OFDM blocks on. */ + reg = rtwn_bb_read(sc, R92C_FPGA0_RFMOD); + reg |= R92C_RFMOD_CCK_EN; + rtwn_bb_write(sc, R92C_FPGA0_RFMOD, reg); + reg = rtwn_bb_read(sc, R92C_FPGA0_RFMOD); + reg |= R92C_RFMOD_OFDM_EN; + rtwn_bb_write(sc, R92C_FPGA0_RFMOD, reg); + + /* Clear per-station keys table. */ + rtwn_cam_init(sc); + + /* Enable hardware sequence numbering. */ + rtwn_write_1(sc, R92C_HWSEQ_CTRL, 0xff); + + /* Perform LO and IQ calibrations. */ + rtwn_iq_calib(sc); + /* Perform LC calibration. */ + rtwn_lc_calib(sc); + + rtwn_pa_bias_init(sc); + + /* Initialize GPIO setting. */ + rtwn_write_1(sc, R92C_GPIO_MUXCFG, + rtwn_read_1(sc, R92C_GPIO_MUXCFG) & ~R92C_GPIO_MUXCFG_ENBT); + + /* Fix for lower temperature. */ + rtwn_write_1(sc, 0x15, 0xe9); + + /* CLear pending interrupts. */ + rtwn_write_4(sc, R92C_HISR, 0xffffffff); + + /* Enable interrupts. */ + rtwn_write_4(sc, R92C_HIMR, RTWN_INT_ENABLE); + + sc->sc_flags |= RTWN_RUNNING; + + callout_reset(&sc->watchdog_to, hz, rtwn_watchdog, sc); + return; + +fail: + rtwn_stop_locked(sc); +} + +static void +rtwn_init(struct rtwn_softc *sc) +{ + + RTWN_LOCK(sc); + rtwn_init_locked(sc); + RTWN_UNLOCK(sc); + + if (sc->sc_flags & RTWN_RUNNING) + ieee80211_start_all(&sc->sc_ic); +} + +static void +rtwn_stop_locked(struct rtwn_softc *sc) +{ + uint16_t reg; + int i; + + RTWN_LOCK_ASSERT(sc); + + sc->sc_tx_timer = 0; + callout_stop(&sc->watchdog_to); + callout_stop(&sc->calib_to); + sc->sc_flags &= ~RTWN_RUNNING; + + /* Disable interrupts. */ + rtwn_write_4(sc, R92C_HISR, 0x00000000); + rtwn_write_4(sc, R92C_HIMR, 0x00000000); + + /* Stop hardware. */ + rtwn_write_1(sc, R92C_TXPAUSE, 0xff); + rtwn_write_1(sc, R92C_RF_CTRL, 0x00); + reg = rtwn_read_1(sc, R92C_SYS_FUNC_EN); + reg |= R92C_SYS_FUNC_EN_BB_GLB_RST; + rtwn_write_1(sc, R92C_SYS_FUNC_EN, reg); + reg &= ~R92C_SYS_FUNC_EN_BB_GLB_RST; + rtwn_write_1(sc, R92C_SYS_FUNC_EN, reg); + reg = rtwn_read_2(sc, R92C_CR); + reg &= ~(R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN | + R92C_CR_TXDMA_EN | R92C_CR_RXDMA_EN | R92C_CR_PROTOCOL_EN | + R92C_CR_SCHEDULE_EN | R92C_CR_MACTXEN | R92C_CR_MACRXEN | + R92C_CR_ENSEC); + rtwn_write_2(sc, R92C_CR, reg); + if (rtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RAM_DL_SEL) + rtwn_fw_reset(sc); + /* TODO: linux does additional btcoex stuff here */ + rtwn_write_2(sc, R92C_AFE_PLL_CTRL, 0x80); /* linux magic number */ + rtwn_write_1(sc, R92C_SPS0_CTRL, 0x23); /* ditto */ + rtwn_write_1(sc, R92C_AFE_XTAL_CTRL, 0x0e); /* different with btcoex */ + rtwn_write_1(sc, R92C_RSV_CTRL, 0x0e); + rtwn_write_1(sc, R92C_APS_FSMCO, R92C_APS_FSMCO_PDN_EN); + + for (i = 0; i < RTWN_NTXQUEUES; i++) + rtwn_reset_tx_list(sc, i); + rtwn_reset_rx_list(sc); +} + +static void +rtwn_stop(struct rtwn_softc *sc) +{ + RTWN_LOCK(sc); + rtwn_stop_locked(sc); + RTWN_UNLOCK(sc); +} + +static void +rtwn_intr(void *arg) +{ + struct rtwn_softc *sc = arg; + uint32_t status; + int i; + + RTWN_LOCK(sc); + status = rtwn_read_4(sc, R92C_HISR); + if (status == 0 || status == 0xffffffff) { + RTWN_UNLOCK(sc); + return; + } + + /* Disable interrupts. */ + rtwn_write_4(sc, R92C_HIMR, 0x00000000); + + /* Ack interrupts. */ + rtwn_write_4(sc, R92C_HISR, status); + + /* Vendor driver treats RX errors like ROK... */ + if (status & (R92C_IMR_ROK | R92C_IMR_RXFOVW | R92C_IMR_RDU)) { + bus_dmamap_sync(sc->rx_ring.desc_dmat, sc->rx_ring.desc_map, + BUS_DMASYNC_POSTREAD); + + for (i = 0; i < RTWN_RX_LIST_COUNT; i++) { + struct r92c_rx_desc *rx_desc = &sc->rx_ring.desc[i]; + struct rtwn_rx_data *rx_data = &sc->rx_ring.rx_data[i]; + + if (le32toh(rx_desc->rxdw0) & R92C_RXDW0_OWN) + continue; + + rtwn_rx_frame(sc, rx_desc, rx_data, i); + } + } + + if (status & R92C_IMR_BDOK) + rtwn_tx_done(sc, RTWN_BEACON_QUEUE); + if (status & R92C_IMR_HIGHDOK) + rtwn_tx_done(sc, RTWN_HIGH_QUEUE); + if (status & R92C_IMR_MGNTDOK) + rtwn_tx_done(sc, RTWN_MGNT_QUEUE); + if (status & R92C_IMR_BKDOK) + rtwn_tx_done(sc, RTWN_BK_QUEUE); + if (status & R92C_IMR_BEDOK) + rtwn_tx_done(sc, RTWN_BE_QUEUE); + if (status & R92C_IMR_VIDOK) + rtwn_tx_done(sc, RTWN_VI_QUEUE); + if (status & R92C_IMR_VODOK) + rtwn_tx_done(sc, RTWN_VO_QUEUE); + + /* Enable interrupts. */ + rtwn_write_4(sc, R92C_HIMR, RTWN_INT_ENABLE); + + RTWN_UNLOCK(sc); +} + +static void +rtwn_hw_reset(void *arg0, int pending) +{ + struct rtwn_softc *sc = arg0; + struct ieee80211com *ic = &sc->sc_ic; + + rtwn_stop(sc); + rtwn_init(sc); + ieee80211_notify_radio(ic, 1); +} diff --git a/sys/dev/rtwn/if_rtwnreg.h b/sys/dev/rtwn/if_rtwnreg.h new file mode 100644 index 000000000000..a5f1cc282b31 --- /dev/null +++ b/sys/dev/rtwn/if_rtwnreg.h @@ -0,0 +1,2106 @@ +/* $OpenBSD: if_rtwnreg.h,v 1.3 2015/06/14 08:02:47 stsp Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#define R92C_MAX_CHAINS 2 + +/* Maximum number of output pipes is 3. */ +#define R92C_MAX_EPOUT 3 + +#define R92C_MAX_TX_PWR 0x3f + +#define R92C_PUBQ_NPAGES 176 +#define R92C_HPQ_NPAGES 41 +#define R92C_LPQ_NPAGES 28 +#define R92C_TXPKTBUF_COUNT 256 +#define R92C_TX_PAGE_COUNT \ + (R92C_PUBQ_NPAGES + R92C_HPQ_NPAGES + R92C_LPQ_NPAGES) +#define R92C_TX_PAGE_BOUNDARY (R92C_TX_PAGE_COUNT + 1) + +#define R92C_H2C_NBOX 4 + +/* USB Requests. */ +#define R92C_REQ_REGS 0x05 + +/* + * MAC registers. + */ +/* System Configuration. */ +#define R92C_SYS_ISO_CTRL 0x000 +#define R92C_SYS_FUNC_EN 0x002 +#define R92C_APS_FSMCO 0x004 +#define R92C_SYS_CLKR 0x008 +#define R92C_AFE_MISC 0x010 +#define R92C_SPS0_CTRL 0x011 +#define R92C_SPS_OCP_CFG 0x018 +#define R92C_RSV_CTRL 0x01c +#define R92C_RF_CTRL 0x01f +#define R92C_LDOA15_CTRL 0x020 +#define R92C_LDOV12D_CTRL 0x021 +#define R92C_LDOHCI12_CTRL 0x022 +#define R92C_LPLDO_CTRL 0x023 +#define R92C_AFE_XTAL_CTRL 0x024 +#define R92C_AFE_PLL_CTRL 0x028 +#define R92C_EFUSE_CTRL 0x030 +#define R92C_EFUSE_TEST 0x034 +#define R92C_PWR_DATA 0x038 +#define R92C_CAL_TIMER 0x03c +#define R92C_ACLK_MON 0x03e +#define R92C_GPIO_MUXCFG 0x040 +#define R92C_GPIO_IO_SEL 0x042 +#define R92C_MAC_PINMUX_CFG 0x043 +#define R92C_GPIO_PIN_CTRL 0x044 +#define R92C_GPIO_INTM 0x048 +#define R92C_LEDCFG0 0x04c +#define R92C_LEDCFG1 0x04d +#define R92C_LEDCFG2 0x04e +#define R92C_LEDCFG3 0x04f +#define R92C_FSIMR 0x050 +#define R92C_FSISR 0x054 +#define R92C_HSIMR 0x058 +#define R92C_HSISR 0x05c +#define R92C_MCUFWDL 0x080 +#define R92C_HMEBOX_EXT(idx) (0x088 + (idx) * 2) +#define R92C_BIST_SCAN 0x0d0 +#define R92C_BIST_RPT 0x0d4 +#define R92C_BIST_ROM_RPT 0x0d8 +#define R92C_USB_SIE_INTF 0x0e0 +#define R92C_PCIE_MIO_INTF 0x0e4 +#define R92C_PCIE_MIO_INTD 0x0e8 +#define R92C_HPON_FSM 0x0ec +#define R92C_SYS_CFG 0x0f0 +/* MAC General Configuration. */ +#define R92C_CR 0x100 +#define R92C_PBP 0x104 +#define R92C_TRXDMA_CTRL 0x10c +#define R92C_TRXFF_BNDY 0x114 +#define R92C_TRXFF_STATUS 0x118 +#define R92C_RXFF_PTR 0x11c +#define R92C_HIMR 0x120 +#define R92C_HISR 0x124 +#define R92C_HIMRE 0x128 +#define R92C_HISRE 0x12c +#define R92C_CPWM 0x12f +#define R92C_FWIMR 0x130 +#define R92C_FWISR 0x134 +#define R92C_PKTBUF_DBG_CTRL 0x140 +#define R92C_PKTBUF_DBG_DATA_L 0x144 +#define R92C_PKTBUF_DBG_DATA_H 0x148 +#define R92C_TC0_CTRL(i) (0x150 + (i) * 4) +#define R92C_TCUNIT_BASE 0x164 +#define R92C_MBIST_START 0x174 +#define R92C_MBIST_DONE 0x178 +#define R92C_MBIST_FAIL 0x17c +#define R92C_C2HEVT_MSG_NORMAL 0x1a0 +#define R92C_C2HEVT_MSG_TEST 0x1b8 +#define R92C_C2HEVT_CLEAR 0x1bf +#define R92C_MCUTST_1 0x1c0 +#define R92C_FMETHR 0x1c8 +#define R92C_HMETFR 0x1cc +#define R92C_HMEBOX(idx) (0x1d0 + (idx) * 4) +#define R92C_LLT_INIT 0x1e0 +#define R92C_BB_ACCESS_CTRL 0x1e8 +#define R92C_BB_ACCESS_DATA 0x1ec +/* Tx DMA Configuration. */ +#define R92C_RQPN 0x200 +#define R92C_FIFOPAGE 0x204 +#define R92C_TDECTRL 0x208 +#define R92C_TXDMA_OFFSET_CHK 0x20c +#define R92C_TXDMA_STATUS 0x210 +#define R92C_RQPN_NPQ 0x214 +/* Rx DMA Configuration. */ +#define R92C_RXDMA_AGG_PG_TH 0x280 +#define R92C_RXPKT_NUM 0x284 +#define R92C_RXDMA_STATUS 0x288 + +#define R92C_PCIE_CTRL_REG 0x300 +#define R92C_INT_MIG 0x304 +#define R92C_BCNQ_DESA 0x308 +#define R92C_HQ_DESA 0x310 +#define R92C_MGQ_DESA 0x318 +#define R92C_VOQ_DESA 0x320 +#define R92C_VIQ_DESA 0x328 +#define R92C_BEQ_DESA 0x330 +#define R92C_BKQ_DESA 0x338 +#define R92C_RX_DESA 0x340 +#define R92C_DBI 0x348 +#define R92C_MDIO 0x354 +#define R92C_DBG_SEL 0x360 +#define R92C_PCIE_HRPWM 0x361 +#define R92C_PCIE_HCPWM 0x363 +#define R92C_UART_CTRL 0x364 +#define R92C_UART_TX_DES 0x370 +#define R92C_UART_RX_DES 0x378 + +#define R92C_VOQ_INFORMATION 0x0400 +#define R92C_VIQ_INFORMATION 0x0404 +#define R92C_BEQ_INFORMATION 0x0408 +#define R92C_BKQ_INFORMATION 0x040C +#define R92C_MGQ_INFORMATION 0x0410 +#define R92C_HGQ_INFORMATION 0x0414 +#define R92C_BCNQ_INFORMATION 0x0418 +#define R92C_CPU_MGQ_INFORMATION 0x041C + +/* Protocol Configuration. */ +#define R92C_FWHW_TXQ_CTRL 0x420 +#define R92C_HWSEQ_CTRL 0x423 +#define R92C_TXPKTBUF_BCNQ_BDNY 0x424 +#define R92C_TXPKTBUF_MGQ_BDNY 0x425 +#define R92C_SPEC_SIFS 0x428 +#define R92C_RL 0x42a +#define R92C_DARFRC 0x430 +#define R92C_RARFRC 0x438 +#define R92C_RRSR 0x440 +#define R92C_ARFR(i) (0x444 + (i) * 4) +#define R92C_AGGLEN_LMT 0x458 +#define R92C_AMPDU_MIN_SPACE 0x45c +#define R92C_TXPKTBUF_WMAC_LBK_BF_HD 0x45d +#define R92C_FAST_EDCA_CTRL 0x460 +#define R92C_RD_RESP_PKT_TH 0x463 +#define R92C_INIRTS_RATE_SEL 0x480 +#define R92C_INIDATA_RATE_SEL(macid) (0x484 + (macid)) +/* EDCA Configuration. */ +#define R92C_EDCA_VO_PARAM 0x500 +#define R92C_EDCA_VI_PARAM 0x504 +#define R92C_EDCA_BE_PARAM 0x508 +#define R92C_EDCA_BK_PARAM 0x50c +#define R92C_BCNTCFG 0x510 +#define R92C_PIFS 0x512 +#define R92C_RDG_PIFS 0x513 +#define R92C_SIFS_CCK 0x514 +#define R92C_SIFS_OFDM 0x516 +#define R92C_AGGR_BREAK_TIME 0x51a +#define R92C_SLOT 0x51b +#define R92C_TX_PTCL_CTRL 0x520 +#define R92C_TXPAUSE 0x522 +#define R92C_DIS_TXREQ_CLR 0x523 +#define R92C_RD_CTRL 0x524 +#define R92C_TBTT_PROHIBIT 0x540 +#define R92C_RD_NAV_NXT 0x544 +#define R92C_NAV_PROT_LEN 0x546 +#define R92C_BCN_CTRL 0x550 +#define R92C_USTIME_TSF 0x551 +#define R92C_MBID_NUM 0x552 +#define R92C_DUAL_TSF_RST 0x553 +#define R92C_BCN_INTERVAL 0x554 +#define R92C_DRVERLYINT 0x558 +#define R92C_BCNDMATIM 0x559 +#define R92C_ATIMWND 0x55a +#define R92C_BCN_MAX_ERR 0x55d +#define R92C_RXTSF_OFFSET_CCK 0x55e +#define R92C_RXTSF_OFFSET_OFDM 0x55f +#define R92C_TSFTR 0x560 +#define R92C_INIT_TSFTR 0x564 +#define R92C_PSTIMER 0x580 +#define R92C_TIMER0 0x584 +#define R92C_TIMER1 0x588 +#define R92C_ACMHWCTRL 0x5c0 +#define R92C_ACMRSTCTRL 0x5c1 +#define R92C_ACMAVG 0x5c2 +#define R92C_VO_ADMTIME 0x5c4 +#define R92C_VI_ADMTIME 0x5c6 +#define R92C_BE_ADMTIME 0x5c8 +#define R92C_EDCA_RANDOM_GEN 0x5cc +#define R92C_SCH_TXCMD 0x5d0 +/* WMAC Configuration. */ +#define R92C_APSD_CTRL 0x600 +#define R92C_BWOPMODE 0x603 +#define R92C_TCR 0x604 +#define R92C_RCR 0x608 +#define R92C_RX_DRVINFO_SZ 0x60f +#define R92C_MACID 0x610 +#define R92C_BSSID 0x618 +#define R92C_MAR 0x620 +#define R92C_MAC_SPEC_SIFS 0x63a +#define R92C_R2T_SIFS 0x63c +#define R92C_T2T_SIFS 0x63e +#define R92C_ACKTO 0x640 +#define R92C_CAMCMD 0x670 +#define R92C_CAMWRITE 0x674 +#define R92C_CAMREAD 0x678 +#define R92C_CAMDBG 0x67c +#define R92C_SECCFG 0x680 +#define R92C_RXFLTMAP0 0x6a0 +#define R92C_RXFLTMAP1 0x6a2 +#define R92C_RXFLTMAP2 0x6a4 + +/* Bits for R92C_SYS_ISO_CTRL. */ +#define R92C_SYS_ISO_CTRL_MD2PP 0x0001 +#define R92C_SYS_ISO_CTRL_UA2USB 0x0002 +#define R92C_SYS_ISO_CTRL_UD2CORE 0x0004 +#define R92C_SYS_ISO_CTRL_PA2PCIE 0x0008 +#define R92C_SYS_ISO_CTRL_PD2CORE 0x0010 +#define R92C_SYS_ISO_CTRL_IP2MAC 0x0020 +#define R92C_SYS_ISO_CTRL_DIOP 0x0040 +#define R92C_SYS_ISO_CTRL_DIOE 0x0080 +#define R92C_SYS_ISO_CTRL_EB2CORE 0x0100 +#define R92C_SYS_ISO_CTRL_DIOR 0x0200 +#define R92C_SYS_ISO_CTRL_PWC_EV25V 0x4000 +#define R92C_SYS_ISO_CTRL_PWC_EV12V 0x8000 + +/* Bits for R92C_SYS_FUNC_EN. */ +#define R92C_SYS_FUNC_EN_BBRSTB 0x0001 +#define R92C_SYS_FUNC_EN_BB_GLB_RST 0x0002 +#define R92C_SYS_FUNC_EN_USBA 0x0004 +#define R92C_SYS_FUNC_EN_UPLL 0x0008 +#define R92C_SYS_FUNC_EN_USBD 0x0010 +#define R92C_SYS_FUNC_EN_DIO_PCIE 0x0020 +#define R92C_SYS_FUNC_EN_PCIEA 0x0040 +#define R92C_SYS_FUNC_EN_PPLL 0x0080 +#define R92C_SYS_FUNC_EN_PCIED 0x0100 +#define R92C_SYS_FUNC_EN_DIOE 0x0200 +#define R92C_SYS_FUNC_EN_CPUEN 0x0400 +#define R92C_SYS_FUNC_EN_DCORE 0x0800 +#define R92C_SYS_FUNC_EN_ELDR 0x1000 +#define R92C_SYS_FUNC_EN_DIO_RF 0x2000 +#define R92C_SYS_FUNC_EN_HWPDN 0x4000 +#define R92C_SYS_FUNC_EN_MREGEN 0x8000 + +/* Bits for R92C_APS_FSMCO. */ +#define R92C_APS_FSMCO_PFM_LDALL 0x00000001 +#define R92C_APS_FSMCO_PFM_ALDN 0x00000002 +#define R92C_APS_FSMCO_PFM_LDKP 0x00000004 +#define R92C_APS_FSMCO_PFM_WOWL 0x00000008 +#define R92C_APS_FSMCO_PDN_EN 0x00000010 +#define R92C_APS_FSMCO_PDN_PL 0x00000020 +#define R92C_APS_FSMCO_APFM_ONMAC 0x00000100 +#define R92C_APS_FSMCO_APFM_OFF 0x00000200 +#define R92C_APS_FSMCO_APFM_RSM 0x00000400 +#define R92C_APS_FSMCO_AFSM_HSUS 0x00000800 +#define R92C_APS_FSMCO_AFSM_PCIE 0x00001000 +#define R92C_APS_FSMCO_APDM_MAC 0x00002000 +#define R92C_APS_FSMCO_APDM_HOST 0x00004000 +#define R92C_APS_FSMCO_APDM_HPDN 0x00008000 +#define R92C_APS_FSMCO_RDY_MACON 0x00010000 +#define R92C_APS_FSMCO_SUS_HOST 0x00020000 +#define R92C_APS_FSMCO_ROP_ALD 0x00100000 +#define R92C_APS_FSMCO_ROP_PWR 0x00200000 +#define R92C_APS_FSMCO_ROP_SPS 0x00400000 +#define R92C_APS_FSMCO_SOP_MRST 0x02000000 +#define R92C_APS_FSMCO_SOP_FUSE 0x04000000 +#define R92C_APS_FSMCO_SOP_ABG 0x08000000 +#define R92C_APS_FSMCO_SOP_AMB 0x10000000 +#define R92C_APS_FSMCO_SOP_RCK 0x20000000 +#define R92C_APS_FSMCO_SOP_A8M 0x40000000 +#define R92C_APS_FSMCO_XOP_BTCK 0x80000000 + +/* Bits for R92C_SYS_CLKR. */ +#define R92C_SYS_CLKR_ANAD16V_EN 0x00000001 +#define R92C_SYS_CLKR_ANA8M 0x00000002 +#define R92C_SYS_CLKR_MACSLP 0x00000010 +#define R92C_SYS_CLKR_LOADER_EN 0x00000020 +#define R92C_SYS_CLKR_80M_SSC_DIS 0x00000080 +#define R92C_SYS_CLKR_80M_SSC_EN_HO 0x00000100 +#define R92C_SYS_CLKR_PHY_SSC_RSTB 0x00000200 +#define R92C_SYS_CLKR_SEC_EN 0x00000400 +#define R92C_SYS_CLKR_MAC_EN 0x00000800 +#define R92C_SYS_CLKR_SYS_EN 0x00001000 +#define R92C_SYS_CLKR_RING_EN 0x00002000 + +/* Bits for R92C_RF_CTRL. */ +#define R92C_RF_CTRL_EN 0x01 +#define R92C_RF_CTRL_RSTB 0x02 +#define R92C_RF_CTRL_SDMRSTB 0x04 + +/* Bits for R92C_LDOV12D_CTRL. */ +#define R92C_LDOV12D_CTRL_LDV12_EN 0x01 + +/* Bits for R92C_EFUSE_CTRL. */ +#define R92C_EFUSE_CTRL_DATA_M 0x000000ff +#define R92C_EFUSE_CTRL_DATA_S 0 +#define R92C_EFUSE_CTRL_ADDR_M 0x0003ff00 +#define R92C_EFUSE_CTRL_ADDR_S 8 +#define R92C_EFUSE_CTRL_VALID 0x80000000 + +/* Bits for R92C_GPIO_MUXCFG. */ +#define R92C_GPIO_MUXCFG_RFKILL 0x0008 +#define R92C_GPIO_MUXCFG_ENBT 0x0020 + +/* Bits for R92C_GPIO_IO_SEL. */ +#define R92C_GPIO_IO_SEL_RFKILL 0x0008 + +/* Bits for R92C_LEDCFG0. */ +#define R92C_LEDCFG0_DIS 0x08 + +/* Bits for R92C_LEDCFG2. */ +#define R92C_LEDCFG2_EN 0x60 +#define R92C_LEDCFG2_DIS 0x68 + +/* Bits for R92C_MCUFWDL. */ +#define R92C_MCUFWDL_EN 0x00000001 +#define R92C_MCUFWDL_RDY 0x00000002 +#define R92C_MCUFWDL_CHKSUM_RPT 0x00000004 +#define R92C_MCUFWDL_MACINI_RDY 0x00000008 +#define R92C_MCUFWDL_BBINI_RDY 0x00000010 +#define R92C_MCUFWDL_RFINI_RDY 0x00000020 +#define R92C_MCUFWDL_WINTINI_RDY 0x00000040 +#define R92C_MCUFWDL_RAM_DL_SEL 0x00000080 /* 1: RAM, 0: ROM */ +#define R92C_MCUFWDL_PAGE_M 0x00070000 +#define R92C_MCUFWDL_PAGE_S 16 +#define R92C_MCUFWDL_CPRST 0x00800000 + +/* Bits for R92C_HPON_FSM. */ +#define R92C_HPON_FSM_CHIP_BONDING_ID_S 22 +#define R92C_HPON_FSM_CHIP_BONDING_ID_M 0x00c00000 +#define R92C_HPON_FSM_CHIP_BONDING_ID_92C_1T2R 1 + +/* Bits for R92C_SYS_CFG. */ +#define R92C_SYS_CFG_XCLK_VLD 0x00000001 +#define R92C_SYS_CFG_ACLK_VLD 0x00000002 +#define R92C_SYS_CFG_UCLK_VLD 0x00000004 +#define R92C_SYS_CFG_PCLK_VLD 0x00000008 +#define R92C_SYS_CFG_PCIRSTB 0x00000010 +#define R92C_SYS_CFG_V15_VLD 0x00000020 +#define R92C_SYS_CFG_TRP_B15V_EN 0x00000080 +#define R92C_SYS_CFG_SIC_IDLE 0x00000100 +#define R92C_SYS_CFG_BD_MAC2 0x00000200 +#define R92C_SYS_CFG_BD_MAC1 0x00000400 +#define R92C_SYS_CFG_IC_MACPHY_MODE 0x00000800 +#define R92C_SYS_CFG_CHIP_VER_RTL_M 0x0000f000 +#define R92C_SYS_CFG_CHIP_VER_RTL_S 12 +#define R92C_SYS_CFG_BT_FUNC 0x00010000 +#define R92C_SYS_CFG_VENDOR_UMC 0x00080000 +#define R92C_SYS_CFG_PAD_HWPD_IDN 0x00400000 +#define R92C_SYS_CFG_TRP_VAUX_EN 0x00800000 +#define R92C_SYS_CFG_TRP_BT_EN 0x01000000 +#define R92C_SYS_CFG_BD_PKG_SEL 0x02000000 +#define R92C_SYS_CFG_BD_HCI_SEL 0x04000000 +#define R92C_SYS_CFG_TYPE_92C 0x08000000 + +/* Bits for R92C_CR. */ +#define R92C_CR_HCI_TXDMA_EN 0x00000001 +#define R92C_CR_HCI_RXDMA_EN 0x00000002 +#define R92C_CR_TXDMA_EN 0x00000004 +#define R92C_CR_RXDMA_EN 0x00000008 +#define R92C_CR_PROTOCOL_EN 0x00000010 +#define R92C_CR_SCHEDULE_EN 0x00000020 +#define R92C_CR_MACTXEN 0x00000040 +#define R92C_CR_MACRXEN 0x00000080 +#define R92C_CR_ENSEC 0x00000200 +#define R92C_CR_NETTYPE_S 16 +#define R92C_CR_NETTYPE_M 0x00030000 +#define R92C_CR_NETTYPE_NOLINK 0 +#define R92C_CR_NETTYPE_ADHOC 1 +#define R92C_CR_NETTYPE_INFRA 2 +#define R92C_CR_NETTYPE_AP 3 + +/* Bits for R92C_PBP. */ +#define R92C_PBP_PSRX_M 0x0f +#define R92C_PBP_PSRX_S 0 +#define R92C_PBP_PSTX_M 0xf0 +#define R92C_PBP_PSTX_S 4 +#define R92C_PBP_64 0 +#define R92C_PBP_128 1 +#define R92C_PBP_256 2 +#define R92C_PBP_512 3 +#define R92C_PBP_1024 4 + +/* Bits for R92C_TRXDMA_CTRL. */ +#define R92C_TRXDMA_CTRL_RXDMA_AGG_EN 0x0004 +#define R92C_TRXDMA_CTRL_TXDMA_VOQ_MAP_M 0x0030 +#define R92C_TRXDMA_CTRL_TXDMA_VOQ_MAP_S 4 +#define R92C_TRXDMA_CTRL_TXDMA_VIQ_MAP_M 0x00c0 +#define R92C_TRXDMA_CTRL_TXDMA_VIQ_MAP_S 6 +#define R92C_TRXDMA_CTRL_TXDMA_BEQ_MAP_M 0x0300 +#define R92C_TRXDMA_CTRL_TXDMA_BEQ_MAP_S 8 +#define R92C_TRXDMA_CTRL_TXDMA_BKQ_MAP_M 0x0c00 +#define R92C_TRXDMA_CTRL_TXDMA_BKQ_MAP_S 10 +#define R92C_TRXDMA_CTRL_TXDMA_MGQ_MAP_M 0x3000 +#define R92C_TRXDMA_CTRL_TXDMA_MGQ_MAP_S 12 +#define R92C_TRXDMA_CTRL_TXDMA_HIQ_MAP_M 0xc000 +#define R92C_TRXDMA_CTRL_TXDMA_HIQ_MAP_S 14 +#define R92C_TRXDMA_CTRL_QUEUE_LOW 1 +#define R92C_TRXDMA_CTRL_QUEUE_NORMAL 2 +#define R92C_TRXDMA_CTRL_QUEUE_HIGH 3 +#define R92C_TRXDMA_CTRL_QMAP_M 0xfff0 +#define R92C_TRXDMA_CTRL_QMAP_S 4 +/* Shortcuts. */ +#define R92C_TRXDMA_CTRL_QMAP_3EP 0xf5b0 +#define R92C_TRXDMA_CTRL_QMAP_HQ_LQ 0xf5f0 +#define R92C_TRXDMA_CTRL_QMAP_HQ_NQ 0xfaf0 +#define R92C_TRXDMA_CTRL_QMAP_LQ 0x5550 +#define R92C_TRXDMA_CTRL_QMAP_NQ 0xaaa0 +#define R92C_TRXDMA_CTRL_QMAP_HQ 0xfff0 + +/* Bits for R92C_LLT_INIT. */ +#define R92C_LLT_INIT_DATA_M 0x000000ff +#define R92C_LLT_INIT_DATA_S 0 +#define R92C_LLT_INIT_ADDR_M 0x0000ff00 +#define R92C_LLT_INIT_ADDR_S 8 +#define R92C_LLT_INIT_OP_M 0xc0000000 +#define R92C_LLT_INIT_OP_S 30 +#define R92C_LLT_INIT_OP_NO_ACTIVE 0 +#define R92C_LLT_INIT_OP_WRITE 1 + +/* Bits for R92C_RQPN. */ +#define R92C_RQPN_HPQ_M 0x000000ff +#define R92C_RQPN_HPQ_S 0 +#define R92C_RQPN_LPQ_M 0x0000ff00 +#define R92C_RQPN_LPQ_S 8 +#define R92C_RQPN_PUBQ_M 0x00ff0000 +#define R92C_RQPN_PUBQ_S 16 +#define R92C_RQPN_LD 0x80000000 + +/* Bits for R92C_TDECTRL. */ +#define R92C_TDECTRL_BLK_DESC_NUM_M 0x0000000f +#define R92C_TDECTRL_BLK_DESC_NUM_S 4 + +/* Bits for R92C_FWHW_TXQ_CTRL. */ +#define R92C_FWHW_TXQ_CTRL_AMPDU_RTY_NEW 0x80 + +/* Bits for R92C_SPEC_SIFS. */ +#define R92C_SPEC_SIFS_CCK_M 0x00ff +#define R92C_SPEC_SIFS_CCK_S 0 +#define R92C_SPEC_SIFS_OFDM_M 0xff00 +#define R92C_SPEC_SIFS_OFDM_S 8 + +/* Bits for R92C_RL. */ +#define R92C_RL_LRL_M 0x003f +#define R92C_RL_LRL_S 0 +#define R92C_RL_SRL_M 0x3f00 +#define R92C_RL_SRL_S 8 + +/* Bits for R92C_RRSR. */ +#define R92C_RRSR_RATE_BITMAP_M 0x000fffff +#define R92C_RRSR_RATE_BITMAP_S 0 +#define R92C_RRSR_RATE_CCK_ONLY_1M 0xffff1 +#define R92C_RRSR_RATE_ALL 0xfffff +#define R92C_RRSR_RSC_LOWSUBCHNL 0x00200000 +#define R92C_RRSR_RSC_UPSUBCHNL 0x00400000 +#define R92C_RRSR_SHORT 0x00800000 + +/* Bits for R92C_EDCA_XX_PARAM. */ +#define R92C_EDCA_PARAM_AIFS_M 0x000000ff +#define R92C_EDCA_PARAM_AIFS_S 0 +#define R92C_EDCA_PARAM_ECWMIN_M 0x00000f00 +#define R92C_EDCA_PARAM_ECWMIN_S 8 +#define R92C_EDCA_PARAM_ECWMAX_M 0x0000f000 +#define R92C_EDCA_PARAM_ECWMAX_S 12 +#define R92C_EDCA_PARAM_TXOP_M 0xffff0000 +#define R92C_EDCA_PARAM_TXOP_S 16 + +/* Bits for R92C_TXPAUSE. */ +#define R92C_TXPAUSE_AC_VO 0x01 +#define R92C_TXPAUSE_AC_VI 0x02 +#define R92C_TXPAUSE_AC_BE 0x04 +#define R92C_TXPAUSE_AC_BK 0x08 + +/* Bits for R92C_BCN_CTRL. */ +#define R92C_BCN_CTRL_EN_MBSSID 0x02 +#define R92C_BCN_CTRL_TXBCN_RPT 0x04 +#define R92C_BCN_CTRL_EN_BCN 0x08 +#define R92C_BCN_CTRL_DIS_TSF_UDT0 0x10 + +/* Bits for R92C_APSD_CTRL. */ +#define R92C_APSD_CTRL_OFF 0x40 +#define R92C_APSD_CTRL_OFF_STATUS 0x80 + +/* Bits for R92C_BWOPMODE. */ +#define R92C_BWOPMODE_11J 0x01 +#define R92C_BWOPMODE_5G 0x02 +#define R92C_BWOPMODE_20MHZ 0x04 + +/* Bits for R92C_TCR. */ +#define R92C_TCR_TSFRST 0x00000001 +#define R92C_TCR_DIS_GCLK 0x00000002 +#define R92C_TCR_PAD_SEL 0x00000004 +#define R92C_TCR_PWR_ST 0x00000040 +#define R92C_TCR_PWRBIT_OW_EN 0x00000080 +#define R92C_TCR_ACRC 0x00000100 +#define R92C_TCR_CFENDFORM 0x00000200 +#define R92C_TCR_ICV 0x00000400 + +/* Bits for R92C_RCR. */ +#define R92C_RCR_AAP 0x00000001 +#define R92C_RCR_APM 0x00000002 +#define R92C_RCR_AM 0x00000004 +#define R92C_RCR_AB 0x00000008 +#define R92C_RCR_ADD3 0x00000010 +#define R92C_RCR_APWRMGT 0x00000020 +#define R92C_RCR_CBSSID_DATA 0x00000040 +#define R92C_RCR_CBSSID_BCN 0x00000080 +#define R92C_RCR_ACRC32 0x00000100 +#define R92C_RCR_AICV 0x00000200 +#define R92C_RCR_ADF 0x00000800 +#define R92C_RCR_ACF 0x00001000 +#define R92C_RCR_AMF 0x00002000 +#define R92C_RCR_HTC_LOC_CTRL 0x00004000 +#define R92C_RCR_MFBEN 0x00400000 +#define R92C_RCR_LSIGEN 0x00800000 +#define R92C_RCR_ENMBID 0x01000000 +#define R92C_RCR_APP_BA_SSN 0x08000000 +#define R92C_RCR_APP_PHYSTS 0x10000000 +#define R92C_RCR_APP_ICV 0x20000000 +#define R92C_RCR_APP_MIC 0x40000000 +#define R92C_RCR_APPFCS 0x80000000 + +/* Bits for R92C_CAMCMD. */ +#define R92C_CAMCMD_ADDR_M 0x0000ffff +#define R92C_CAMCMD_ADDR_S 0 +#define R92C_CAMCMD_WRITE 0x00010000 +#define R92C_CAMCMD_CLR 0x40000000 +#define R92C_CAMCMD_POLLING 0x80000000 + +/* IMR */ + +/*Beacon DMA interrupt 6 */ +#define R92C_IMR_BCNDMAINT6 0x80000000 +/*Beacon DMA interrupt 5 */ +#define R92C_IMR_BCNDMAINT5 0x40000000 +/*Beacon DMA interrupt 4 */ +#define R92C_IMR_BCNDMAINT4 0x20000000 +/*Beacon DMA interrupt 3 */ +#define R92C_IMR_BCNDMAINT3 0x10000000 +/*Beacon DMA interrupt 2 */ +#define R92C_IMR_BCNDMAINT2 0x08000000 +/*Beacon DMA interrupt 1 */ +#define R92C_IMR_BCNDMAINT1 0x04000000 +/*Beacon Queue DMA OK interrupt 8 */ +#define R92C_IMR_BCNDOK8 0x02000000 +/*Beacon Queue DMA OK interrupt 7 */ +#define R92C_IMR_BCNDOK7 0x01000000 +/*Beacon Queue DMA OK interrupt 6 */ +#define R92C_IMR_BCNDOK6 0x00800000 +/*Beacon Queue DMA OK interrupt 5 */ +#define R92C_IMR_BCNDOK5 0x00400000 +/*Beacon Queue DMA OK interrupt 4 */ +#define R92C_IMR_BCNDOK4 0x00200000 +/*Beacon Queue DMA OK interrupt 3 */ +#define R92C_IMR_BCNDOK3 0x00100000 +/*Beacon Queue DMA OK interrupt 2 */ +#define R92C_IMR_BCNDOK2 0x00080000 +/*Beacon Queue DMA OK interrupt 1 */ +#define R92C_IMR_BCNDOK1 0x00040000 +/*Timeout interrupt 2 */ +#define R92C_IMR_TIMEOUT2 0x00020000 +/*Timeout interrupt 1 */ +#define R92C_IMR_TIMEOUT1 0x00010000 +/*Transmit FIFO Overflow */ +#define R92C_IMR_TXFOVW 0x00008000 +/*Power save time out interrupt */ +#define R92C_IMR_PSTIMEOUT 0x00004000 +/*Beacon DMA interrupt 0 */ +#define R92C_IMR_BCNINT 0x00002000 +/*Receive FIFO Overflow */ +#define R92C_IMR_RXFOVW 0x00001000 +/*Receive Descriptor Unavailable */ +#define R92C_IMR_RDU 0x00000800 +/*For 92C,ATIM Window End interrupt */ +#define R92C_IMR_ATIMEND 0x00000400 +/*Beacon Queue DMA OK interrupt */ +#define R92C_IMR_BDOK 0x00000200 +/*High Queue DMA OK interrupt */ +#define R92C_IMR_HIGHDOK 0x00000100 +/*Transmit Beacon OK interrupt */ +#define R92C_IMR_TBDOK 0x00000080 +/*Management Queue DMA OK interrupt */ +#define R92C_IMR_MGNTDOK 0x00000040 +/*For 92C,Transmit Beacon Error interrupt */ +#define R92C_IMR_TBDER 0x00000020 +/*AC_BK DMA OK interrupt */ +#define R92C_IMR_BKDOK 0x00000010 +/*AC_BE DMA OK interrupt */ +#define R92C_IMR_BEDOK 0x00000008 +/*AC_VI DMA OK interrupt */ +#define R92C_IMR_VIDOK 0x00000004 +/*AC_VO DMA interrupt */ +#define R92C_IMR_VODOK 0x00000002 +/*Receive DMA OK interrupt */ +#define R92C_IMR_ROK 0x00000001 + +#define R92C_IBSS_INT_MASK (R92C_IMR_BCNINT | R92C_IMR_TBDOK | R92C_IMR_TBDER) + +/* + * Baseband registers. + */ +#define R92C_FPGA0_RFMOD 0x800 +#define R92C_FPGA0_TXINFO 0x804 +#define R92C_HSSI_PARAM1(chain) (0x820 + (chain) * 8) +#define R92C_HSSI_PARAM2(chain) (0x824 + (chain) * 8) +#define R92C_TXAGC_RATE18_06(i) (((i) == 0) ? 0xe00 : 0x830) +#define R92C_TXAGC_RATE54_24(i) (((i) == 0) ? 0xe04 : 0x834) +#define R92C_TXAGC_A_CCK1_MCS32 0xe08 +#define R92C_TXAGC_B_CCK1_55_MCS32 0x838 +#define R92C_TXAGC_B_CCK11_A_CCK2_11 0x86c +#define R92C_TXAGC_MCS03_MCS00(i) (((i) == 0) ? 0xe10 : 0x83c) +#define R92C_TXAGC_MCS07_MCS04(i) (((i) == 0) ? 0xe14 : 0x848) +#define R92C_TXAGC_MCS11_MCS08(i) (((i) == 0) ? 0xe18 : 0x84c) +#define R92C_TXAGC_MCS15_MCS12(i) (((i) == 0) ? 0xe1c : 0x868) +#define R92C_LSSI_PARAM(chain) (0x840 + (chain) * 4) +#define R92C_FPGA0_RFIFACEOE(chain) (0x860 + (chain) * 4) +#define R92C_FPGA0_RFIFACESW(idx) (0x870 + (idx) * 4) +#define R92C_FPGA0_RFPARAM(idx) (0x878 + (idx) * 4) +#define R92C_FPGA0_ANAPARAM2 0x884 +#define R92C_LSSI_READBACK(chain) (0x8a0 + (chain) * 4) +#define R92C_HSPI_READBACK(chain) (0x8b8 + (chain) * 4) +#define R92C_FPGA1_RFMOD 0x900 +#define R92C_FPGA1_TXINFO 0x90c +#define R92C_CCK0_SYSTEM 0xa00 +#define R92C_CCK0_AFESETTING 0xa04 +#define R92C_OFDM0_TRXPATHENA 0xc04 +#define R92C_OFDM0_TRMUXPAR 0xc08 +#define R92C_OFDM0_RXIQIMBALANCE(chain) (0xc14 + (chain) * 8) +#define R92C_OFDM0_ECCATHRESHOLD 0xc4c +#define R92C_OFDM0_AGCCORE1(chain) (0xc50 + (chain) * 8) +#define R92C_OFDM0_AGCPARAM1 0xc70 +#define R92C_OFDM0_AGCRSSITABLE 0xc78 +#define R92C_OFDM0_TXIQIMBALANCE(chain) (0xc80 + (chain) * 8) +#define R92C_OFDM0_TXAFE(chain) (0xc94 + (chain) * 8) +#define R92C_OFDM0_RXIQEXTANTA 0xca0 +#define R92C_OFDM1_LSTF 0xd00 + +/* Bits for R92C_FPGA[01]_RFMOD. */ +#define R92C_RFMOD_40MHZ 0x00000001 +#define R92C_RFMOD_JAPAN 0x00000002 +#define R92C_RFMOD_CCK_TXSC 0x00000030 +#define R92C_RFMOD_CCK_EN 0x01000000 +#define R92C_RFMOD_OFDM_EN 0x02000000 + +/* Bits for R92C_HSSI_PARAM1(i). */ +#define R92C_HSSI_PARAM1_PI 0x00000100 + +/* Bits for R92C_HSSI_PARAM2(i). */ +#define R92C_HSSI_PARAM2_CCK_HIPWR 0x00000200 +#define R92C_HSSI_PARAM2_ADDR_LENGTH 0x00000400 +#define R92C_HSSI_PARAM2_DATA_LENGTH 0x00000800 +#define R92C_HSSI_PARAM2_READ_ADDR_M 0x7f800000 +#define R92C_HSSI_PARAM2_READ_ADDR_S 23 +#define R92C_HSSI_PARAM2_READ_EDGE 0x80000000 + +/* Bits for R92C_TXAGC_A_CCK1_MCS32. */ +#define R92C_TXAGC_A_CCK1_M 0x0000ff00 +#define R92C_TXAGC_A_CCK1_S 8 + +/* Bits for R92C_TXAGC_B_CCK11_A_CCK2_11. */ +#define R92C_TXAGC_B_CCK11_M 0x000000ff +#define R92C_TXAGC_B_CCK11_S 0 +#define R92C_TXAGC_A_CCK2_M 0x0000ff00 +#define R92C_TXAGC_A_CCK2_S 8 +#define R92C_TXAGC_A_CCK55_M 0x00ff0000 +#define R92C_TXAGC_A_CCK55_S 16 +#define R92C_TXAGC_A_CCK11_M 0xff000000 +#define R92C_TXAGC_A_CCK11_S 24 + +/* Bits for R92C_TXAGC_B_CCK1_55_MCS32. */ +#define R92C_TXAGC_B_CCK1_M 0x0000ff00 +#define R92C_TXAGC_B_CCK1_S 8 +#define R92C_TXAGC_B_CCK2_M 0x00ff0000 +#define R92C_TXAGC_B_CCK2_S 16 +#define R92C_TXAGC_B_CCK55_M 0xff000000 +#define R92C_TXAGC_B_CCK55_S 24 + +/* Bits for R92C_TXAGC_RATE18_06(x). */ +#define R92C_TXAGC_RATE06_M 0x000000ff +#define R92C_TXAGC_RATE06_S 0 +#define R92C_TXAGC_RATE09_M 0x0000ff00 +#define R92C_TXAGC_RATE09_S 8 +#define R92C_TXAGC_RATE12_M 0x00ff0000 +#define R92C_TXAGC_RATE12_S 16 +#define R92C_TXAGC_RATE18_M 0xff000000 +#define R92C_TXAGC_RATE18_S 24 + +/* Bits for R92C_TXAGC_RATE54_24(x). */ +#define R92C_TXAGC_RATE24_M 0x000000ff +#define R92C_TXAGC_RATE24_S 0 +#define R92C_TXAGC_RATE36_M 0x0000ff00 +#define R92C_TXAGC_RATE36_S 8 +#define R92C_TXAGC_RATE48_M 0x00ff0000 +#define R92C_TXAGC_RATE48_S 16 +#define R92C_TXAGC_RATE54_M 0xff000000 +#define R92C_TXAGC_RATE54_S 24 + +/* Bits for R92C_TXAGC_MCS03_MCS00(x). */ +#define R92C_TXAGC_MCS00_M 0x000000ff +#define R92C_TXAGC_MCS00_S 0 +#define R92C_TXAGC_MCS01_M 0x0000ff00 +#define R92C_TXAGC_MCS01_S 8 +#define R92C_TXAGC_MCS02_M 0x00ff0000 +#define R92C_TXAGC_MCS02_S 16 +#define R92C_TXAGC_MCS03_M 0xff000000 +#define R92C_TXAGC_MCS03_S 24 + +/* Bits for R92C_TXAGC_MCS07_MCS04(x). */ +#define R92C_TXAGC_MCS04_M 0x000000ff +#define R92C_TXAGC_MCS04_S 0 +#define R92C_TXAGC_MCS05_M 0x0000ff00 +#define R92C_TXAGC_MCS05_S 8 +#define R92C_TXAGC_MCS06_M 0x00ff0000 +#define R92C_TXAGC_MCS06_S 16 +#define R92C_TXAGC_MCS07_M 0xff000000 +#define R92C_TXAGC_MCS07_S 24 + +/* Bits for R92C_TXAGC_MCS11_MCS08(x). */ +#define R92C_TXAGC_MCS08_M 0x000000ff +#define R92C_TXAGC_MCS08_S 0 +#define R92C_TXAGC_MCS09_M 0x0000ff00 +#define R92C_TXAGC_MCS09_S 8 +#define R92C_TXAGC_MCS10_M 0x00ff0000 +#define R92C_TXAGC_MCS10_S 16 +#define R92C_TXAGC_MCS11_M 0xff000000 +#define R92C_TXAGC_MCS11_S 24 + +/* Bits for R92C_TXAGC_MCS15_MCS12(x). */ +#define R92C_TXAGC_MCS12_M 0x000000ff +#define R92C_TXAGC_MCS12_S 0 +#define R92C_TXAGC_MCS13_M 0x0000ff00 +#define R92C_TXAGC_MCS13_S 8 +#define R92C_TXAGC_MCS14_M 0x00ff0000 +#define R92C_TXAGC_MCS14_S 16 +#define R92C_TXAGC_MCS15_M 0xff000000 +#define R92C_TXAGC_MCS15_S 24 + +/* Bits for R92C_LSSI_PARAM(i). */ +#define R92C_LSSI_PARAM_DATA_M 0x000fffff +#define R92C_LSSI_PARAM_DATA_S 0 +#define R92C_LSSI_PARAM_ADDR_M 0x03f00000 +#define R92C_LSSI_PARAM_ADDR_S 20 + +/* Bits for R92C_FPGA0_ANAPARAM2. */ +#define R92C_FPGA0_ANAPARAM2_CBW20 0x00000400 + +/* Bits for R92C_LSSI_READBACK(i). */ +#define R92C_LSSI_READBACK_DATA_M 0x000fffff +#define R92C_LSSI_READBACK_DATA_S 0 + +/* Bits for R92C_OFDM0_AGCCORE1(i). */ +#define R92C_OFDM0_AGCCORE1_GAIN_M 0x0000007f +#define R92C_OFDM0_AGCCORE1_GAIN_S 0 + + +/* + * USB registers. + */ +#define R92C_USB_INFO 0xfe17 +#define R92C_USB_SPECIAL_OPTION 0xfe55 +#define R92C_USB_HCPWM 0xfe57 +#define R92C_USB_HRPWM 0xfe58 +#define R92C_USB_DMA_AGG_TO 0xfe5b +#define R92C_USB_AGG_TO 0xfe5c +#define R92C_USB_AGG_TH 0xfe5d +#define R92C_USB_VID 0xfe60 +#define R92C_USB_PID 0xfe62 +#define R92C_USB_OPTIONAL 0xfe64 +#define R92C_USB_EP 0xfe65 +#define R92C_USB_PHY 0xfe68 +#define R92C_USB_MAC_ADDR 0xfe70 +#define R92C_USB_STRING 0xfe80 + +/* Bits for R92C_USB_SPECIAL_OPTION. */ +#define R92C_USB_SPECIAL_OPTION_AGG_EN 0x08 + +/* Bits for R92C_USB_EP. */ +#define R92C_USB_EP_HQ_M 0x000f +#define R92C_USB_EP_HQ_S 0 +#define R92C_USB_EP_NQ_M 0x00f0 +#define R92C_USB_EP_NQ_S 4 +#define R92C_USB_EP_LQ_M 0x0f00 +#define R92C_USB_EP_LQ_S 8 + + +/* + * Firmware base address. + */ +#define R92C_FW_START_ADDR 0x1000 +#define R92C_FW_PAGE_SIZE 4096 + + +/* + * RF (6052) registers. + */ +#define R92C_RF_AC 0x00 +#define R92C_RF_IQADJ_G(i) (0x01 + (i)) +#define R92C_RF_POW_TRSW 0x05 +#define R92C_RF_GAIN_RX 0x06 +#define R92C_RF_GAIN_TX 0x07 +#define R92C_RF_TXM_IDAC 0x08 +#define R92C_RF_BS_IQGEN 0x0f +#define R92C_RF_MODE1 0x10 +#define R92C_RF_MODE2 0x11 +#define R92C_RF_RX_AGC_HP 0x12 +#define R92C_RF_TX_AGC 0x13 +#define R92C_RF_BIAS 0x14 +#define R92C_RF_IPA 0x15 +#define R92C_RF_POW_ABILITY 0x17 +#define R92C_RF_CHNLBW 0x18 +#define R92C_RF_RX_G1 0x1a +#define R92C_RF_RX_G2 0x1b +#define R92C_RF_RX_BB2 0x1c +#define R92C_RF_RX_BB1 0x1d +#define R92C_RF_RCK1 0x1e +#define R92C_RF_RCK2 0x1f +#define R92C_RF_TX_G(i) (0x20 + (i)) +#define R92C_RF_TX_BB1 0x23 +#define R92C_RF_T_METER 0x24 +#define R92C_RF_SYN_G(i) (0x25 + (i)) +#define R92C_RF_RCK_OS 0x30 +#define R92C_RF_TXPA_G(i) (0x31 + (i)) + +/* Bits for R92C_RF_AC. */ +#define R92C_RF_AC_MODE_M 0x70000 +#define R92C_RF_AC_MODE_S 16 +#define R92C_RF_AC_MODE_STANDBY 1 + +/* Bits for R92C_RF_CHNLBW. */ +#define R92C_RF_CHNLBW_CHNL_M 0x003ff +#define R92C_RF_CHNLBW_CHNL_S 0 +#define R92C_RF_CHNLBW_BW20 0x00400 +#define R92C_RF_CHNLBW_LCSTART 0x08000 + + +/* + * CAM entries. + */ +#define R92C_CAM_ENTRY_COUNT 32 + +#define R92C_CAM_CTL0(entry) ((entry) * 8 + 0) +#define R92C_CAM_CTL1(entry) ((entry) * 8 + 1) +#define R92C_CAM_KEY(entry, i) ((entry) * 8 + 2 + (i)) + +/* Bits for R92C_CAM_CTL0(i). */ +#define R92C_CAM_KEYID_M 0x00000003 +#define R92C_CAM_KEYID_S 0 +#define R92C_CAM_ALGO_M 0x0000001c +#define R92C_CAM_ALGO_S 2 +#define R92C_CAM_ALGO_NONE 0 +#define R92C_CAM_ALGO_WEP40 1 +#define R92C_CAM_ALGO_TKIP 2 +#define R92C_CAM_ALGO_AES 4 +#define R92C_CAM_ALGO_WEP104 5 +#define R92C_CAM_VALID 0x00008000 +#define R92C_CAM_MACLO_M 0xffff0000 +#define R92C_CAM_MACLO_S 16 + +/* Rate adaptation modes. */ +#define R92C_RAID_11GN 1 +#define R92C_RAID_11N 3 +#define R92C_RAID_11BG 4 +#define R92C_RAID_11G 5 /* "pure" 11g */ +#define R92C_RAID_11B 6 + + +/* Macros to access unaligned little-endian memory. */ +#define LE_READ_2(x) ((x)[0] | (x)[1] << 8) +#define LE_READ_4(x) ((x)[0] | (x)[1] << 8 | (x)[2] << 16 | (x)[3] << 24) + +/* + * Macros to access subfields in registers. + */ +/* Mask and Shift (getter). */ +#define MS(val, field) \ + (((val) & field##_M) >> field##_S) + +/* Shift and Mask (setter). */ +#define SM(field, val) \ + (((val) << field##_S) & field##_M) + +/* Rewrite. */ +#define RW(var, field, val) \ + (((var) & ~field##_M) | SM(field, val)) + +/* + * Firmware image header. + */ +struct r92c_fw_hdr { + /* QWORD0 */ + uint16_t signature; + uint8_t category; + uint8_t function; + uint16_t version; + uint16_t subversion; + /* QWORD1 */ + uint8_t month; + uint8_t date; + uint8_t hour; + uint8_t minute; + uint16_t ramcodesize; + uint16_t reserved2; + /* QWORD2 */ + uint32_t svnidx; + uint32_t reserved3; + /* QWORD3 */ + uint32_t reserved4; + uint32_t reserved5; +} __packed; + +/* + * Host to firmware commands. + */ +struct r92c_fw_cmd { + uint8_t id; +#define R92C_CMD_AP_OFFLOAD 0 +#define R92C_CMD_SET_PWRMODE 1 +#define R92C_CMD_JOINBSS_RPT 2 +#define R92C_CMD_RSVD_PAGE 3 +#define R92C_CMD_RSSI 4 +#define R92C_CMD_RSSI_SETTING 5 +#define R92C_CMD_MACID_CONFIG 6 +#define R92C_CMD_MACID_PS_MODE 7 +#define R92C_CMD_P2P_PS_OFFLOAD 8 +#define R92C_CMD_SELECTIVE_SUSPEND 9 +#define R92C_CMD_FLAG_EXT 0x80 + + uint8_t msg[5]; +} __packed; + +/* Structure for R92C_CMD_RSSI_SETTING. */ +struct r92c_fw_cmd_rssi { + uint8_t macid; + uint8_t reserved; + uint8_t pwdb; +} __packed; + +/* Structure for R92C_CMD_MACID_CONFIG. */ +struct r92c_fw_cmd_macid_cfg { + uint32_t mask; + uint8_t macid; +#define RTWN_MACID_BSS 0 +#define RTWN_MACID_BC 4 /* Broadcast. */ +#define RTWN_MACID_VALID 0x80 +} __packed; + +/* + * RTL8192CU ROM image. + */ +struct r92c_rom { + uint16_t id; /* 0x8129 */ + uint8_t reserved1[5]; + uint8_t dbg_sel; + uint16_t reserved2; + uint16_t vid; + uint16_t pid; + uint8_t usb_opt; + uint8_t ep_setting; + uint16_t reserved3; + uint8_t usb_phy; + uint8_t reserved4[3]; + uint8_t macaddr[6]; + uint8_t string[61]; /* "Realtek" */ + uint8_t subcustomer_id; + uint8_t cck_tx_pwr[R92C_MAX_CHAINS][3]; + uint8_t ht40_1s_tx_pwr[R92C_MAX_CHAINS][3]; + uint8_t ht40_2s_tx_pwr_diff[3]; + uint8_t ht20_tx_pwr_diff[3]; + uint8_t ofdm_tx_pwr_diff[3]; + uint8_t ht40_max_pwr[3]; + uint8_t ht20_max_pwr[3]; + uint8_t xtal_calib; + uint8_t tssi[R92C_MAX_CHAINS]; + uint8_t thermal_meter; + uint8_t rf_opt1; +#define R92C_ROM_RF1_REGULATORY_M 0x07 +#define R92C_ROM_RF1_REGULATORY_S 0 +#define R92C_ROM_RF1_BOARD_TYPE_M 0xe0 +#define R92C_ROM_RF1_BOARD_TYPE_S 5 +#define R92C_BOARD_TYPE_DONGLE 0 +#define R92C_BOARD_TYPE_HIGHPA 1 +#define R92C_BOARD_TYPE_MINICARD 2 +#define R92C_BOARD_TYPE_SOLO 3 +#define R92C_BOARD_TYPE_COMBO 4 + + uint8_t rf_opt2; + uint8_t rf_opt3; + uint8_t rf_opt4; + uint8_t channel_plan; + uint8_t version; + uint8_t curstomer_id; +} __packed; + +/* Rx MAC descriptor. */ +struct r92c_rx_desc { + uint32_t rxdw0; +#define R92C_RXDW0_PKTLEN_M 0x00003fff +#define R92C_RXDW0_PKTLEN_S 0 +#define R92C_RXDW0_CRCERR 0x00004000 +#define R92C_RXDW0_ICVERR 0x00008000 +#define R92C_RXDW0_INFOSZ_M 0x000f0000 +#define R92C_RXDW0_INFOSZ_S 16 +#define R92C_RXDW0_QOS 0x00800000 +#define R92C_RXDW0_SHIFT_M 0x03000000 +#define R92C_RXDW0_SHIFT_S 24 +#define R92C_RXDW0_PHYST 0x04000000 +#define R92C_RXDW0_DECRYPTED 0x08000000 +#define R92C_RXDW0_LS 0x10000000 +#define R92C_RXDW0_FS 0x20000000 +#define R92C_RXDW0_EOR 0x40000000 +#define R92C_RXDW0_OWN 0x80000000 + + uint32_t rxdw1; + uint32_t rxdw2; +#define R92C_RXDW2_PKTCNT_M 0x00ff0000 +#define R92C_RXDW2_PKTCNT_S 16 + + uint32_t rxdw3; +#define R92C_RXDW3_RATE_M 0x0000003f +#define R92C_RXDW3_RATE_S 0 +#define R92C_RXDW3_HT 0x00000040 +#define R92C_RXDW3_HTC 0x00000400 + + uint32_t rxdw4; + uint32_t rxdw5; + + uint32_t rxbufaddr; + uint32_t rxbufaddr64; +} __packed __attribute__((aligned(4))); + +/* Rx PHY descriptor. */ +struct r92c_rx_phystat { + uint32_t phydw0; + uint32_t phydw1; + uint32_t phydw2; + uint32_t phydw3; + uint32_t phydw4; + uint32_t phydw5; + uint32_t phydw6; + uint32_t phydw7; +} __packed __attribute__((aligned(4))); + +/* Rx PHY CCK descriptor. */ +struct r92c_rx_cck { + uint8_t adc_pwdb[4]; + uint8_t sq_rpt; + uint8_t agc_rpt; +} __packed; + +/* Tx MAC descriptor. */ +struct r92c_tx_desc { + uint32_t txdw0; +#define R92C_TXDW0_PKTLEN_M 0x0000ffff +#define R92C_TXDW0_PKTLEN_S 0 +#define R92C_TXDW0_OFFSET_M 0x00ff0000 +#define R92C_TXDW0_OFFSET_S 16 +#define R92C_TXDW0_BMCAST 0x01000000 +#define R92C_TXDW0_LSG 0x04000000 +#define R92C_TXDW0_FSG 0x08000000 +#define R92C_TXDW0_OWN 0x80000000 + + uint32_t txdw1; +#define R92C_TXDW1_MACID_M 0x0000001f +#define R92C_TXDW1_MACID_S 0 +#define R92C_TXDW1_AGGEN 0x00000020 +#define R92C_TXDW1_AGGBK 0x00000040 +#define R92C_TXDW1_QSEL_M 0x00001f00 +#define R92C_TXDW1_QSEL_S 8 +#define R92C_TXDW1_QSEL_BE 0x00 +#define R92C_TXDW1_QSEL_BK 0x02 +#define R92C_TXDW1_QSEL_VI 0x05 +#define R92C_TXDW1_QSEL_VO 0x07 +#define R92C_TXDW1_QSEL_BEACON 0x10 +#define R92C_TXDW1_QSEL_HIGH 0x11 +#define R92C_TXDW1_QSEL_MGNT 0x12 +#define R92C_TXDW1_QSEL_CMD 0x13 +#define R92C_TXDW1_RAID_M 0x000f0000 +#define R92C_TXDW1_RAID_S 16 +#define R92C_TXDW1_CIPHER_M 0x00c00000 +#define R92C_TXDW1_CIPHER_S 22 +#define R92C_TXDW1_CIPHER_NONE 0 +#define R92C_TXDW1_CIPHER_RC4 1 +#define R92C_TXDW1_CIPHER_AES 3 +#define R92C_TXDW1_PKTOFF_M 0x7c000000 +#define R92C_TXDW1_PKTOFF_S 26 + + uint32_t txdw2; + uint16_t txdw3; + uint16_t txdseq; + + uint32_t txdw4; +#define R92C_TXDW4_RTSRATE_M 0x0000003f +#define R92C_TXDW4_RTSRATE_S 0 +#define R92C_TXDW4_QOS 0x00000040 +#define R92C_TXDW4_HWSEQ 0x00000080 +#define R92C_TXDW4_DRVRATE 0x00000100 +#define R92C_TXDW4_CTS2SELF 0x00000800 +#define R92C_TXDW4_RTSEN 0x00001000 +#define R92C_TXDW4_HWRTSEN 0x00002000 +#define R92C_TXDW4_SCO_M 0x003f0000 +#define R92C_TXDW4_SCO_S 20 +#define R92C_TXDW4_SCO_SCA 1 +#define R92C_TXDW4_SCO_SCB 2 +#define R92C_TXDW4_40MHZ 0x02000000 + + uint32_t txdw5; +#define R92C_TXDW5_DATARATE_M 0x0000003f +#define R92C_TXDW5_DATARATE_S 0 +#define R92C_TXDW5_SGI 0x00000040 +#define R92C_TXDW5_DATARATE_FBLIMIT_M 0x00001f00 +#define R92C_TXDW5_DATARATE_FBLIMIT_S 8 +#define R92C_TXDW5_RTSRATE_FBLIMIT_M 0x0001e000 +#define R92C_TXDW5_RTSRATE_FBLIMIT_S 13 +#define R92C_TXDW5_RETRY_LIMIT_ENABLE 0x00020000 +#define R92C_TXDW5_DATA_RETRY_LIMIT_M 0x00fc0000 +#define R92C_TXDW5_DATA_RETRY_LIMIT_S 18 +#define R92C_TXDW5_AGGNUM_M 0xff000000 +#define R92C_TXDW5_AGGNUM_S 24 + + uint32_t txdw6; + + uint16_t txbufsize; + uint16_t pad; + + uint32_t txbufaddr; + uint32_t txbufaddr64; + + uint32_t nextdescaddr; + uint32_t nextdescaddr64; + + uint32_t reserved[4]; +} __packed __attribute__((aligned(4))); + + +/* + * Driver definitions. + */ +#define RTWN_NTXQUEUES 9 +#define RTWN_RX_LIST_COUNT 256 +#define RTWN_TX_LIST_COUNT 256 +#define RTWN_HOST_CMD_RING_COUNT 32 + +/* TX queue indices. */ +#define RTWN_BK_QUEUE 0 +#define RTWN_BE_QUEUE 1 +#define RTWN_VI_QUEUE 2 +#define RTWN_VO_QUEUE 3 +#define RTWN_BEACON_QUEUE 4 +#define RTWN_TXCMD_QUEUE 5 +#define RTWN_MGNT_QUEUE 6 +#define RTWN_HIGH_QUEUE 7 +#define RTWN_HCCA_QUEUE 8 + +/* RX queue indices. */ +#define RTWN_RX_QUEUE 0 + +#define RTWN_RXBUFSZ (16 * 1024) +#define RTWN_TXBUFSZ (sizeof(struct r92c_tx_desc) + IEEE80211_MAX_LEN) + +#define RTWN_RIDX_COUNT 28 + +#define RTWN_TX_TIMEOUT 5000 /* ms */ + +#define RTWN_LED_LINK 0 +#define RTWN_LED_DATA 1 + +struct rtwn_rx_radiotap_header { + struct ieee80211_radiotap_header wr_ihdr; + uint8_t wr_flags; + uint8_t wr_rate; + uint16_t wr_chan_freq; + uint16_t wr_chan_flags; + uint8_t wr_dbm_antsignal; +} __packed; + +#define RTWN_RX_RADIOTAP_PRESENT \ + (1 << IEEE80211_RADIOTAP_FLAGS | \ + 1 << IEEE80211_RADIOTAP_RATE | \ + 1 << IEEE80211_RADIOTAP_CHANNEL | \ + 1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) + +struct rtwn_tx_radiotap_header { + struct ieee80211_radiotap_header wt_ihdr; + uint8_t wt_flags; + uint16_t wt_chan_freq; + uint16_t wt_chan_flags; +} __packed; + +#define RTWN_TX_RADIOTAP_PRESENT \ + (1 << IEEE80211_RADIOTAP_FLAGS | \ + 1 << IEEE80211_RADIOTAP_CHANNEL) + +struct rtwn_softc; + +struct rtwn_rx_data { + bus_dmamap_t map; + struct mbuf *m; + bus_addr_t paddr; +}; + +struct rtwn_rx_ring { + struct r92c_rx_desc *desc; + bus_addr_t paddr; + bus_dma_tag_t desc_dmat; + bus_dmamap_t desc_map; + bus_dma_tag_t data_dmat; + bus_dma_segment_t seg; + struct rtwn_rx_data rx_data[RTWN_RX_LIST_COUNT]; + +}; +struct rtwn_tx_data { + bus_dmamap_t map; + struct mbuf *m; + struct ieee80211_node *ni; +}; + +struct rtwn_tx_ring { + bus_addr_t paddr; + bus_dma_tag_t desc_dmat; + bus_dmamap_t desc_map; + bus_dma_tag_t data_dmat; + bus_dma_segment_t seg; + struct r92c_tx_desc *desc; + struct rtwn_tx_data tx_data[RTWN_TX_LIST_COUNT]; + int queued; + int cur; +}; + +struct rtwn_host_cmd { + void (*cb)(struct rtwn_softc *, void *); + uint8_t data[256]; +}; + +struct rtwn_cmd_key { + struct ieee80211_key key; + uint16_t associd; +}; + +struct rtwn_host_cmd_ring { + struct rtwn_host_cmd cmd[RTWN_HOST_CMD_RING_COUNT]; + int cur; + int next; + int queued; +}; + +struct rtwn_vap { + struct ieee80211vap vap; + int (*newstate)(struct ieee80211vap *, + enum ieee80211_state, int); +}; +#define RTWN_VAP(vap) ((struct rtwn_vap *)(vap)) + +struct rtwn_softc { + device_t sc_dev; + struct mtx sc_mtx; + struct ieee80211com sc_ic; + struct mbufq sc_snd; + + struct resource *irq; + struct resource *mem; + bus_space_tag_t sc_st; + bus_space_handle_t sc_sh; + void *sc_ih; + bus_size_t sc_mapsize; + int sc_cap_off; + + struct task sc_reinit_task; + struct callout calib_to; + struct callout watchdog_to; + + int sc_debug; + + u_int sc_flags; +#define RTWN_FLAG_CCK_HIPWR 0x01 +#define RTWN_FLAG_BUSY 0x02 +#define RTWN_RUNNING 0x04 + + u_int chip; +#define RTWN_CHIP_88C 0x00 +#define RTWN_CHIP_92C 0x01 +#define RTWN_CHIP_92C_1T2R 0x02 +#define RTWN_CHIP_UMC 0x04 +#define RTWN_CHIP_UMC_A_CUT 0x08 + + uint8_t board_type; + uint8_t regulatory; + uint8_t pa_setting; + int avg_pwdb; + int thcal_state; + int thcal_lctemp; + int ntxchains; + int nrxchains; + int ledlink; + + int sc_tx_timer; + int fwcur; + struct rtwn_rx_ring rx_ring; + struct rtwn_tx_ring tx_ring[RTWN_NTXQUEUES]; + uint32_t qfullmsk; + struct r92c_rom rom; + + uint32_t rf_chnlbw[R92C_MAX_CHAINS]; + + struct rtwn_rx_radiotap_header sc_rxtap; + struct rtwn_tx_radiotap_header sc_txtap; +}; + +/* + * MAC initialization values. + */ +static const struct { + uint16_t reg; + uint8_t val; +} rtl8192ce_mac[] = { + { 0x420, 0x80 }, { 0x423, 0x00 }, { 0x430, 0x00 }, { 0x431, 0x00 }, + { 0x432, 0x00 }, { 0x433, 0x01 }, { 0x434, 0x04 }, { 0x435, 0x05 }, + { 0x436, 0x06 }, { 0x437, 0x07 }, { 0x438, 0x00 }, { 0x439, 0x00 }, + { 0x43a, 0x00 }, { 0x43b, 0x01 }, { 0x43c, 0x04 }, { 0x43d, 0x05 }, + { 0x43e, 0x06 }, { 0x43f, 0x07 }, { 0x440, 0x5d }, { 0x441, 0x01 }, + { 0x442, 0x00 }, { 0x444, 0x15 }, { 0x445, 0xf0 }, { 0x446, 0x0f }, + { 0x447, 0x00 }, { 0x458, 0x41 }, { 0x459, 0xa8 }, { 0x45a, 0x72 }, + { 0x45b, 0xb9 }, { 0x460, 0x88 }, { 0x461, 0x88 }, { 0x462, 0x06 }, + { 0x463, 0x03 }, { 0x4c8, 0x04 }, { 0x4c9, 0x08 }, { 0x4cc, 0x02 }, + { 0x4cd, 0x28 }, { 0x4ce, 0x01 }, { 0x500, 0x26 }, { 0x501, 0xa2 }, + { 0x502, 0x2f }, { 0x503, 0x00 }, { 0x504, 0x28 }, { 0x505, 0xa3 }, + { 0x506, 0x5e }, { 0x507, 0x00 }, { 0x508, 0x2b }, { 0x509, 0xa4 }, + { 0x50a, 0x5e }, { 0x50b, 0x00 }, { 0x50c, 0x4f }, { 0x50d, 0xa4 }, + { 0x50e, 0x00 }, { 0x50f, 0x00 }, { 0x512, 0x1c }, { 0x514, 0x0a }, + { 0x515, 0x10 }, { 0x516, 0x0a }, { 0x517, 0x10 }, { 0x51a, 0x16 }, + { 0x524, 0x0f }, { 0x525, 0x4f }, { 0x546, 0x20 }, { 0x547, 0x00 }, + { 0x559, 0x02 }, { 0x55a, 0x02 }, { 0x55d, 0xff }, { 0x605, 0x30 }, + { 0x608, 0x0e }, { 0x609, 0x2a }, { 0x652, 0x20 }, { 0x63c, 0x0a }, + { 0x63d, 0x0e }, { 0x700, 0x21 }, { 0x701, 0x43 }, { 0x702, 0x65 }, + { 0x703, 0x87 }, { 0x708, 0x21 }, { 0x709, 0x43 }, { 0x70a, 0x65 }, + { 0x70b, 0x87 } +}; + +/* + * Baseband initialization values. + */ +struct rtwn_bb_prog { + int count; + const uint16_t *regs; + const uint32_t *vals; + int agccount; + const uint32_t *agcvals; +}; + +/* + * RTL8192CU and RTL8192CE-VAU. + */ +static const uint16_t rtl8192ce_bb_regs[] = { + 0x024, 0x028, 0x800, 0x804, 0x808, 0x80c, 0x810, 0x814, 0x818, + 0x81c, 0x820, 0x824, 0x828, 0x82c, 0x830, 0x834, 0x838, 0x83c, + 0x840, 0x844, 0x848, 0x84c, 0x850, 0x854, 0x858, 0x85c, 0x860, + 0x864, 0x868, 0x86c, 0x870, 0x874, 0x878, 0x87c, 0x880, 0x884, + 0x888, 0x88c, 0x890, 0x894, 0x898, 0x89c, 0x900, 0x904, 0x908, + 0x90c, 0xa00, 0xa04, 0xa08, 0xa0c, 0xa10, 0xa14, 0xa18, 0xa1c, + 0xa20, 0xa24, 0xa28, 0xa2c, 0xa70, 0xa74, 0xc00, 0xc04, 0xc08, + 0xc0c, 0xc10, 0xc14, 0xc18, 0xc1c, 0xc20, 0xc24, 0xc28, 0xc2c, + 0xc30, 0xc34, 0xc38, 0xc3c, 0xc40, 0xc44, 0xc48, 0xc4c, 0xc50, + 0xc54, 0xc58, 0xc5c, 0xc60, 0xc64, 0xc68, 0xc6c, 0xc70, 0xc74, + 0xc78, 0xc7c, 0xc80, 0xc84, 0xc88, 0xc8c, 0xc90, 0xc94, 0xc98, + 0xc9c, 0xca0, 0xca4, 0xca8, 0xcac, 0xcb0, 0xcb4, 0xcb8, 0xcbc, + 0xcc0, 0xcc4, 0xcc8, 0xccc, 0xcd0, 0xcd4, 0xcd8, 0xcdc, 0xce0, + 0xce4, 0xce8, 0xcec, 0xd00, 0xd04, 0xd08, 0xd0c, 0xd10, 0xd14, + 0xd18, 0xd2c, 0xd30, 0xd34, 0xd38, 0xd3c, 0xd40, 0xd44, 0xd48, + 0xd4c, 0xd50, 0xd54, 0xd58, 0xd5c, 0xd60, 0xd64, 0xd68, 0xd6c, + 0xd70, 0xd74, 0xd78, 0xe00, 0xe04, 0xe08, 0xe10, 0xe14, 0xe18, + 0xe1c, 0xe28, 0xe30, 0xe34, 0xe38, 0xe3c, 0xe40, 0xe44, 0xe48, + 0xe4c, 0xe50, 0xe54, 0xe58, 0xe5c, 0xe60, 0xe68, 0xe6c, 0xe70, + 0xe74, 0xe78, 0xe7c, 0xe80, 0xe84, 0xe88, 0xe8c, 0xed0, 0xed4, + 0xed8, 0xedc, 0xee0, 0xeec, 0xf14, 0xf4c, 0xf00 +}; + +static const uint32_t rtl8192ce_bb_vals_2t[] = { + 0x0011800f, 0x00ffdb83, 0x80040002, 0x00000003, 0x0000fc00, + 0x0000000a, 0x10005388, 0x020c3d10, 0x02200385, 0x00000000, + 0x01000100, 0x00390004, 0x01000100, 0x00390004, 0x27272727, + 0x27272727, 0x27272727, 0x27272727, 0x00010000, 0x00010000, + 0x27272727, 0x27272727, 0x00000000, 0x00000000, 0x569a569a, + 0x0c1b25a4, 0x66e60230, 0x061f0130, 0x27272727, 0x2b2b2b27, + 0x07000700, 0x22184000, 0x08080808, 0x00000000, 0xc0083070, + 0x000004d5, 0x00000000, 0xcc0000c0, 0x00000800, 0xfffffffe, + 0x40302010, 0x00706050, 0x00000000, 0x00000023, 0x00000000, + 0x81121313, 0x00d047c8, 0x80ff000c, 0x8c838300, 0x2e68120f, + 0x9500bb78, 0x11144028, 0x00881117, 0x89140f00, 0x1a1b0000, + 0x090e1317, 0x00000204, 0x00d30000, 0x101fbf00, 0x00000007, + 0x48071d40, 0x03a05633, 0x000000e4, 0x6c6c6c6c, 0x08800000, + 0x40000100, 0x08800000, 0x40000100, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x69e9ac44, 0x469652cf, 0x49795994, + 0x0a97971c, 0x1f7c403f, 0x000100b7, 0xec020107, 0x007f037f, + 0x69543420, 0x43bc0094, 0x69543420, 0x433c0094, 0x00000000, + 0x5116848b, 0x47c00bff, 0x00000036, 0x2c7f000d, 0x018610db, + 0x0000001f, 0x00b91612, 0x40000100, 0x20f60000, 0x40000100, + 0x20200000, 0x00121820, 0x00000000, 0x00121820, 0x00007f7f, + 0x00000000, 0x00000080, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x28000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x64b22427, + 0x00766932, 0x00222222, 0x00000000, 0x37644302, 0x2f97d40c, + 0x00080740, 0x00020403, 0x0000907f, 0x20010201, 0xa0633333, + 0x3333bc43, 0x7a8f5b6b, 0xcc979975, 0x00000000, 0x80608000, + 0x00000000, 0x00027293, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x6437140a, 0x00000000, 0x00000000, 0x30032064, + 0x4653de68, 0x04518a3c, 0x00002101, 0x2a201c16, 0x1812362e, + 0x322c2220, 0x000e3c24, 0x2a2a2a2a, 0x2a2a2a2a, 0x03902a2a, + 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x00000000, + 0x1000dc1f, 0x10008c1f, 0x02140102, 0x681604c2, 0x01007c00, + 0x01004800, 0xfb000000, 0x000028d1, 0x1000dc1f, 0x10008c1f, + 0x02140102, 0x28160d05, 0x00000010, 0x001b25a4, 0x63db25a4, + 0x63db25a4, 0x0c1b25a4, 0x0c1b25a4, 0x0c1b25a4, 0x0c1b25a4, + 0x63db25a4, 0x0c1b25a4, 0x63db25a4, 0x63db25a4, 0x63db25a4, + 0x63db25a4, 0x001b25a4, 0x001b25a4, 0x6fdb25a4, 0x00000003, + 0x00000000, 0x00000300 +}; + +static const uint32_t rtl8192ce_bb_vals_1t[] = { + 0x0011800f, 0x00ffdb83, 0x80040000, 0x00000001, 0x0000fc00, + 0x0000000a, 0x10005388, 0x020c3d10, 0x02200385, 0x00000000, + 0x01000100, 0x00390004, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00010000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x569a569a, + 0x001b25a4, 0x66e60230, 0x061f0130, 0x00000000, 0x32323200, + 0x07000700, 0x22004000, 0x00000808, 0x00000000, 0xc0083070, + 0x000004d5, 0x00000000, 0xccc000c0, 0x00000800, 0xfffffffe, + 0x40302010, 0x00706050, 0x00000000, 0x00000023, 0x00000000, + 0x81121111, 0x00d047c8, 0x80ff000c, 0x8c838300, 0x2e68120f, + 0x9500bb78, 0x11144028, 0x00881117, 0x89140f00, 0x1a1b0000, + 0x090e1317, 0x00000204, 0x00d30000, 0x101fbf00, 0x00000007, + 0x48071d40, 0x03a05611, 0x000000e4, 0x6c6c6c6c, 0x08800000, + 0x40000100, 0x08800000, 0x40000100, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x69e9ac44, 0x469652cf, 0x49795994, + 0x0a97971c, 0x1f7c403f, 0x000100b7, 0xec020107, 0x007f037f, + 0x69543420, 0x43bc0094, 0x69543420, 0x433c0094, 0x00000000, + 0x5116848b, 0x47c00bff, 0x00000036, 0x2c7f000d, 0x018610db, + 0x0000001f, 0x00b91612, 0x40000100, 0x20f60000, 0x40000100, + 0x20200000, 0x00121820, 0x00000000, 0x00121820, 0x00007f7f, + 0x00000000, 0x00000080, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x28000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x64b22427, + 0x00766932, 0x00222222, 0x00000000, 0x37644302, 0x2f97d40c, + 0x00080740, 0x00020401, 0x0000907f, 0x20010201, 0xa0633333, + 0x3333bc43, 0x7a8f5b6b, 0xcc979975, 0x00000000, 0x80608000, + 0x00000000, 0x00027293, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x6437140a, 0x00000000, 0x00000000, 0x30032064, + 0x4653de68, 0x04518a3c, 0x00002101, 0x2a201c16, 0x1812362e, + 0x322c2220, 0x000e3c24, 0x2a2a2a2a, 0x2a2a2a2a, 0x03902a2a, + 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x00000000, + 0x1000dc1f, 0x10008c1f, 0x02140102, 0x681604c2, 0x01007c00, + 0x01004800, 0xfb000000, 0x000028d1, 0x1000dc1f, 0x10008c1f, + 0x02140102, 0x28160d05, 0x00000010, 0x001b25a4, 0x631b25a0, + 0x631b25a0, 0x081b25a0, 0x081b25a0, 0x081b25a0, 0x081b25a0, + 0x631b25a0, 0x081b25a0, 0x631b25a0, 0x631b25a0, 0x631b25a0, + 0x631b25a0, 0x001b25a0, 0x001b25a0, 0x6b1b25a0, 0x00000003, + 0x00000000, 0x00000300, +}; + +static const uint32_t rtl8192ce_agc_vals[] = { + 0x7b000001, 0x7b010001, 0x7b020001, 0x7b030001, 0x7b040001, + 0x7b050001, 0x7a060001, 0x79070001, 0x78080001, 0x77090001, + 0x760a0001, 0x750b0001, 0x740c0001, 0x730d0001, 0x720e0001, + 0x710f0001, 0x70100001, 0x6f110001, 0x6e120001, 0x6d130001, + 0x6c140001, 0x6b150001, 0x6a160001, 0x69170001, 0x68180001, + 0x67190001, 0x661a0001, 0x651b0001, 0x641c0001, 0x631d0001, + 0x621e0001, 0x611f0001, 0x60200001, 0x49210001, 0x48220001, + 0x47230001, 0x46240001, 0x45250001, 0x44260001, 0x43270001, + 0x42280001, 0x41290001, 0x402a0001, 0x262b0001, 0x252c0001, + 0x242d0001, 0x232e0001, 0x222f0001, 0x21300001, 0x20310001, + 0x06320001, 0x05330001, 0x04340001, 0x03350001, 0x02360001, + 0x01370001, 0x00380001, 0x00390001, 0x003a0001, 0x003b0001, + 0x003c0001, 0x003d0001, 0x003e0001, 0x003f0001, 0x7b400001, + 0x7b410001, 0x7b420001, 0x7b430001, 0x7b440001, 0x7b450001, + 0x7a460001, 0x79470001, 0x78480001, 0x77490001, 0x764a0001, + 0x754b0001, 0x744c0001, 0x734d0001, 0x724e0001, 0x714f0001, + 0x70500001, 0x6f510001, 0x6e520001, 0x6d530001, 0x6c540001, + 0x6b550001, 0x6a560001, 0x69570001, 0x68580001, 0x67590001, + 0x665a0001, 0x655b0001, 0x645c0001, 0x635d0001, 0x625e0001, + 0x615f0001, 0x60600001, 0x49610001, 0x48620001, 0x47630001, + 0x46640001, 0x45650001, 0x44660001, 0x43670001, 0x42680001, + 0x41690001, 0x406a0001, 0x266b0001, 0x256c0001, 0x246d0001, + 0x236e0001, 0x226f0001, 0x21700001, 0x20710001, 0x06720001, + 0x05730001, 0x04740001, 0x03750001, 0x02760001, 0x01770001, + 0x00780001, 0x00790001, 0x007a0001, 0x007b0001, 0x007c0001, + 0x007d0001, 0x007e0001, 0x007f0001, 0x3800001e, 0x3801001e, + 0x3802001e, 0x3803001e, 0x3804001e, 0x3805001e, 0x3806001e, + 0x3807001e, 0x3808001e, 0x3c09001e, 0x3e0a001e, 0x400b001e, + 0x440c001e, 0x480d001e, 0x4c0e001e, 0x500f001e, 0x5210001e, + 0x5611001e, 0x5a12001e, 0x5e13001e, 0x6014001e, 0x6015001e, + 0x6016001e, 0x6217001e, 0x6218001e, 0x6219001e, 0x621a001e, + 0x621b001e, 0x621c001e, 0x621d001e, 0x621e001e, 0x621f001e +}; + +static const struct rtwn_bb_prog rtl8192ce_bb_prog_2t = { + nitems(rtl8192ce_bb_regs), + rtl8192ce_bb_regs, + rtl8192ce_bb_vals_2t, + nitems(rtl8192ce_agc_vals), + rtl8192ce_agc_vals +}; + +static const struct rtwn_bb_prog rtl8192ce_bb_prog_1t = { + nitems(rtl8192ce_bb_regs), + rtl8192ce_bb_regs, + rtl8192ce_bb_vals_1t, + nitems(rtl8192ce_agc_vals), + rtl8192ce_agc_vals +}; + +/* + * RTL8188CU. + */ +static const uint32_t rtl8192cu_bb_vals[] = { + 0x0011800d, 0x00ffdb83, 0x80040002, 0x00000003, 0x0000fc00, + 0x0000000a, 0x10005388, 0x020c3d10, 0x02200385, 0x00000000, + 0x01000100, 0x00390004, 0x01000100, 0x00390004, 0x27272727, + 0x27272727, 0x27272727, 0x27272727, 0x00010000, 0x00010000, + 0x27272727, 0x27272727, 0x00000000, 0x00000000, 0x569a569a, + 0x0c1b25a4, 0x66e60230, 0x061f0130, 0x27272727, 0x2b2b2b27, + 0x07000700, 0x22184000, 0x08080808, 0x00000000, 0xc0083070, + 0x000004d5, 0x00000000, 0xcc0000c0, 0x00000800, 0xfffffffe, + 0x40302010, 0x00706050, 0x00000000, 0x00000023, 0x00000000, + 0x81121313, 0x00d047c8, 0x80ff000c, 0x8c838300, 0x2e68120f, + 0x9500bb78, 0x11144028, 0x00881117, 0x89140f00, 0x1a1b0000, + 0x090e1317, 0x00000204, 0x00d30000, 0x101fbf00, 0x00000007, + 0x48071d40, 0x03a05633, 0x000000e4, 0x6c6c6c6c, 0x08800000, + 0x40000100, 0x08800000, 0x40000100, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x69e9ac44, 0x469652cf, 0x49795994, + 0x0a97971c, 0x1f7c403f, 0x000100b7, 0xec020107, 0x007f037f, + 0x6954341e, 0x43bc0094, 0x6954341e, 0x433c0094, 0x00000000, + 0x5116848b, 0x47c00bff, 0x00000036, 0x2c7f000d, 0x0186115b, + 0x0000001f, 0x00b99612, 0x40000100, 0x20f60000, 0x40000100, + 0x20200000, 0x00121820, 0x00000000, 0x00121820, 0x00007f7f, + 0x00000000, 0x00000080, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x28000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x64b22427, + 0x00766932, 0x00222222, 0x00000000, 0x37644302, 0x2f97d40c, + 0x00080740, 0x00020403, 0x0000907f, 0x20010201, 0xa0633333, + 0x3333bc43, 0x7a8f5b6b, 0xcc979975, 0x00000000, 0x80608000, + 0x00000000, 0x00027293, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x6437140a, 0x00000000, 0x00000000, 0x30032064, + 0x4653de68, 0x04518a3c, 0x00002101, 0x2a201c16, 0x1812362e, + 0x322c2220, 0x000e3c24, 0x2a2a2a2a, 0x2a2a2a2a, 0x03902a2a, + 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x00000000, + 0x1000dc1f, 0x10008c1f, 0x02140102, 0x681604c2, 0x01007c00, + 0x01004800, 0xfb000000, 0x000028d1, 0x1000dc1f, 0x10008c1f, + 0x02140102, 0x28160d05, 0x00000010, 0x001b25a4, 0x63db25a4, + 0x63db25a4, 0x0c1b25a4, 0x0c1b25a4, 0x0c1b25a4, 0x0c1b25a4, + 0x63db25a4, 0x0c1b25a4, 0x63db25a4, 0x63db25a4, 0x63db25a4, + 0x63db25a4, 0x001b25a4, 0x001b25a4, 0x6fdb25a4, 0x00000003, + 0x00000000, 0x00000300 +}; + +static const struct rtwn_bb_prog rtl8192cu_bb_prog = { + nitems(rtl8192ce_bb_regs), + rtl8192ce_bb_regs, + rtl8192cu_bb_vals, + nitems(rtl8192ce_agc_vals), + rtl8192ce_agc_vals +}; + +/* + * RTL8188CE-VAU. + */ +static const uint32_t rtl8188ce_bb_vals[] = { + 0x0011800d, 0x00ffdb83, 0x80040000, 0x00000001, 0x0000fc00, + 0x0000000a, 0x10005388, 0x020c3d10, 0x02200385, 0x00000000, + 0x01000100, 0x00390004, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00010000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x569a569a, + 0x001b25a4, 0x66e60230, 0x061f0130, 0x00000000, 0x32323200, + 0x07000700, 0x22004000, 0x00000808, 0x00000000, 0xc0083070, + 0x000004d5, 0x00000000, 0xccc000c0, 0x00000800, 0xfffffffe, + 0x40302010, 0x00706050, 0x00000000, 0x00000023, 0x00000000, + 0x81121111, 0x00d047c8, 0x80ff000c, 0x8c838300, 0x2e68120f, + 0x9500bb78, 0x11144028, 0x00881117, 0x89140f00, 0x1a1b0000, + 0x090e1317, 0x00000204, 0x00d30000, 0x101fbf00, 0x00000007, + 0x48071d40, 0x03a05611, 0x000000e4, 0x6c6c6c6c, 0x08800000, + 0x40000100, 0x08800000, 0x40000100, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x69e9ac44, 0x469652cf, 0x49795994, + 0x0a97971c, 0x1f7c403f, 0x000100b7, 0xec020107, 0x007f037f, + 0x6954341e, 0x43bc0094, 0x6954341e, 0x433c0094, 0x00000000, + 0x5116848b, 0x47c00bff, 0x00000036, 0x2c7f000d, 0x018610db, + 0x0000001f, 0x00b91612, 0x40000100, 0x20f60000, 0x40000100, + 0x20200000, 0x00121820, 0x00000000, 0x00121820, 0x00007f7f, + 0x00000000, 0x00000080, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x28000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x64b22427, + 0x00766932, 0x00222222, 0x00000000, 0x37644302, 0x2f97d40c, + 0x00080740, 0x00020401, 0x0000907f, 0x20010201, 0xa0633333, + 0x3333bc43, 0x7a8f5b6b, 0xcc979975, 0x00000000, 0x80608000, + 0x00000000, 0x00027293, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x6437140a, 0x00000000, 0x00000000, 0x30032064, + 0x4653de68, 0x04518a3c, 0x00002101, 0x2a201c16, 0x1812362e, + 0x322c2220, 0x000e3c24, 0x2a2a2a2a, 0x2a2a2a2a, 0x03902a2a, + 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x00000000, + 0x1000dc1f, 0x10008c1f, 0x02140102, 0x681604c2, 0x01007c00, + 0x01004800, 0xfb000000, 0x000028d1, 0x1000dc1f, 0x10008c1f, + 0x02140102, 0x28160d05, 0x00000008, 0x001b25a4, 0x631b25a0, + 0x631b25a0, 0x081b25a0, 0x081b25a0, 0x081b25a0, 0x081b25a0, + 0x631b25a0, 0x081b25a0, 0x631b25a0, 0x631b25a0, 0x631b25a0, + 0x631b25a0, 0x001b25a0, 0x001b25a0, 0x6b1b25a0, 0x00000003, + 0x00000000, 0x00000300 +}; + +static const uint32_t rtl8188ce_agc_vals[] = { + 0x7b000001, 0x7b010001, 0x7b020001, 0x7b030001, 0x7b040001, + 0x7b050001, 0x7a060001, 0x79070001, 0x78080001, 0x77090001, + 0x760a0001, 0x750b0001, 0x740c0001, 0x730d0001, 0x720e0001, + 0x710f0001, 0x70100001, 0x6f110001, 0x6e120001, 0x6d130001, + 0x6c140001, 0x6b150001, 0x6a160001, 0x69170001, 0x68180001, + 0x67190001, 0x661a0001, 0x651b0001, 0x641c0001, 0x631d0001, + 0x621e0001, 0x611f0001, 0x60200001, 0x49210001, 0x48220001, + 0x47230001, 0x46240001, 0x45250001, 0x44260001, 0x43270001, + 0x42280001, 0x41290001, 0x402a0001, 0x262b0001, 0x252c0001, + 0x242d0001, 0x232e0001, 0x222f0001, 0x21300001, 0x20310001, + 0x06320001, 0x05330001, 0x04340001, 0x03350001, 0x02360001, + 0x01370001, 0x00380001, 0x00390001, 0x003a0001, 0x003b0001, + 0x003c0001, 0x003d0001, 0x003e0001, 0x003f0001, 0x7b400001, + 0x7b410001, 0x7b420001, 0x7b430001, 0x7b440001, 0x7b450001, + 0x7a460001, 0x79470001, 0x78480001, 0x77490001, 0x764a0001, + 0x754b0001, 0x744c0001, 0x734d0001, 0x724e0001, 0x714f0001, + 0x70500001, 0x6f510001, 0x6e520001, 0x6d530001, 0x6c540001, + 0x6b550001, 0x6a560001, 0x69570001, 0x68580001, 0x67590001, + 0x665a0001, 0x655b0001, 0x645c0001, 0x635d0001, 0x625e0001, + 0x615f0001, 0x60600001, 0x49610001, 0x48620001, 0x47630001, + 0x46640001, 0x45650001, 0x44660001, 0x43670001, 0x42680001, + 0x41690001, 0x406a0001, 0x266b0001, 0x256c0001, 0x246d0001, + 0x236e0001, 0x226f0001, 0x21700001, 0x20710001, 0x06720001, + 0x05730001, 0x04740001, 0x03750001, 0x02760001, 0x01770001, + 0x00780001, 0x00790001, 0x007a0001, 0x007b0001, 0x007c0001, + 0x007d0001, 0x007e0001, 0x007f0001, 0x3800001e, 0x3801001e, + 0x3802001e, 0x3803001e, 0x3804001e, 0x3805001e, 0x3806001e, + 0x3807001e, 0x3808001e, 0x3c09001e, 0x3e0a001e, 0x400b001e, + 0x440c001e, 0x480d001e, 0x4c0e001e, 0x500f001e, 0x5210001e, + 0x5611001e, 0x5a12001e, 0x5e13001e, 0x6014001e, 0x6015001e, + 0x6016001e, 0x6217001e, 0x6218001e, 0x6219001e, 0x621a001e, + 0x621b001e, 0x621c001e, 0x621d001e, 0x621e001e, 0x621f001e +}; + +static const struct rtwn_bb_prog rtl8188ce_bb_prog = { + nitems(rtl8192ce_bb_regs), + rtl8192ce_bb_regs, + rtl8188ce_bb_vals, + nitems(rtl8188ce_agc_vals), + rtl8188ce_agc_vals +}; + +static const uint32_t rtl8188cu_bb_vals[] = { + 0x0011800d, 0x00ffdb83, 0x80040000, 0x00000001, 0x0000fc00, + 0x0000000a, 0x10005388, 0x020c3d10, 0x02200385, 0x00000000, + 0x01000100, 0x00390004, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00010000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x569a569a, + 0x001b25a4, 0x66e60230, 0x061f0130, 0x00000000, 0x32323200, + 0x07000700, 0x22004000, 0x00000808, 0x00000000, 0xc0083070, + 0x000004d5, 0x00000000, 0xccc000c0, 0x00000800, 0xfffffffe, + 0x40302010, 0x00706050, 0x00000000, 0x00000023, 0x00000000, + 0x81121111, 0x00d047c8, 0x80ff000c, 0x8c838300, 0x2e68120f, + 0x9500bb78, 0x11144028, 0x00881117, 0x89140f00, 0x1a1b0000, + 0x090e1317, 0x00000204, 0x00d30000, 0x101fbf00, 0x00000007, + 0x48071d40, 0x03a05611, 0x000000e4, 0x6c6c6c6c, 0x08800000, + 0x40000100, 0x08800000, 0x40000100, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x69e9ac44, 0x469652cf, 0x49795994, + 0x0a97971c, 0x1f7c403f, 0x000100b7, 0xec020107, 0x007f037f, + 0x6954341e, 0x43bc0094, 0x6954341e, 0x433c0094, 0x00000000, + 0x5116848b, 0x47c00bff, 0x00000036, 0x2c7f000d, 0x018610db, + 0x0000001f, 0x00b91612, 0x40000100, 0x20f60000, 0x40000100, + 0x20200000, 0x00121820, 0x00000000, 0x00121820, 0x00007f7f, + 0x00000000, 0x00000080, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x28000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x64b22427, + 0x00766932, 0x00222222, 0x00000000, 0x37644302, 0x2f97d40c, + 0x00080740, 0x00020401, 0x0000907f, 0x20010201, 0xa0633333, + 0x3333bc43, 0x7a8f5b6b, 0xcc979975, 0x00000000, 0x80608000, + 0x00000000, 0x00027293, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x6437140a, 0x00000000, 0x00000000, 0x30032064, + 0x4653de68, 0x04518a3c, 0x00002101, 0x2a201c16, 0x1812362e, + 0x322c2220, 0x000e3c24, 0x2a2a2a2a, 0x2a2a2a2a, 0x03902a2a, + 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x00000000, + 0x1000dc1f, 0x10008c1f, 0x02140102, 0x681604c2, 0x01007c00, + 0x01004800, 0xfb000000, 0x000028d1, 0x1000dc1f, 0x10008c1f, + 0x02140102, 0x28160d05, 0x00000008, 0x001b25a4, 0x631b25a0, + 0x631b25a0, 0x081b25a0, 0x081b25a0, 0x081b25a0, 0x081b25a0, + 0x631b25a0, 0x081b25a0, 0x631b25a0, 0x631b25a0, 0x631b25a0, + 0x631b25a0, 0x001b25a0, 0x001b25a0, 0x6b1b25a0, 0x00000003, + 0x00000000, 0x00000300 +}; + +static const struct rtwn_bb_prog rtl8188cu_bb_prog = { + nitems(rtl8192ce_bb_regs), + rtl8192ce_bb_regs, + rtl8188cu_bb_vals, + nitems(rtl8188ce_agc_vals), + rtl8188ce_agc_vals +}; + +/* + * RTL8188RU. + */ +static const uint16_t rtl8188ru_bb_regs[] = { + 0x024, 0x028, 0x040, 0x800, 0x804, 0x808, 0x80c, 0x810, 0x814, + 0x818, 0x81c, 0x820, 0x824, 0x828, 0x82c, 0x830, 0x834, 0x838, + 0x83c, 0x840, 0x844, 0x848, 0x84c, 0x850, 0x854, 0x858, 0x85c, + 0x860, 0x864, 0x868, 0x86c, 0x870, 0x874, 0x878, 0x87c, 0x880, + 0x884, 0x888, 0x88c, 0x890, 0x894, 0x898, 0x89c, 0x900, 0x904, + 0x908, 0x90c, 0xa00, 0xa04, 0xa08, 0xa0c, 0xa10, 0xa14, 0xa18, + 0xa1c, 0xa20, 0xa24, 0xa28, 0xa2c, 0xa70, 0xa74, 0xc00, 0xc04, + 0xc08, 0xc0c, 0xc10, 0xc14, 0xc18, 0xc1c, 0xc20, 0xc24, 0xc28, + 0xc2c, 0xc30, 0xc34, 0xc38, 0xc3c, 0xc40, 0xc44, 0xc48, 0xc4c, + 0xc50, 0xc54, 0xc58, 0xc5c, 0xc60, 0xc64, 0xc68, 0xc6c, 0xc70, + 0xc74, 0xc78, 0xc7c, 0xc80, 0xc84, 0xc88, 0xc8c, 0xc90, 0xc94, + 0xc98, 0xc9c, 0xca0, 0xca4, 0xca8, 0xcac, 0xcb0, 0xcb4, 0xcb8, + 0xcbc, 0xcc0, 0xcc4, 0xcc8, 0xccc, 0xcd0, 0xcd4, 0xcd8, 0xcdc, + 0xce0, 0xce4, 0xce8, 0xcec, 0xd00, 0xd04, 0xd08, 0xd0c, 0xd10, + 0xd14, 0xd18, 0xd2c, 0xd30, 0xd34, 0xd38, 0xd3c, 0xd40, 0xd44, + 0xd48, 0xd4c, 0xd50, 0xd54, 0xd58, 0xd5c, 0xd60, 0xd64, 0xd68, + 0xd6c, 0xd70, 0xd74, 0xd78, 0xe00, 0xe04, 0xe08, 0xe10, 0xe14, + 0xe18, 0xe1c, 0xe28, 0xe30, 0xe34, 0xe38, 0xe3c, 0xe40, 0xe44, + 0xe48, 0xe4c, 0xe50, 0xe54, 0xe58, 0xe5c, 0xe60, 0xe68, 0xe6c, + 0xe70, 0xe74, 0xe78, 0xe7c, 0xe80, 0xe84, 0xe88, 0xe8c, 0xed0, + 0xed4, 0xed8, 0xedc, 0xee0, 0xeec, 0xee8, 0xf14, 0xf4c, 0xf00 +}; + +static const uint32_t rtl8188ru_bb_vals[] = { + 0x0011800d, 0x00ffdb83, 0x000c0004, 0x80040000, 0x00000001, + 0x0000fc00, 0x0000000a, 0x10005388, 0x020c3d10, 0x02200385, + 0x00000000, 0x01000100, 0x00390204, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00010000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x569a569a, 0x001b25a4, 0x66e60230, 0x061f0130, 0x00000000, + 0x32323200, 0x03000300, 0x22004000, 0x00000808, 0x00ffc3f1, + 0xc0083070, 0x000004d5, 0x00000000, 0xccc000c0, 0x00000800, + 0xfffffffe, 0x40302010, 0x00706050, 0x00000000, 0x00000023, + 0x00000000, 0x81121111, 0x00d047c8, 0x80ff000c, 0x8c838300, + 0x2e68120f, 0x9500bb78, 0x11144028, 0x00881117, 0x89140f00, + 0x15160000, 0x070b0f12, 0x00000104, 0x00d30000, 0x101fbf00, + 0x00000007, 0x48071d40, 0x03a05611, 0x000000e4, 0x6c6c6c6c, + 0x08800000, 0x40000100, 0x08800000, 0x40000100, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x69e9ac44, 0x469652cf, + 0x49795994, 0x0a97971c, 0x1f7c403f, 0x000100b7, 0xec020107, + 0x007f037f, 0x6954342e, 0x43bc0094, 0x6954342f, 0x433c0094, + 0x00000000, 0x5116848b, 0x47c00bff, 0x00000036, 0x2c56000d, + 0x018610db, 0x0000001f, 0x00b91612, 0x24000090, 0x20f60000, + 0x24000090, 0x20200000, 0x00121820, 0x00000000, 0x00121820, + 0x00007f7f, 0x00000000, 0x00000080, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x28000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x64b22427, 0x00766932, 0x00222222, 0x00000000, 0x37644302, + 0x2f97d40c, 0x00080740, 0x00020401, 0x0000907f, 0x20010201, + 0xa0633333, 0x3333bc43, 0x7a8f5b6b, 0xcc979975, 0x00000000, + 0x80608000, 0x00000000, 0x00027293, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x6437140a, 0x00000000, 0x00000000, + 0x30032064, 0x4653de68, 0x04518a3c, 0x00002101, 0x2a201c16, + 0x1812362e, 0x322c2220, 0x000e3c24, 0x2a2a2a2a, 0x2a2a2a2a, + 0x03902a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, + 0x00000000, 0x1000dc1f, 0x10008c1f, 0x02140102, 0x681604c2, + 0x01007c00, 0x01004800, 0xfb000000, 0x000028d1, 0x1000dc1f, + 0x10008c1f, 0x02140102, 0x28160d05, 0x00000010, 0x001b25a4, + 0x631b25a0, 0x631b25a0, 0x081b25a0, 0x081b25a0, 0x081b25a0, + 0x081b25a0, 0x631b25a0, 0x081b25a0, 0x631b25a0, 0x631b25a0, + 0x631b25a0, 0x631b25a0, 0x001b25a0, 0x001b25a0, 0x6b1b25a0, + 0x31555448, 0x00000003, 0x00000000, 0x00000300 +}; + +static const uint32_t rtl8188ru_agc_vals[] = { + 0x7b000001, 0x7b010001, 0x7b020001, 0x7b030001, 0x7b040001, + 0x7b050001, 0x7b060001, 0x7b070001, 0x7b080001, 0x7a090001, + 0x790a0001, 0x780b0001, 0x770c0001, 0x760d0001, 0x750e0001, + 0x740f0001, 0x73100001, 0x72110001, 0x71120001, 0x70130001, + 0x6f140001, 0x6e150001, 0x6d160001, 0x6c170001, 0x6b180001, + 0x6a190001, 0x691a0001, 0x681b0001, 0x671c0001, 0x661d0001, + 0x651e0001, 0x641f0001, 0x63200001, 0x62210001, 0x61220001, + 0x60230001, 0x46240001, 0x45250001, 0x44260001, 0x43270001, + 0x42280001, 0x41290001, 0x402a0001, 0x262b0001, 0x252c0001, + 0x242d0001, 0x232e0001, 0x222f0001, 0x21300001, 0x20310001, + 0x06320001, 0x05330001, 0x04340001, 0x03350001, 0x02360001, + 0x01370001, 0x00380001, 0x00390001, 0x003a0001, 0x003b0001, + 0x003c0001, 0x003d0001, 0x003e0001, 0x003f0001, 0x7b400001, + 0x7b410001, 0x7b420001, 0x7b430001, 0x7b440001, 0x7b450001, + 0x7b460001, 0x7b470001, 0x7b480001, 0x7a490001, 0x794a0001, + 0x784b0001, 0x774c0001, 0x764d0001, 0x754e0001, 0x744f0001, + 0x73500001, 0x72510001, 0x71520001, 0x70530001, 0x6f540001, + 0x6e550001, 0x6d560001, 0x6c570001, 0x6b580001, 0x6a590001, + 0x695a0001, 0x685b0001, 0x675c0001, 0x665d0001, 0x655e0001, + 0x645f0001, 0x63600001, 0x62610001, 0x61620001, 0x60630001, + 0x46640001, 0x45650001, 0x44660001, 0x43670001, 0x42680001, + 0x41690001, 0x406a0001, 0x266b0001, 0x256c0001, 0x246d0001, + 0x236e0001, 0x226f0001, 0x21700001, 0x20710001, 0x06720001, + 0x05730001, 0x04740001, 0x03750001, 0x02760001, 0x01770001, + 0x00780001, 0x00790001, 0x007a0001, 0x007b0001, 0x007c0001, + 0x007d0001, 0x007e0001, 0x007f0001, 0x3800001e, 0x3801001e, + 0x3802001e, 0x3803001e, 0x3804001e, 0x3805001e, 0x3806001e, + 0x3807001e, 0x3808001e, 0x3c09001e, 0x3e0a001e, 0x400b001e, + 0x440c001e, 0x480d001e, 0x4c0e001e, 0x500f001e, 0x5210001e, + 0x5611001e, 0x5a12001e, 0x5e13001e, 0x6014001e, 0x6015001e, + 0x6016001e, 0x6217001e, 0x6218001e, 0x6219001e, 0x621a001e, + 0x621b001e, 0x621c001e, 0x621d001e, 0x621e001e, 0x621f001e +}; + +static const struct rtwn_bb_prog rtl8188ru_bb_prog = { + nitems(rtl8188ru_bb_regs), + rtl8188ru_bb_regs, + rtl8188ru_bb_vals, + nitems(rtl8188ru_agc_vals), + rtl8188ru_agc_vals +}; + +/* + * RF initialization values. + */ +struct rtwn_rf_prog { + int count; + const uint8_t *regs; + const uint32_t *vals; +}; + +/* + * RTL8192CU and RTL8192CE-VAU. + */ +static const uint8_t rtl8192ce_rf1_regs[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x0f, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, + 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2a, 0x2b, + 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, + 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, + 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, + 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, + 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, + 0x2c, 0x2a, 0x10, 0x11, 0x10, 0x11, 0x10, 0x11, 0x10, 0x11, 0x10, + 0x11, 0x10, 0x11, 0x10, 0x11, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, + 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x00, + 0x18, 0xfe, 0xfe, 0x1f, 0xfe, 0xfe, 0x1e, 0x1f, 0x00 +}; + +static const uint32_t rtl8192ce_rf1_vals[] = { + 0x30159, 0x31284, 0x98000, 0x18c63, 0x210e7, 0x2044f, 0x1adb1, + 0x54867, 0x8992e, 0x0e52c, 0x39ce7, 0x00451, 0x00000, 0x10255, + 0x60a00, 0xfc378, 0xa1250, 0x4445f, 0x80001, 0x0b614, 0x6c000, + 0x00000, 0x01558, 0x00060, 0x00483, 0x4f000, 0xec7d9, 0x577c0, + 0x04783, 0x00001, 0x21334, 0x00000, 0x00054, 0x00001, 0x00808, + 0x53333, 0x0000c, 0x00002, 0x00808, 0x5b333, 0x0000d, 0x00003, + 0x00808, 0x63333, 0x0000d, 0x00004, 0x00808, 0x6b333, 0x0000d, + 0x00005, 0x00808, 0x73333, 0x0000d, 0x00006, 0x00709, 0x5b333, + 0x0000d, 0x00007, 0x00709, 0x63333, 0x0000d, 0x00008, 0x0060a, + 0x4b333, 0x0000d, 0x00009, 0x0060a, 0x53333, 0x0000d, 0x0000a, + 0x0060a, 0x5b333, 0x0000d, 0x0000b, 0x0060a, 0x63333, 0x0000d, + 0x0000c, 0x0060a, 0x6b333, 0x0000d, 0x0000d, 0x0060a, 0x73333, + 0x0000d, 0x0000e, 0x0050b, 0x66666, 0x0001a, 0xe0000, 0x4000f, + 0xe31fc, 0x6000f, 0xff9f8, 0x2000f, 0x203f9, 0x3000f, 0xff500, + 0x00000, 0x00000, 0x8000f, 0x3f100, 0x9000f, 0x23100, 0x32000, + 0x71000, 0xb0000, 0xfc000, 0x287af, 0x244b7, 0x204ab, 0x1c49f, + 0x18493, 0x14297, 0x10295, 0x0c298, 0x0819c, 0x040a8, 0x0001c, + 0x1944c, 0x59444, 0x9944c, 0xd9444, 0x0f424, 0x4f424, 0x8f424, + 0xcf424, 0xe0330, 0xa0330, 0x60330, 0x20330, 0x10159, 0x0f401, + 0x00000, 0x00000, 0x80003, 0x00000, 0x00000, 0x44457, 0x80000, + 0x30159 +}; + +static const uint8_t rtl8192ce_rf2_regs[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x0f, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, + 0x15, 0x15, 0x16, 0x16, 0x16, 0x16 +}; + +static const uint32_t rtl8192ce_rf2_vals[] = { + 0x30159, 0x31284, 0x98000, 0x18c63, 0x210e7, 0x2044f, 0x1adb1, + 0x54867, 0x8992e, 0x0e52c, 0x39ce7, 0x00451, 0x32000, 0x71000, + 0xb0000, 0xfc000, 0x287af, 0x244b7, 0x204ab, 0x1c49f, 0x18493, + 0x14297, 0x10295, 0x0c298, 0x0819c, 0x040a8, 0x0001c, 0x1944c, + 0x59444, 0x9944c, 0xd9444, 0x0f424, 0x4f424, 0x8f424, 0xcf424, + 0xe0330, 0xa0330, 0x60330, 0x20330 +}; + +static const struct rtwn_rf_prog rtl8192ce_rf_prog[] = { + { + nitems(rtl8192ce_rf1_regs), + rtl8192ce_rf1_regs, + rtl8192ce_rf1_vals + }, + { + nitems(rtl8192ce_rf2_regs), + rtl8192ce_rf2_regs, + rtl8192ce_rf2_vals + } +}; + +/* + * RTL8188CE-VAU. + */ +static const uint32_t rtl8188ce_rf_vals[] = { + 0x30159, 0x31284, 0x98000, 0x18c63, 0x210e7, 0x2044f, 0x1adb1, + 0x54867, 0x8992e, 0x0e52c, 0x39ce7, 0x00451, 0x00000, 0x10255, + 0x60a00, 0xfc378, 0xa1250, 0x4445f, 0x80001, 0x0b614, 0x6c000, + 0x00000, 0x01558, 0x00060, 0x00483, 0x4f200, 0xec7d9, 0x577c0, + 0x04783, 0x00001, 0x21334, 0x00000, 0x00054, 0x00001, 0x00808, + 0x53333, 0x0000c, 0x00002, 0x00808, 0x5b333, 0x0000d, 0x00003, + 0x00808, 0x63333, 0x0000d, 0x00004, 0x00808, 0x6b333, 0x0000d, + 0x00005, 0x00808, 0x73333, 0x0000d, 0x00006, 0x00709, 0x5b333, + 0x0000d, 0x00007, 0x00709, 0x63333, 0x0000d, 0x00008, 0x0060a, + 0x4b333, 0x0000d, 0x00009, 0x0060a, 0x53333, 0x0000d, 0x0000a, + 0x0060a, 0x5b333, 0x0000d, 0x0000b, 0x0060a, 0x63333, 0x0000d, + 0x0000c, 0x0060a, 0x6b333, 0x0000d, 0x0000d, 0x0060a, 0x73333, + 0x0000d, 0x0000e, 0x0050b, 0x66666, 0x0001a, 0xe0000, 0x4000f, + 0xe31fc, 0x6000f, 0xff9f8, 0x2000f, 0x203f9, 0x3000f, 0xff500, + 0x00000, 0x00000, 0x8000f, 0x3f100, 0x9000f, 0x23100, 0x32000, + 0x71000, 0xb0000, 0xfc000, 0x287b3, 0x244b7, 0x204ab, 0x1c49f, + 0x18493, 0x1429b, 0x10299, 0x0c29c, 0x081a0, 0x040ac, 0x00020, + 0x1944c, 0x59444, 0x9944c, 0xd9444, 0x0f424, 0x4f424, 0x8f424, + 0xcf424, 0xe0330, 0xa0330, 0x60330, 0x20330, 0x10159, 0x0f401, + 0x00000, 0x00000, 0x80003, 0x00000, 0x00000, 0x44457, 0x80000, + 0x30159 +}; + +static const struct rtwn_rf_prog rtl8188ce_rf_prog[] = { + { + nitems(rtl8192ce_rf1_regs), + rtl8192ce_rf1_regs, + rtl8188ce_rf_vals + } +}; + + +/* + * RTL8188CU. + */ +static const uint32_t rtl8188cu_rf_vals[] = { + 0x30159, 0x31284, 0x98000, 0x18c63, 0x210e7, 0x2044f, 0x1adb1, + 0x54867, 0x8992e, 0x0e52c, 0x39ce7, 0x00451, 0x00000, 0x10255, + 0x60a00, 0xfc378, 0xa1250, 0x4445f, 0x80001, 0x0b614, 0x6c000, + 0x00000, 0x01558, 0x00060, 0x00483, 0x4f000, 0xec7d9, 0x577c0, + 0x04783, 0x00001, 0x21334, 0x00000, 0x00054, 0x00001, 0x00808, + 0x53333, 0x0000c, 0x00002, 0x00808, 0x5b333, 0x0000d, 0x00003, + 0x00808, 0x63333, 0x0000d, 0x00004, 0x00808, 0x6b333, 0x0000d, + 0x00005, 0x00808, 0x73333, 0x0000d, 0x00006, 0x00709, 0x5b333, + 0x0000d, 0x00007, 0x00709, 0x63333, 0x0000d, 0x00008, 0x0060a, + 0x4b333, 0x0000d, 0x00009, 0x0060a, 0x53333, 0x0000d, 0x0000a, + 0x0060a, 0x5b333, 0x0000d, 0x0000b, 0x0060a, 0x63333, 0x0000d, + 0x0000c, 0x0060a, 0x6b333, 0x0000d, 0x0000d, 0x0060a, 0x73333, + 0x0000d, 0x0000e, 0x0050b, 0x66666, 0x0001a, 0xe0000, 0x4000f, + 0xe31fc, 0x6000f, 0xff9f8, 0x2000f, 0x203f9, 0x3000f, 0xff500, + 0x00000, 0x00000, 0x8000f, 0x3f100, 0x9000f, 0x23100, 0x32000, + 0x71000, 0xb0000, 0xfc000, 0x287b3, 0x244b7, 0x204ab, 0x1c49f, + 0x18493, 0x1429b, 0x10299, 0x0c29c, 0x081a0, 0x040ac, 0x00020, + 0x1944c, 0x59444, 0x9944c, 0xd9444, 0x0f405, 0x4f405, 0x8f405, + 0xcf405, 0xe0330, 0xa0330, 0x60330, 0x20330, 0x10159, 0x0f401, + 0x00000, 0x00000, 0x80003, 0x00000, 0x00000, 0x44457, 0x80000, + 0x30159 +}; + +static const struct rtwn_rf_prog rtl8188cu_rf_prog[] = { + { + nitems(rtl8192ce_rf1_regs), + rtl8192ce_rf1_regs, + rtl8188cu_rf_vals + } +}; + +/* + * RTL8188RU. + */ +static const uint32_t rtl8188ru_rf_vals[] = { + 0x30159, 0x31284, 0x98000, 0x18c63, 0x210e7, 0x2044f, 0x1adb0, + 0x54867, 0x8992e, 0x0e529, 0x39ce7, 0x00451, 0x00000, 0x00255, + 0x60a00, 0xfc378, 0xa1250, 0x4445f, 0x80001, 0x0b614, 0x6c000, + 0x0083c, 0x01558, 0x00060, 0x00483, 0x4f000, 0xec7d9, 0x977c0, + 0x04783, 0x00001, 0x21334, 0x00000, 0x00054, 0x00001, 0x00808, + 0x53333, 0x0000c, 0x00002, 0x00808, 0x5b333, 0x0000d, 0x00003, + 0x00808, 0x63333, 0x0000d, 0x00004, 0x00808, 0x6b333, 0x0000d, + 0x00005, 0x00808, 0x73333, 0x0000d, 0x00006, 0x00709, 0x5b333, + 0x0000d, 0x00007, 0x00709, 0x63333, 0x0000d, 0x00008, 0x0060a, + 0x4b333, 0x0000d, 0x00009, 0x0060a, 0x53333, 0x0000d, 0x0000a, + 0x0060a, 0x5b333, 0x0000d, 0x0000b, 0x0060a, 0x63333, 0x0000d, + 0x0000c, 0x0060a, 0x6b333, 0x0000d, 0x0000d, 0x0060a, 0x73333, + 0x0000d, 0x0000e, 0x0050b, 0x66666, 0x0001a, 0xe0000, 0x4000f, + 0xe31fc, 0x6000f, 0xff9f8, 0x2000f, 0x203f9, 0x3000f, 0xff500, + 0x00000, 0x00000, 0x8000f, 0x3f100, 0x9000f, 0x23100, 0xd8000, + 0x90000, 0x51000, 0x12000, 0x28fb4, 0x24fa8, 0x207a4, 0x1c798, + 0x183a4, 0x14398, 0x101a4, 0x0c198, 0x080a4, 0x04098, 0x00014, + 0x1944c, 0x59444, 0x9944c, 0xd9444, 0x0f405, 0x4f405, 0x8f405, + 0xcf405, 0xe0330, 0xa0330, 0x60330, 0x20330, 0x10159, 0x0f401, + 0x00000, 0x00000, 0x80003, 0x00000, 0x00000, 0x44457, 0x80000, + 0x30159 +}; + +static const struct rtwn_rf_prog rtl8188ru_rf_prog[] = { + { + nitems(rtl8192ce_rf1_regs), + rtl8192ce_rf1_regs, + rtl8188ru_rf_vals + } +}; + +struct rtwn_txpwr { + uint8_t pwr[3][28]; +}; + +/* + * Per RF chain/group/rate Tx gain values. + */ +static const struct rtwn_txpwr rtl8192cu_txagc[] = { + { { /* Chain 0. */ + { /* Group 0. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x0c, 0x0c, 0x0c, 0x0a, 0x08, 0x06, 0x04, 0x02, /* OFDM6~54. */ + 0x0e, 0x0d, 0x0c, 0x0a, 0x08, 0x06, 0x04, 0x02, /* MCS0~7. */ + 0x0e, 0x0d, 0x0c, 0x0a, 0x08, 0x06, 0x04, 0x02 /* MCS8~15. */ + }, + { /* Group 1. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ + }, + { /* Group 2. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x04, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x00, /* OFDM6~54. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ + } + } }, + { { /* Chain 1. */ + { /* Group 0. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ + }, + { /* Group 1. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ + }, + { /* Group 2. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x04, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x00, /* OFDM6~54. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ + } + } } +}; + +static const struct rtwn_txpwr rtl8188ru_txagc[] = { + { { /* Chain 0. */ + { /* Group 0. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x08, 0x08, 0x08, 0x06, 0x06, 0x04, 0x04, 0x00, /* OFDM6~54. */ + 0x08, 0x06, 0x06, 0x04, 0x04, 0x02, 0x02, 0x00, /* MCS0~7. */ + 0x08, 0x06, 0x06, 0x04, 0x04, 0x02, 0x02, 0x00 /* MCS8~15. */ + }, + { /* Group 1. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ + }, + { /* Group 2. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ + } + } } +}; + +#define RTWN_LOCK_INIT(_sc) \ + mtx_init(&(_sc)->sc_mtx, device_get_nameunit((_sc)->sc_dev), \ + MTX_NETWORK_LOCK, MTX_DEF) +#define RTWN_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) +#define RTWN_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED) +#define RTWN_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) +#define RTWN_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx) + From b6ac0e6565b7bbb903ab09d2f8ed1e2a25135133 Mon Sep 17 00:00:00 2001 From: Adrian Chadd Date: Thu, 31 Dec 2015 22:33:32 +0000 Subject: [PATCH 36/37] [rtwn] Add rtwn firmware and driver module. Submitted by: kevlo --- sys/modules/Makefile | 2 ++ sys/modules/rtwnfw/Makefile | 5 +++++ sys/modules/rtwnfw/Makefile.inc | 15 +++++++++++++++ sys/modules/rtwnfw/rtwnrtl8192cU/Makefile | 6 ++++++ sys/modules/rtwnfw/rtwnrtl8192cUB/Makefile | 6 ++++++ 5 files changed, 34 insertions(+) create mode 100644 sys/modules/rtwnfw/Makefile create mode 100644 sys/modules/rtwnfw/Makefile.inc create mode 100644 sys/modules/rtwnfw/rtwnrtl8192cU/Makefile create mode 100644 sys/modules/rtwnfw/rtwnrtl8192cUB/Makefile diff --git a/sys/modules/Makefile b/sys/modules/Makefile index 1b3b7eb3d2d9..0fad8aaceb5d 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -311,6 +311,8 @@ SUBDIR= \ re \ reiserfs \ rl \ + rtwn \ + rtwnfw \ ${_s3} \ ${_safe} \ ${_sbni} \ diff --git a/sys/modules/rtwnfw/Makefile b/sys/modules/rtwnfw/Makefile new file mode 100644 index 000000000000..7a679dfbfebb --- /dev/null +++ b/sys/modules/rtwnfw/Makefile @@ -0,0 +1,5 @@ +# $FreeBSD$ + +SUBDIR= rtwnrtl8192cU rtwnrtl8192cUB + +.include diff --git a/sys/modules/rtwnfw/Makefile.inc b/sys/modules/rtwnfw/Makefile.inc new file mode 100644 index 000000000000..ce5bcee3f531 --- /dev/null +++ b/sys/modules/rtwnfw/Makefile.inc @@ -0,0 +1,15 @@ +# $FreeBSD$ +# +# Common rules for building firmware. Note this gets auto-included +# by the subdir Makefile's as a consequence of included bsd.kmod.mk. + +_FIRM= ${IMG}.fw + +CLEANFILES+= ${_FIRM} + +FIRMWS= ${_FIRM}:${KMOD}:111 + +FIRMWARE_LICENSE= realtek + +${_FIRM}: ${.CURDIR}/../../../contrib/dev/rtwn/${_FIRM}.uu + uudecode -p $? > ${.TARGET} diff --git a/sys/modules/rtwnfw/rtwnrtl8192cU/Makefile b/sys/modules/rtwnfw/rtwnrtl8192cU/Makefile new file mode 100644 index 000000000000..643a30f5c95f --- /dev/null +++ b/sys/modules/rtwnfw/rtwnrtl8192cU/Makefile @@ -0,0 +1,6 @@ +# $FreeBSD$ + +KMOD= rtwn-rtl8192cfwU +IMG= rtwn-rtl8192cfwU + +.include diff --git a/sys/modules/rtwnfw/rtwnrtl8192cUB/Makefile b/sys/modules/rtwnfw/rtwnrtl8192cUB/Makefile new file mode 100644 index 000000000000..eb878d48c184 --- /dev/null +++ b/sys/modules/rtwnfw/rtwnrtl8192cUB/Makefile @@ -0,0 +1,6 @@ +# $FreeBSD$ + +KMOD= rtwn-rtl8192cfwU_B +IMG= rtwn-rtl8192cfwU_B + +.include From 2600131bd63b70eb0523a0cbfb034a92dddde963 Mon Sep 17 00:00:00 2001 From: Adrian Chadd Date: Thu, 31 Dec 2015 22:34:16 +0000 Subject: [PATCH 37/37] [rtwn] Add initial manpages for the rtwn driver. --- share/man/man4/Makefile | 2 + share/man/man4/rtwn.4 | 165 ++++++++++++++++++++++++++++++++++++++++ share/man/man4/rtwnfw.4 | 74 ++++++++++++++++++ 3 files changed, 241 insertions(+) create mode 100644 share/man/man4/rtwn.4 create mode 100644 share/man/man4/rtwnfw.4 diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile index 6cf392ac084e..d5050ac45a62 100644 --- a/share/man/man4/Makefile +++ b/share/man/man4/Makefile @@ -424,6 +424,8 @@ MAN= aac.4 \ rndtest.4 \ route.4 \ rp.4 \ + rtwn.4 \ + rtwnfw.4 \ rue.4 \ rum.4 \ run.4 \ diff --git a/share/man/man4/rtwn.4 b/share/man/man4/rtwn.4 new file mode 100644 index 000000000000..10258494f3ef --- /dev/null +++ b/share/man/man4/rtwn.4 @@ -0,0 +1,165 @@ +.\" $OpenBSD: rtwn.4,v 1.2 2015/07/09 11:28:53 stsp Exp $ +.\" +.\" Copyright (c) 2010 Damien Bergamini +.\" Copyright (c) 2015 Stefan Sperling +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.\" $FreeBSD$ +.\" +.Dd October 28, 2015 +.Dt RTWN 4 +.Os +.Sh NAME +.Nm rtwn +.Nd Realtek RTL8188CE PCIe IEEE 802.11b/g/n wireless network device +.Sh SYNOPSIS +To compile this driver into the kernel, +place the following lines in your +kernel configuration file: +.Bd -ragged -offset indent +.Cd "device rtwn" +.Cd "device rtwnfw" +.Cd "device wlan" +.Cd "device firmware" +.Ed +.Pp +Alternatively, to load the driver as a +module at boot time, place the following line in +.Xr loader.conf 5 : +.Bd -literal -offset indent +if_rtwn_load="YES" +.Ed +.Pp +After you have read the license in +.Pa /usr/share/doc/legal/realtek.LICENSE +you will want to add the following lines to +.Xr loader.conf 5 : +.Bd -literal -offset indent +legal.realtek.license_ack=1 +rtwn-rtl8192cfwU_load="YES" +rtwn-rtl8192cfwU_B_load="YES" +.Ed +.Sh DESCRIPTION +The +.Nm +driver supports PCIe wireless network devices based on the Realtek +RTL8188CE chipset. +.Pp +The RTL8188CE is a highly integrated 802.11n adapter that combines a MAC, +a 1T1R capable baseband and an RF in a single chip. +It operates in the 2GHz spectrum only. +.Pp +These are the modes the +.Nm +driver can operate in: +.Bl -tag -width "IBSS-masterXX" +.It BSS mode +Also known as +.Em infrastructure +mode, this is used when associating with an access point, through +which all traffic passes. +This mode is the default. +.It monitor mode +In this mode the driver is able to receive packets without +associating with an access point. +This disables the internal receive filter and enables the card to +capture packets from networks which it wouldn't normally have access to, +or to scan for access points. +.El +.Pp +The +.Nm +driver can be configured to use +Wired Equivalent Privacy (WEP) or +Wi-Fi Protected Access (WPA-PSK and WPA2-PSK). +WPA is the current encryption standard for wireless networks. +It is strongly recommended that WEP +not be used as the sole mechanism +to secure wireless communication, +due to serious weaknesses in it. +.Pp +The +.Nm +driver can be configured at runtime with +.Xr ifconfig 8 . +.Sh FILES +The driver needs at least version 1.0 of the following firmware files, +which are loaded when an interface is brought up: +.Pp +.Bl -tag -width Ds -offset indent -compact +.It Pa /boot/kernel/rtwn-rtl8192cfwU.ko +.It Pa /boot/kernel/rtwn-rtl8192cfwU_B.ko +.El +.Sh EXAMPLES +Join an existing BSS network (i.e., connect to an access point): +.Bd -literal -offset indent +ifconfig wlan create wlandev rtwn0 inet 192.168.0.20 \e + netmask 0xffffff00 +.Ed +.Pp +Join a specific BSS network with network name +.Dq Li my_net : +.Pp +.Dl "ifconfig wlan create wlandev rtwn0 ssid my_net up" +.Pp +Join a specific BSS network with 64-bit WEP encryption: +.Bd -literal -offset indent +ifconfig wlan create wlandev rtwn0 ssid my_net \e + wepmode on wepkey 0x1234567890 weptxkey 1 up +.Ed +.Sh DIAGNOSTICS +.Bl -diag +.It "could not read firmware %s" +For some reason, the driver was unable to read the microcode file from the +filesystem. +The file might be missing or corrupted. +.It "device timeout" +A frame dispatched to the hardware for transmission did not complete in time. +The driver will reset the hardware. +This should not happen. +.El +.Sh SEE ALSO +.Xr pci 4 , +.Xr rtwnfw 4 , +.Xr wlan 4 , +.Xr wlan_ccmp 4 , +.Xr wlan_tkip 4 , +.Xr wlan_wep 4 , +.Xr ifconfig 8 , +.Xr wpa_supplicant 8 +.Sh HISTORY +The +.Nm +driver first appeared in +.Ox 5.8 . +.Sh AUTHORS +The +.Nm +driver was written by +.An -nosplit +.An Stefan Sperling Aq Mt stsp@openbsd.org +and ported by +.An Kevin Lo Aq Mt kevlo@freebsd.org . +It was based on the +.Xr urtwn 4 +driver written by +.An Damien Bergamini Aq Mt damien.bergamini@free.fr . +.Sh CAVEATS +The +.Nm +driver does not support any of the 802.11n capabilities offered by the +adapters. +Additional work is required in +.Xr ieee80211 9 +before those features can be supported. diff --git a/share/man/man4/rtwnfw.4 b/share/man/man4/rtwnfw.4 new file mode 100644 index 000000000000..e4ab346874f3 --- /dev/null +++ b/share/man/man4/rtwnfw.4 @@ -0,0 +1,74 @@ +.\" Copyright (c) 2015 Kevin Lo +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd October 28, 2015 +.Dt RTWNFW 4 +.Os +.Sh NAME +.Nm rtwnfw +.Nd "Firmware Module for Realtek Wireless driver" +.Sh SYNOPSIS +To compile this module into the kernel, +place the following line in your +kernel configuration file: +.Bd -ragged -offset indent +.Cd "device rtwnfw" +.Ed +.Pp +This will include three firmware images inside the kernel. +If you want to pick only the firmware image for your network adapter choose one +of the following: +.Bd -ragged -offset indent +.Cd "device rtwn-rtl8192cfwU" +.Cd "device rtwn-rtl8192cfwU_B" +.Ed +.Pp +Alternatively, to load the driver as a +module at boot time, place the following line in +.Xr loader.conf 5 : +.Bd -literal -offset indent +rtwn-rtl8192cfwU_load="YES" +rtwn-rtl8192cfwU_B_load="YES" +.Ed +.Sh DESCRIPTION +This module provides access to firmware sets for the +Realtek RTL8188CE chip based PCIe adapters. +It may be +statically linked into the kernel, or loaded as a module. +.Pp +For the loaded firmware to be enabled for use the license at +.Pa /usr/share/doc/legal/realtek.LICENSE +must be agreed to by adding the following line to +.Xr loader.conf 5 : +.Pp +.Dl "legal.realtek.license_ack=1" +.Sh FILES +.Bl -tag -width ".Pa /usr/share/doc/legal/realtek.LICENSE" -compact +.It Pa /usr/share/doc/legal/realtek.LICENSE +.Nm +firmware license +.El +.Sh SEE ALSO +.Xr rtwn 4 , +.Xr firmware 9