diff options
author | sam <sam@FreeBSD.org> | 2008-12-20 01:29:19 +0000 |
---|---|---|
committer | sam <sam@FreeBSD.org> | 2008-12-20 01:29:19 +0000 |
commit | c3f1faeb23e27c2ffda030cf892c5df698734622 (patch) | |
tree | 0b964e87f3cbd93269e72d591d2eb44bc6ace51c /sys | |
parent | cd99ae6c06463359389c703ff069f25d28878ad7 (diff) | |
parent | 3fcef6d9c20b6c3577c741e4a0fe24807fd08a66 (diff) | |
download | FreeBSD-src-c3f1faeb23e27c2ffda030cf892c5df698734622.zip FreeBSD-src-c3f1faeb23e27c2ffda030cf892c5df698734622.tar.gz |
MFH @ 186335
Diffstat (limited to 'sys')
283 files changed, 6678 insertions, 5156 deletions
diff --git a/sys/amd64/amd64/exception.S b/sys/amd64/amd64/exception.S index fd0a7ca..80308a9 100644 --- a/sys/amd64/amd64/exception.S +++ b/sys/amd64/amd64/exception.S @@ -459,9 +459,9 @@ nmi_calltrap: */ movq %rsp,%rsi /* source stack pointer */ movq $TF_SIZE,%rcx - movq PCPU(RSP0),%rbx - subq %rcx,%rbx - movq %rbx,%rdi /* destination stack pointer */ + movq PCPU(RSP0),%rdx + subq %rcx,%rdx + movq %rdx,%rdi /* destination stack pointer */ shrq $3,%rcx /* trap frame size in long words */ cld @@ -470,7 +470,7 @@ nmi_calltrap: movl %ss,%eax pushq %rax /* tf_ss */ - pushq %rbx /* tf_rsp (on kernel stack) */ + pushq %rdx /* tf_rsp (on kernel stack) */ pushfq /* tf_rflags */ movl %cs,%eax pushq %rax /* tf_cs */ @@ -480,16 +480,20 @@ outofnmi: /* * At this point the processor has exited NMI mode and is running * with interrupts turned off on the normal kernel stack. - * We turn interrupts back on, and take the usual 'doreti' exit - * path. * * If a pending NMI gets recognized at or after this point, it - * will cause a kernel callchain to be traced. Since this path - * is only taken for NMI interrupts from user space, our `swapgs' - * state is correct for taking the doreti path. + * will cause a kernel callchain to be traced. + * + * We turn interrupts back on, and call the user callchain capture hook. */ + movq pmc_hook,%rax + orq %rax,%rax + jz nocallchain + movq PCPU(CURTHREAD),%rdi /* thread */ + movq $PMC_FN_USER_CALLCHAIN,%rsi /* command */ + movq %rsp,%rdx /* frame */ sti - jmp doreti + call *%rax nocallchain: #endif testl %ebx,%ebx diff --git a/sys/amd64/amd64/identcpu.c b/sys/amd64/amd64/identcpu.c index c63339d..f417e0f 100644 --- a/sys/amd64/amd64/identcpu.c +++ b/sys/amd64/amd64/identcpu.c @@ -322,15 +322,15 @@ printcpuinfo(void) "\003SVM" /* Secure Virtual Mode */ "\004ExtAPIC" /* Extended APIC register */ "\005CR8" /* CR8 in legacy mode */ - "\006<b5>" - "\007<b6>" - "\010<b7>" + "\006ABM" /* LZCNT instruction */ + "\007SSE4A" /* SSE4A */ + "\010MAS" /* Misaligned SSE mode */ "\011Prefetch" /* 3DNow! Prefetch/PrefetchW */ - "\012<b9>" - "\013<b10>" - "\014<b11>" - "\015<b12>" - "\016<b13>" + "\012OSVW" /* OS visible workaround */ + "\013IBS" /* Instruction based sampling */ + "\014SSE5" /* SSE5 */ + "\015SKINIT" /* SKINIT/STGI */ + "\016WDT" /* Watchdog timer */ "\017<b14>" "\020<b15>" "\021<b16>" diff --git a/sys/amd64/conf/DEFAULTS b/sys/amd64/conf/DEFAULTS index 3477caf..fac8dce 100644 --- a/sys/amd64/conf/DEFAULTS +++ b/sys/amd64/conf/DEFAULTS @@ -16,5 +16,5 @@ device io # I/O device device uart_ns8250 # Default partitioning schemes -options GEOM_BSD -options GEOM_MBR +options GEOM_PART_BSD +options GEOM_PART_MBR diff --git a/sys/amd64/include/elf.h b/sys/amd64/include/elf.h index 0a386be..a4c7f79 100644 --- a/sys/amd64/include/elf.h +++ b/sys/amd64/include/elf.h @@ -81,18 +81,6 @@ __ElfType(Auxinfo); #define AT_BASE 7 /* Interpreter's base address. */ #define AT_FLAGS 8 /* Flags (unused for i386). */ #define AT_ENTRY 9 /* Where interpreter should transfer control. */ - -/* - * The following non-standard values are used for passing information - * from John Polstra's testbed program to the dynamic linker. These - * are expected to go away soon. - * - * Unfortunately, these overlap the Linux non-standard values, so they - * must not be used in the same context. - */ -#define AT_BRK 10 /* Starting point for sbrk and brk. */ -#define AT_DEBUG 11 /* Debugging level. */ - /* * The following non-standard values are used in Linux ELF binaries. */ diff --git a/sys/amd64/include/specialreg.h b/sys/amd64/include/specialreg.h index cd9da86..674638c 100644 --- a/sys/amd64/include/specialreg.h +++ b/sys/amd64/include/specialreg.h @@ -150,7 +150,15 @@ #define AMDID2_SVM 0x00000004 #define AMDID2_EXT_APIC 0x00000008 #define AMDID2_CR8 0x00000010 +#define AMDID2_ABM 0x00000020 +#define AMDID2_SSE4A 0x00000040 +#define AMDID2_MAS 0x00000080 #define AMDID2_PREFETCH 0x00000100 +#define AMDID2_OSVW 0x00000200 +#define AMDID2_IBS 0x00000400 +#define AMDID2_SSE5 0x00000800 +#define AMDID2_SKINIT 0x00001000 +#define AMDID2_WDT 0x00002000 /* * CPUID instruction 1 eax info diff --git a/sys/amd64/linux32/linux32_sysvec.c b/sys/amd64/linux32/linux32_sysvec.c index 3acee30..aaa7458 100644 --- a/sys/amd64/linux32/linux32_sysvec.c +++ b/sys/amd64/linux32/linux32_sysvec.c @@ -254,8 +254,6 @@ elf_linux_fixup(register_t **stack_base, struct image_params *imgp) args = (Elf32_Auxargs *)imgp->auxargs; pos = base + (imgp->args->argc + imgp->args->envc + 2); - if (args->trace) - AUXARGS_ENTRY_32(pos, AT_DEBUG, 1); if (args->execfd != -1) AUXARGS_ENTRY_32(pos, AT_EXECFD, args->execfd); AUXARGS_ENTRY_32(pos, AT_PHDR, args->phdr); diff --git a/sys/arm/conf/DEFAULTS b/sys/arm/conf/DEFAULTS index 606e962..591a0a1 100644 --- a/sys/arm/conf/DEFAULTS +++ b/sys/arm/conf/DEFAULTS @@ -7,5 +7,5 @@ machine arm device mem -options GEOM_BSD -options GEOM_MBR +options GEOM_PART_BSD +options GEOM_PART_MBR diff --git a/sys/arm/conf/EP80219 b/sys/arm/conf/EP80219 index 8e2d6cb..8ce5b164 100644 --- a/sys/arm/conf/EP80219 +++ b/sys/arm/conf/EP80219 @@ -57,7 +57,6 @@ options SYSVSEM #SYSV-style semaphores options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions options KBD_INSTALL_CDEV # install a CDEV entry in /dev options GEOM_PART_GPT # GUID Partition Tables. -options GEOM_MBR # DOS/MBR partitioning options GEOM_LABEL # Providers labelization. options BOOTP diff --git a/sys/arm/include/elf.h b/sys/arm/include/elf.h index 353be7c..c516864 100644 --- a/sys/arm/include/elf.h +++ b/sys/arm/include/elf.h @@ -70,10 +70,6 @@ __ElfType(Auxinfo); #define AT_BASE 7 /* Interpreter's base address. */ #define AT_FLAGS 8 /* Flags (unused). */ #define AT_ENTRY 9 /* Where interpreter should transfer control. */ - -#define AT_BRK 10 /* Starting point for sbrk and brk. */ -#define AT_DEBUG 11 /* Debugging level. */ - #define AT_NOTELF 10 /* Program is not ELF ?? */ #define AT_UID 11 /* Real uid. */ #define AT_EUID 12 /* Effective uid. */ diff --git a/sys/boot/Makefile b/sys/boot/Makefile index 27cb7e3..7020ebb 100644 --- a/sys/boot/Makefile +++ b/sys/boot/Makefile @@ -12,7 +12,7 @@ SUBDIR+= ficl .endif # Build EFI library. -.if ${MACHINE_ARCH} == "amd64" || ${MACHINE_ARCH} == "i386" || ${MACHINE_ARCH} == "ia64" +.if ${MACHINE_ARCH} == "amd64" || ${MACHINE} == "i386" || ${MACHINE_ARCH} == "ia64" SUBDIR+= efi .endif diff --git a/sys/boot/i386/gptzfsboot/Makefile b/sys/boot/i386/gptzfsboot/Makefile index 930061f..467d312 100644 --- a/sys/boot/i386/gptzfsboot/Makefile +++ b/sys/boot/i386/gptzfsboot/Makefile @@ -60,7 +60,7 @@ gptzfsboot.bin: gptzfsboot.out objcopy -S -O binary gptzfsboot.out ${.TARGET} gptzfsboot.out: ${BTXCRT} zfsboot.o sio.o - ${LD} ${LDFLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} + ${LD} ${LDFLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBSTAND} zfsboot.o: ${.CURDIR}/../../zfs/zfsimpl.c diff --git a/sys/boot/i386/zfsboot/Makefile b/sys/boot/i386/zfsboot/Makefile index 41f1672..1653534 100644 --- a/sys/boot/i386/zfsboot/Makefile +++ b/sys/boot/i386/zfsboot/Makefile @@ -80,7 +80,7 @@ zfsboot.bin: zfsboot.out objcopy -S -O binary zfsboot.out ${.TARGET} zfsboot.out: ${BTXCRT} zfsboot.o sio.o - ${LD} ${LDFLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} + ${LD} ${LDFLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBSTAND} zfsboot.o: zfsboot.s diff --git a/sys/boot/powerpc/uboot/conf.c b/sys/boot/powerpc/uboot/conf.c index 8bc307a..5a9515a 100644 --- a/sys/boot/powerpc/uboot/conf.c +++ b/sys/boot/powerpc/uboot/conf.c @@ -94,8 +94,8 @@ struct netif_driver *netif_drivers[] = { */ struct file_format *file_formats[] = { - &uboot_elf, - NULL + &uboot_elf, + NULL }; /* @@ -104,6 +104,6 @@ struct file_format *file_formats[] = { extern struct console uboot_console; struct console *consoles[] = { - &uboot_console, - NULL + &uboot_console, + NULL }; diff --git a/sys/boot/uboot/common/main.c b/sys/boot/uboot/common/main.c index f7a0745..1ebb097 100644 --- a/sys/boot/uboot/common/main.c +++ b/sys/boot/uboot/common/main.c @@ -216,6 +216,7 @@ COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); static int command_reboot(int argc, char *argv[]) { + printf("Resetting...\n"); ub_reset(); diff --git a/sys/boot/uboot/lib/devicename.c b/sys/boot/uboot/lib/devicename.c index 3183ae1..5d91550 100644 --- a/sys/boot/uboot/lib/devicename.c +++ b/sys/boot/uboot/lib/devicename.c @@ -35,7 +35,8 @@ __FBSDID("$FreeBSD$"); #include "bootstrap.h" #include "libuboot.h" -static int uboot_parsedev(struct uboot_devdesc **dev, const char *devspec, const char **path); +static int uboot_parsedev(struct uboot_devdesc **dev, const char *devspec, + const char **path); /* * Point (dev) at an allocated device specifier for the device matching the @@ -178,11 +179,11 @@ uboot_parsedev(struct uboot_devdesc **dev, const char *devspec, } else { *dev = idev; } - return(0); + return (0); fail: free(idev); - return(err); + return (err); } @@ -191,7 +192,7 @@ uboot_fmtdev(void *vdev) { struct uboot_devdesc *dev = (struct uboot_devdesc *)vdev; char *cp; - static char buf[128]; /* XXX device length constant? */ + static char buf[128]; switch(dev->d_type) { case DEVT_NONE: @@ -220,12 +221,12 @@ uboot_fmtdev(void *vdev) int uboot_setcurrdev(struct env_var *ev, int flags, const void *value) { - struct uboot_devdesc *ncurr; - int rv; + struct uboot_devdesc *ncurr; + int rv; if ((rv = uboot_parsedev(&ncurr, value, NULL)) != 0) - return(rv); + return (rv); free(ncurr); env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); - return(0); + return (0); } diff --git a/sys/boot/zfs/zfsimpl.c b/sys/boot/zfs/zfsimpl.c index a6dc99e..e6695cf 100644 --- a/sys/boot/zfs/zfsimpl.c +++ b/sys/boot/zfs/zfsimpl.c @@ -873,17 +873,12 @@ dnode_read(spa_t *spa, const dnode_phys_t *dnode, off_t offset, void *buf, size_ int i, rc; /* - * We truncate the offset to 32bits, mainly so that I don't - * have to find a copy of __divdi3 to put into the bootstrap. - * I don't think the bootstrap needs to access anything bigger - * than 2G anyway. Note that block addresses are still 64bit - * so it doesn't affect the possible size of the media. - * We still use 64bit block numbers so that the bitshifts - * work correctly. Note: bsize may not be a power of two here. + * Note: bsize may not be a power of two here so we need to do an + * actual divide rather than a bitshift. */ while (buflen > 0) { - uint64_t bn = ((int) offset) / bsize; - int boff = ((int) offset) % bsize; + uint64_t bn = offset / bsize; + int boff = offset % bsize; int ibn; const blkptr_t *indbp; blkptr_t bp; diff --git a/sys/cam/cam_periph.c b/sys/cam/cam_periph.c index 26fbc6e..3abeed8 100644 --- a/sys/cam/cam_periph.c +++ b/sys/cam/cam_periph.c @@ -290,7 +290,7 @@ cam_periph_acquire(struct cam_periph *periph) } void -cam_periph_release(struct cam_periph *periph) +cam_periph_release_locked(struct cam_periph *periph) { if (periph == NULL) @@ -302,7 +302,21 @@ cam_periph_release(struct cam_periph *periph) camperiphfree(periph); } xpt_unlock_buses(); +} + +void +cam_periph_release(struct cam_periph *periph) +{ + struct cam_sim *sim; + if (periph == NULL) + return; + + sim = periph->sim; + mtx_assert(sim->mtx, MA_NOTOWNED); + mtx_lock(sim->mtx); + cam_periph_release_locked(periph); + mtx_unlock(sim->mtx); } int @@ -311,8 +325,6 @@ cam_periph_hold(struct cam_periph *periph, int priority) struct mtx *mtx; int error; - mtx_assert(periph->sim->mtx, MA_OWNED); - /* * Increment the reference count on the peripheral * while we wait for our lock attempt to succeed @@ -324,13 +336,14 @@ cam_periph_hold(struct cam_periph *periph, int priority) return (ENXIO); mtx = periph->sim->mtx; + mtx_assert(mtx, MA_OWNED); if (mtx == &Giant) mtx = NULL; while ((periph->flags & CAM_PERIPH_LOCKED) != 0) { periph->flags |= CAM_PERIPH_LOCK_WANTED; if ((error = msleep(periph, mtx, priority, "caplck", 0)) != 0) { - cam_periph_release(periph); + cam_periph_release_locked(periph); return (error); } } @@ -351,7 +364,7 @@ cam_periph_unhold(struct cam_periph *periph) wakeup(periph); } - cam_periph_release(periph); + cam_periph_release_locked(periph); } /* diff --git a/sys/cam/cam_periph.h b/sys/cam/cam_periph.h index e6073d9..8a45806 100644 --- a/sys/cam/cam_periph.h +++ b/sys/cam/cam_periph.h @@ -141,6 +141,7 @@ cam_status cam_periph_alloc(periph_ctor_t *periph_ctor, struct cam_periph *cam_periph_find(struct cam_path *path, char *name); cam_status cam_periph_acquire(struct cam_periph *periph); void cam_periph_release(struct cam_periph *periph); +void cam_periph_release_locked(struct cam_periph *periph); int cam_periph_hold(struct cam_periph *periph, int priority); void cam_periph_unhold(struct cam_periph *periph); void cam_periph_invalidate(struct cam_periph *periph); diff --git a/sys/cam/cam_sim.c b/sys/cam/cam_sim.c index cfc2044..adccfa8 100644 --- a/sys/cam/cam_sim.c +++ b/sys/cam/cam_sim.c @@ -84,6 +84,7 @@ cam_sim_alloc(sim_action_func sim_action, sim_poll_func sim_poll, sim->max_tagged_dev_openings = max_tagged_dev_transactions; sim->max_dev_openings = max_dev_transactions; sim->flags = 0; + sim->refcount = 1; sim->devq = queue; sim->mtx = mtx; if (mtx == &Giant) { @@ -103,12 +104,42 @@ cam_sim_alloc(sim_action_func sim_action, sim_poll_func sim_poll, void cam_sim_free(struct cam_sim *sim, int free_devq) { + int error; + + sim->refcount--; + if (sim->refcount > 0) { + error = msleep(sim, sim->mtx, PRIBIO, "simfree", 0); + KASSERT(error == 0, ("invalid error value for msleep(9)")); + } + + KASSERT(sim->refcount == 0, ("sim->refcount == 0")); + if (free_devq) cam_simq_free(sim->devq); free(sim, M_CAMSIM); } void +cam_sim_release(struct cam_sim *sim) +{ + KASSERT(sim->refcount >= 1, ("sim->refcount >= 1")); + mtx_assert(sim->mtx, MA_OWNED); + + sim->refcount--; + if (sim->refcount == 0) + wakeup(sim); +} + +void +cam_sim_hold(struct cam_sim *sim) +{ + KASSERT(sim->refcount >= 1, ("sim->refcount >= 1")); + mtx_assert(sim->mtx, MA_OWNED); + + sim->refcount++; +} + +void cam_sim_set_path(struct cam_sim *sim, u_int32_t path_id) { sim->path_id = path_id; diff --git a/sys/cam/cam_sim.h b/sys/cam/cam_sim.h index c2d3c5f..f37c5d5 100644 --- a/sys/cam/cam_sim.h +++ b/sys/cam/cam_sim.h @@ -61,6 +61,8 @@ struct cam_sim * cam_sim_alloc(sim_action_func sim_action, int max_tagged_dev_transactions, struct cam_devq *queue); void cam_sim_free(struct cam_sim *sim, int free_devq); +void cam_sim_hold(struct cam_sim *sim); +void cam_sim_release(struct cam_sim *sim); /* Optional sim attributes may be set with these. */ void cam_sim_set_path(struct cam_sim *sim, u_int32_t path_id); @@ -105,6 +107,7 @@ struct cam_sim { #define CAM_SIM_ON_DONEQ 0x04 struct callout callout; struct cam_devq *devq; /* Device Queue to use for this SIM */ + int refcount; /* References to the SIM. */ /* "Pool" of inactive ccbs managed by xpt_alloc_ccb and xpt_free_ccb */ SLIST_HEAD(,ccb_hdr) ccb_freeq; diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c index b400e42..f2a2d9d 100644 --- a/sys/cam/cam_xpt.c +++ b/sys/cam/cam_xpt.c @@ -698,19 +698,6 @@ static struct cdevsw xpt_cdevsw = { }; -static void dead_sim_action(struct cam_sim *sim, union ccb *ccb); -static void dead_sim_poll(struct cam_sim *sim); - -/* Dummy SIM that is used when the real one has gone. */ -static struct cam_sim cam_dead_sim = { - .sim_action = dead_sim_action, - .sim_poll = dead_sim_poll, - .sim_name = "dead_sim", -}; - -#define SIM_DEAD(sim) ((sim) == &cam_dead_sim) - - /* Storage for debugging datastructures */ #ifdef CAMDEBUG struct cam_path *cam_dpath; @@ -3023,19 +3010,10 @@ xpt_action(union ccb *start_ccb) case XPT_ENG_EXEC: { struct cam_path *path; - struct cam_sim *sim; int runq; path = start_ccb->ccb_h.path; - sim = path->bus->sim; - if (SIM_DEAD(sim)) { - /* The SIM has gone; just execute the CCB directly. */ - cam_ccbq_send_ccb(&path->device->ccbq, start_ccb); - (*(sim->sim_action))(sim, start_ccb); - break; - } - cam_ccbq_insert_ccb(&path->device->ccbq, start_ccb); if (path->device->qfrozen_cnt == 0) runq = xpt_schedule_dev_sendq(path->bus, path->device); @@ -3623,7 +3601,6 @@ void xpt_schedule(struct cam_periph *perph, u_int32_t new_priority) { struct cam_ed *device; - union ccb *work_ccb; int runq; mtx_assert(perph->sim->mtx, MA_OWNED); @@ -3640,15 +3617,6 @@ xpt_schedule(struct cam_periph *perph, u_int32_t new_priority) new_priority); } runq = 0; - } else if (SIM_DEAD(perph->path->bus->sim)) { - /* The SIM is gone so just call periph_start directly. */ - work_ccb = xpt_get_ccb(perph->path->device); - if (work_ccb == NULL) - return; /* XXX */ - xpt_setup_ccb(&work_ccb->ccb_h, perph->path, new_priority); - perph->pinfo.priority = new_priority; - perph->periph_start(perph, work_ccb); - return; } else { /* New entry on the queue */ CAM_DEBUG(perph->path, CAM_DEBUG_SUBTRACE, @@ -4336,6 +4304,7 @@ xpt_bus_register(struct cam_sim *sim, device_t parent, u_int32_t bus) TAILQ_INIT(&new_bus->et_entries); new_bus->path_id = sim->path_id; + cam_sim_hold(sim); new_bus->sim = sim; timevalclear(&new_bus->last_reset); new_bus->flags = 0; @@ -4372,15 +4341,8 @@ int32_t xpt_bus_deregister(path_id_t pathid) { struct cam_path bus_path; - struct cam_ed *device; - struct cam_ed_qinfo *qinfo; - struct cam_devq *devq; - struct cam_periph *periph; - struct cam_sim *ccbsim; - union ccb *work_ccb; cam_status status; - status = xpt_compile_path(&bus_path, NULL, pathid, CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); if (status != CAM_REQ_CMP) @@ -4389,42 +4351,6 @@ xpt_bus_deregister(path_id_t pathid) xpt_async(AC_LOST_DEVICE, &bus_path, NULL); xpt_async(AC_PATH_DEREGISTERED, &bus_path, NULL); - /* The SIM may be gone, so use a dummy SIM for any stray operations. */ - devq = bus_path.bus->sim->devq; - ccbsim = bus_path.bus->sim; - bus_path.bus->sim = &cam_dead_sim; - - /* Execute any pending operations now. */ - while ((qinfo = (struct cam_ed_qinfo *)camq_remove(&devq->send_queue, - CAMQ_HEAD)) != NULL || - (qinfo = (struct cam_ed_qinfo *)camq_remove(&devq->alloc_queue, - CAMQ_HEAD)) != NULL) { - do { - device = qinfo->device; - work_ccb = cam_ccbq_peek_ccb(&device->ccbq, CAMQ_HEAD); - if (work_ccb != NULL) { - devq->active_dev = device; - cam_ccbq_remove_ccb(&device->ccbq, work_ccb); - cam_ccbq_send_ccb(&device->ccbq, work_ccb); - (*(ccbsim->sim_action))(ccbsim, work_ccb); - } - - periph = (struct cam_periph *)camq_remove(&device->drvq, - CAMQ_HEAD); - if (periph != NULL) - xpt_schedule(periph, periph->pinfo.priority); - } while (work_ccb != NULL || periph != NULL); - } - - /* Make sure all completed CCBs are processed. */ - while (!TAILQ_EMPTY(&ccbsim->sim_doneq)) { - camisr_runqueue(&ccbsim->sim_doneq); - - /* Repeat the async's for the benefit of any new devices. */ - xpt_async(AC_LOST_DEVICE, &bus_path, NULL); - xpt_async(AC_PATH_DEREGISTERED, &bus_path, NULL); - } - /* Release the reference count held while registered. */ xpt_release_bus(bus_path.bus); xpt_release_path(&bus_path); @@ -4921,6 +4847,7 @@ xpt_release_bus(struct cam_eb *bus) TAILQ_REMOVE(&xsoftc.xpt_busses, bus, links); xsoftc.bus_generation++; mtx_unlock(&xsoftc.xpt_topo_lock); + cam_sim_release(bus->sim); free(bus, M_CAMXPT); } } @@ -4982,9 +4909,6 @@ xpt_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id) struct cam_devq *devq; cam_status status; - if (SIM_DEAD(bus->sim)) - return (NULL); - /* Make space for us in the device queue on our bus */ devq = bus->sim->devq; status = cam_devq_resize(devq, devq->alloc_queue.array_size + 1); @@ -5094,11 +5018,9 @@ xpt_release_device(struct cam_eb *bus, struct cam_et *target, TAILQ_REMOVE(&target->ed_entries, device,links); target->generation++; bus->sim->max_ccbs -= device->ccbq.devq_openings; - if (!SIM_DEAD(bus->sim)) { - /* Release our slot in the devq */ - devq = bus->sim->devq; - cam_devq_resize(devq, devq->alloc_queue.array_size - 1); - } + /* Release our slot in the devq */ + devq = bus->sim->devq; + cam_devq_resize(devq, devq->alloc_queue.array_size - 1); camq_fini(&device->drvq); camq_fini(&device->ccbq.queue); free(device, M_CAMXPT); @@ -6392,7 +6314,7 @@ probedone(struct cam_periph *periph, union ccb *done_ccb) xpt_done(done_ccb); if (TAILQ_FIRST(&softc->request_ccbs) == NULL) { cam_periph_invalidate(periph); - cam_periph_release(periph); + cam_periph_release_locked(periph); } else { probeschedule(periph); } @@ -7269,11 +7191,8 @@ camisr_runqueue(void *V_queue) dev = ccb_h->path->device; cam_ccbq_ccb_done(&dev->ccbq, (union ccb *)ccb_h); - - if (!SIM_DEAD(ccb_h->path->bus->sim)) { - ccb_h->path->bus->sim->devq->send_active--; - ccb_h->path->bus->sim->devq->send_openings++; - } + ccb_h->path->bus->sim->devq->send_active--; + ccb_h->path->bus->sim->devq->send_openings++; if (((dev->flags & CAM_DEV_REL_ON_COMPLETE) != 0 && (ccb_h->status&CAM_STATUS_MASK) != CAM_REQUEUE_REQ) @@ -7317,15 +7236,3 @@ camisr_runqueue(void *V_queue) } } -static void -dead_sim_action(struct cam_sim *sim, union ccb *ccb) -{ - - ccb->ccb_h.status = CAM_DEV_NOT_THERE; - xpt_done(ccb); -} - -static void -dead_sim_poll(struct cam_sim *sim) -{ -} diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c index f63a9b0..8797a08 100644 --- a/sys/cam/scsi/scsi_da.c +++ b/sys/cam/scsi/scsi_da.c @@ -772,8 +772,8 @@ daclose(struct disk *dp) softc->flags &= ~DA_FLAG_OPEN; cam_periph_unhold(periph); - cam_periph_release(periph); cam_periph_unlock(periph); + cam_periph_release(periph); return (0); } diff --git a/sys/compat/svr4/svr4_sysvec.c b/sys/compat/svr4/svr4_sysvec.c index 63e8e54..0030e3a 100644 --- a/sys/compat/svr4/svr4_sysvec.c +++ b/sys/compat/svr4/svr4_sysvec.c @@ -218,8 +218,6 @@ svr4_fixup(register_t **stack_base, struct image_params *imgp) args = (Elf32_Auxargs *)imgp->auxargs; pos = *stack_base + (imgp->args->argc + imgp->args->envc + 2); - if (args->trace) - AUXARGS_ENTRY(pos, AT_DEBUG, 1); if (args->execfd != -1) AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd); AUXARGS_ENTRY(pos, AT_PHDR, args->phdr); diff --git a/sys/conf/NOTES b/sys/conf/NOTES index 4c66d14..6825dd4 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -1958,7 +1958,7 @@ device fatm #Fore PCA200E device hatm #Fore/Marconi HE155/622 device patm #IDT77252 cards (ProATM and IDT) device utopia #ATM PHY driver -options NATM #native ATM +#options NATM #native ATM options LIBMBPOOL #needed by patm, iatm diff --git a/sys/conf/files b/sys/conf/files index 8c2316fa..68fb14e 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -2173,6 +2173,7 @@ net/if_gre.c optional gre net/if_iso88025subr.c optional token net/if_lagg.c optional lagg net/if_loop.c optional loop +net/if_llatbl.c standard net/if_media.c standard net/if_mib.c standard net/if_ppp.c optional ppp diff --git a/sys/conf/files.powerpc b/sys/conf/files.powerpc index 7570d93..901e36d 100644 --- a/sys/conf/files.powerpc +++ b/sys/conf/files.powerpc @@ -30,9 +30,11 @@ dev/kbd/kbd.c optional sc dev/ofw/openfirm.c optional aim dev/ofw/openfirmio.c optional aim dev/ofw/ofw_bus_if.m optional aim +dev/ofw/ofw_if.m optional aim dev/ofw/ofw_bus_subr.c optional aim dev/ofw/ofw_console.c optional aim dev/ofw/ofw_disk.c optional ofwd aim +dev/ofw/ofw_standard.c optional aim dev/powermac_nvram/powermac_nvram.c optional powermac_nvram powermac dev/quicc/quicc_bfe_ocp.c optional quicc mpc85xx dev/scc/scc_bfe_macio.c optional scc powermac diff --git a/sys/conf/files.sparc64 b/sys/conf/files.sparc64 index 93f07ed..311027c 100644 --- a/sys/conf/files.sparc64 +++ b/sys/conf/files.sparc64 @@ -42,8 +42,10 @@ dev/kbd/kbd.c optional atkbd | sc | ukbd dev/le/if_le_lebuffer.c optional le sbus dev/le/if_le_ledma.c optional le sbus dev/le/lebuffer_sbus.c optional le sbus +dev/ofw/ofw_if.m standard dev/ofw/ofw_bus_if.m standard dev/ofw/ofw_bus_subr.c standard +dev/ofw/ofw_standard.c standard dev/ofw/ofw_console.c optional ofw_console dev/ofw/openfirm.c standard dev/ofw/openfirmio.c standard @@ -111,7 +113,6 @@ sparc64/sparc64/mp_exception.S optional smp \ sparc64/sparc64/mp_locore.S optional smp sparc64/sparc64/mp_machdep.c optional smp sparc64/sparc64/nexus.c standard -sparc64/sparc64/ofw_bus.c standard sparc64/sparc64/ofw_machdep.c standard sparc64/sparc64/pmap.c standard sparc64/sparc64/prof_machdep.c optional profiling-routine diff --git a/sys/conf/files.sun4v b/sys/conf/files.sun4v index 03fca35..384c13a 100644 --- a/sys/conf/files.sun4v +++ b/sys/conf/files.sun4v @@ -21,8 +21,10 @@ ukbdmap.h optional ukbd_dflt_keymap \ crypto/blowfish/bf_enc.c optional crypto | ipsec crypto/des/des_enc.c optional crypto | ipsec | netsmb dev/ofw/ofw_bus_if.m standard +dev/ofw/ofw_if.m standard dev/ofw/ofw_bus_subr.c standard dev/ofw/ofw_console.c optional ofw_console +dev/ofw/ofw_standard.c standard dev/ofw/openfirm.c standard dev/ofw/openfirmio.c standard dev/ofw/openpromio.c standard @@ -65,7 +67,6 @@ sun4v/sun4v/mp_locore.S optional smp sun4v/sun4v/mp_machdep.c optional smp sun4v/sun4v/nexus.c standard sun4v/cddl/t1_copy.S standard -sparc64/sparc64/ofw_bus.c standard sparc64/sparc64/ofw_machdep.c standard sun4v/sun4v/pmap.c standard sparc64/sparc64/prof_machdep.c optional profiling-routine diff --git a/sys/contrib/pf/net/pf.c b/sys/contrib/pf/net/pf.c index 2959830..d69372b 100644 --- a/sys/contrib/pf/net/pf.c +++ b/sys/contrib/pf/net/pf.c @@ -3162,7 +3162,7 @@ pf_calc_mss(struct pf_addr *addr, sa_family_t af, u_int16_t offer) #ifdef RTF_PRCLONING rtalloc_ign(&ro, (RTF_CLONING | RTF_PRCLONING)); #else /* !RTF_PRCLONING */ - in_rtalloc_ign(&ro, RTF_CLONING, 0); + in_rtalloc_ign(&ro, 0, 0); #endif #else /* ! __FreeBSD__ */ rtalloc_noclone(&ro, NO_CLONING); @@ -3183,7 +3183,7 @@ pf_calc_mss(struct pf_addr *addr, sa_family_t af, u_int16_t offer) rtalloc_ign((struct route *)&ro6, (RTF_CLONING | RTF_PRCLONING)); #else /* !RTF_PRCLONING */ - rtalloc_ign((struct route *)&ro6, RTF_CLONING); + rtalloc_ign((struct route *)&ro6, 0); #endif #else /* ! __FreeBSD__ */ rtalloc_noclone((struct route *)&ro6, NO_CLONING); @@ -5986,9 +5986,9 @@ pf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *kif) #ifdef __FreeBSD__ /* XXX MRT not always INET */ /* stick with table 0 though */ if (af == AF_INET) - in_rtalloc_ign((struct route *)&ro, RTF_CLONING, 0); + in_rtalloc_ign((struct route *)&ro, 0, 0); else - rtalloc_ign((struct route *)&ro, RTF_CLONING); + rtalloc_ign((struct route *)&ro, 0); #else /* ! __FreeBSD__ */ rtalloc_noclone((struct route *)&ro, NO_CLONING); #endif @@ -6068,9 +6068,9 @@ pf_rtlabel_match(struct pf_addr *addr, sa_family_t af, struct pf_addr_wrap *aw) rtalloc_ign((struct route *)&ro, (RTF_CLONING|RTF_PRCLONING)); # else /* !RTF_PRCLONING */ if (af == AF_INET) - in_rtalloc_ign((struct route *)&ro, RTF_CLONING, 0); + in_rtalloc_ign((struct route *)&ro, 0, 0); else - rtalloc_ign((struct route *)&ro, RTF_CLONING); + rtalloc_ign((struct route *)&ro, 0); # endif #else /* ! __FreeBSD__ */ rtalloc_noclone((struct route *)&ro, NO_CLONING); diff --git a/sys/contrib/pf/net/pf_if.c b/sys/contrib/pf/net/pf_if.c index 62dbbf2..1972edc 100644 --- a/sys/contrib/pf/net/pf_if.c +++ b/sys/contrib/pf/net/pf_if.c @@ -115,8 +115,10 @@ void pfi_change_group_event(void * __unused, char *); void pfi_detach_group_event(void * __unused, struct ifg_group *); void pfi_ifaddr_event(void * __unused, struct ifnet *); +#ifdef VIMAGE_GLOBALS extern struct ifgrouphead ifg_head; #endif +#endif RB_PROTOTYPE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare); RB_GENERATE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare); diff --git a/sys/contrib/pf/net/pf_subr.c b/sys/contrib/pf/net/pf_subr.c index 1ac8b40..a722aef 100644 --- a/sys/contrib/pf/net/pf_subr.c +++ b/sys/contrib/pf/net/pf_subr.c @@ -116,22 +116,22 @@ __FBSDID("$FreeBSD$"); #define ISN_STATIC_INCREMENT 4096 #define ISN_RANDOM_INCREMENT (4096 - 1) -static u_char isn_secret[32]; -static int isn_last_reseed; -static u_int32_t isn_offset; -static MD5_CTX isn_ctx; +static u_char pf_isn_secret[32]; +static int pf_isn_last_reseed; +static u_int32_t pf_isn_offset; u_int32_t pf_new_isn(struct pf_state *s) { + MD5_CTX isn_ctx; u_int32_t md5_buffer[4]; u_int32_t new_isn; struct pf_state_host *src, *dst; /* Seed if this is the first use, reseed if requested. */ - if (isn_last_reseed == 0) { - read_random(&isn_secret, sizeof(isn_secret)); - isn_last_reseed = ticks; + if (pf_isn_last_reseed == 0) { + read_random(&pf_isn_secret, sizeof(pf_isn_secret)); + pf_isn_last_reseed = ticks; } if (s->direction == PF_IN) { @@ -160,11 +160,11 @@ pf_new_isn(struct pf_state *s) MD5Update(&isn_ctx, (u_char *) &src->addr, sizeof(struct in_addr)); } - MD5Update(&isn_ctx, (u_char *) &isn_secret, sizeof(isn_secret)); + MD5Update(&isn_ctx, (u_char *) &pf_isn_secret, sizeof(pf_isn_secret)); MD5Final((u_char *) &md5_buffer, &isn_ctx); new_isn = (tcp_seq) md5_buffer[0]; - isn_offset += ISN_STATIC_INCREMENT + + pf_isn_offset += ISN_STATIC_INCREMENT + (arc4random() & ISN_RANDOM_INCREMENT); - new_isn += isn_offset; + new_isn += pf_isn_offset; return (new_isn); } diff --git a/sys/contrib/rdma/rdma_addr.c b/sys/contrib/rdma/rdma_addr.c index e052b80..971b4de 100644 --- a/sys/contrib/rdma/rdma_addr.c +++ b/sys/contrib/rdma/rdma_addr.c @@ -163,6 +163,7 @@ static void addr_send_arp(struct sockaddr_in *dst_in) struct route iproute; struct sockaddr_in *dst = (struct sockaddr_in *)&iproute.ro_dst; char dmac[ETHER_ADDR_LEN]; + struct llentry *lle; bzero(&iproute, sizeof iproute); *dst = *dst_in; @@ -172,7 +173,7 @@ static void addr_send_arp(struct sockaddr_in *dst_in) return; arpresolve(iproute.ro_rt->rt_ifp, iproute.ro_rt, NULL, - rt_key(iproute.ro_rt), dmac); + rt_key(iproute.ro_rt), dmac, &lle); RTFREE(iproute.ro_rt); } @@ -186,6 +187,7 @@ static int addr_resolve_remote(struct sockaddr_in *src_in, struct route iproute; struct sockaddr_in *dst = (struct sockaddr_in *)&iproute.ro_dst; char dmac[ETHER_ADDR_LEN]; + struct llentry *lle; bzero(&iproute, sizeof iproute); *dst = *dst_in; @@ -202,7 +204,7 @@ static int addr_resolve_remote(struct sockaddr_in *src_in, goto put; } ret = arpresolve(iproute.ro_rt->rt_ifp, iproute.ro_rt, NULL, - rt_key(iproute.ro_rt), dmac); + rt_key(iproute.ro_rt), dmac, &lle); if (ret) { goto put; } diff --git a/sys/crypto/rc4/rc4.c b/sys/crypto/rc4/rc4.c index f94a554..dbdbd7a 100644 --- a/sys/crypto/rc4/rc4.c +++ b/sys/crypto/rc4/rc4.c @@ -61,7 +61,7 @@ void rc4_init(struct rc4_state *const state, const u_char *key, int keylen) { u_char j; - int i; + int i, k; /* Initialize state with identity permutation */ for (i = 0; i < 256; i++) @@ -70,9 +70,11 @@ rc4_init(struct rc4_state *const state, const u_char *key, int keylen) state->index2 = 0; /* Randomize the permutation using key data */ - for (j = i = 0; i < 256; i++) { - j += state->perm[i] + key[i % keylen]; + for (j = i = k = 0; i < 256; i++) { + j += state->perm[i] + key[k]; swap_bytes(&state->perm[i], &state->perm[j]); + if (++k >= keylen) + k = 0; } } diff --git a/sys/dev/acpica/acpi_smbat.c b/sys/dev/acpica/acpi_smbat.c index 5e1c66e..3935a9f 100644 --- a/sys/dev/acpica/acpi_smbat.c +++ b/sys/dev/acpica/acpi_smbat.c @@ -61,6 +61,23 @@ static int acpi_smbat_get_bst(device_t dev, struct acpi_bst *bst); ACPI_SERIAL_DECL(smbat, "ACPI Smart Battery"); +SYSCTL_DECL(_debug_acpi); +SYSCTL_NODE(_debug_acpi, OID_AUTO, batt, CTLFLAG_RD, NULL, "Battery debugging"); + +/* On some laptops with smart batteries, enabling battery monitoring + * software causes keystrokes from atkbd to be lost. This has also been + * reported on Linux, and is apparently due to the keyboard and I2C line + * for the battery being routed through the same chip. Whether that's + * accurate or not, adding extra sleeps to the status checking code + * causes the problem to go away. + * + * If you experience that problem, try a value of 10ms and move up + * from there. + */ +static int batt_sleep_ms; +SYSCTL_INT(_debug_acpi_batt, OID_AUTO, batt_sleep_ms, CTLFLAG_RW, &batt_sleep_ms, 0, + "Sleep during battery status updates to prevent keystroke loss."); + static device_method_t acpi_smbat_methods[] = { /* device interface */ DEVMETHOD(device_probe, acpi_smbat_probe), @@ -176,6 +193,9 @@ acpi_smbus_read_2(struct acpi_smbat_softc *sc, uint8_t addr, uint8_t cmd, ACPI_SERIAL_ASSERT(smbat); + if (batt_sleep_ms) + AcpiOsSleep(batt_sleep_ms); + val = addr; error = ACPI_EC_WRITE(sc->ec_dev, sc->sb_base_addr + SMBUS_ADDR, val, 1); @@ -194,6 +214,9 @@ acpi_smbus_read_2(struct acpi_smbat_softc *sc, uint8_t addr, uint8_t cmd, if (error) goto out; + if (batt_sleep_ms) + AcpiOsSleep(batt_sleep_ms); + for (to = SMBUS_TIMEOUT; to != 0; to--) { error = ACPI_EC_READ(sc->ec_dev, sc->sb_base_addr + SMBUS_PRTCL, &val, 1); @@ -239,6 +262,9 @@ acpi_smbus_read_multi_1(struct acpi_smbat_softc *sc, uint8_t addr, uint8_t cmd, ACPI_SERIAL_ASSERT(smbat); + if (batt_sleep_ms) + AcpiOsSleep(batt_sleep_ms); + val = addr; error = ACPI_EC_WRITE(sc->ec_dev, sc->sb_base_addr + SMBUS_ADDR, val, 1); @@ -257,6 +283,9 @@ acpi_smbus_read_multi_1(struct acpi_smbat_softc *sc, uint8_t addr, uint8_t cmd, if (error) goto out; + if (batt_sleep_ms) + AcpiOsSleep(batt_sleep_ms); + for (to = SMBUS_TIMEOUT; to != 0; to--) { error = ACPI_EC_READ(sc->ec_dev, sc->sb_base_addr + SMBUS_PRTCL, &val, 1); @@ -292,6 +321,9 @@ acpi_smbus_read_multi_1(struct acpi_smbat_softc *sc, uint8_t addr, uint8_t cmd, if (len > val) len = val; + if (batt_sleep_ms) + AcpiOsSleep(batt_sleep_ms); + while (len--) { error = ACPI_EC_READ(sc->ec_dev, sc->sb_base_addr + SMBUS_DATA + len, &val, 1); @@ -299,6 +331,8 @@ acpi_smbus_read_multi_1(struct acpi_smbat_softc *sc, uint8_t addr, uint8_t cmd, goto out; ptr[len] = val; + if (batt_sleep_ms) + AcpiOsSleep(batt_sleep_ms); } out: diff --git a/sys/dev/ata/ata-pci.c b/sys/dev/ata/ata-pci.c index 855a1d0..f2e4805 100644 --- a/sys/dev/ata/ata-pci.c +++ b/sys/dev/ata/ata-pci.c @@ -92,7 +92,8 @@ ata_pci_attach(device_t dev) int unit; /* do chipset specific setups only needed once */ - if (ata_legacy(dev) || pci_read_config(dev, PCIR_BAR(2), 4) & IOMASK) + ctlr->legacy = ata_legacy(dev); + if (ctlr->legacy || pci_read_config(dev, PCIR_BAR(2), 4) & IOMASK) ctlr->channels = 2; else ctlr->channels = 1; @@ -120,7 +121,7 @@ ata_pci_attach(device_t dev) /* attach all channels on this controller */ for (unit = 0; unit < ctlr->channels; unit++) { - if ((unit == 0 || unit == 1) && ata_legacy(dev)) { + if ((unit == 0 || unit == 1) && ctlr->legacy) { device_add_child(dev, "ata", unit); continue; } @@ -192,7 +193,7 @@ ata_pci_alloc_resource(device_t dev, device_t child, int type, int *rid, if (type == SYS_RES_IOPORT) { switch (*rid) { case ATA_IOADDR_RID: - if (ata_legacy(dev)) { + if (controller->legacy) { start = (unit ? ATA_SECONDARY : ATA_PRIMARY); count = ATA_IOSIZE; end = start + count - 1; @@ -204,7 +205,7 @@ ata_pci_alloc_resource(device_t dev, device_t child, int type, int *rid, break; case ATA_CTLADDR_RID: - if (ata_legacy(dev)) { + if (controller->legacy) { start = (unit ? ATA_SECONDARY : ATA_PRIMARY) + ATA_CTLOFFSET; count = ATA_CTLIOSIZE; end = start + count - 1; @@ -217,7 +218,7 @@ ata_pci_alloc_resource(device_t dev, device_t child, int type, int *rid, } } if (type == SYS_RES_IRQ && *rid == ATA_IRQ_RID) { - if (ata_legacy(dev)) { + if (controller->legacy) { int irq = (unit == 0 ? 14 : 15); res = BUS_ALLOC_RESOURCE(device_get_parent(dev), child, @@ -233,6 +234,7 @@ int ata_pci_release_resource(device_t dev, device_t child, int type, int rid, struct resource *r) { + struct ata_pci_controller *controller = device_get_softc(dev); int unit = ((struct ata_channel *)device_get_softc(child))->unit; if (type == SYS_RES_IOPORT) { @@ -256,7 +258,7 @@ ata_pci_release_resource(device_t dev, device_t child, int type, int rid, if (rid != ATA_IRQ_RID) return ENOENT; - if (ata_legacy(dev)) { + if (controller->legacy) { return BUS_RELEASE_RESOURCE(device_get_parent(dev), child, SYS_RES_IRQ, rid, r); } @@ -271,7 +273,9 @@ ata_pci_setup_intr(device_t dev, device_t child, struct resource *irq, int flags, driver_filter_t *filter, driver_intr_t *function, void *argument, void **cookiep) { - if (ata_legacy(dev)) { + struct ata_pci_controller *controller = device_get_softc(dev); + + if (controller->legacy) { return BUS_SETUP_INTR(device_get_parent(dev), child, irq, flags, filter, function, argument, cookiep); } @@ -294,7 +298,9 @@ int ata_pci_teardown_intr(device_t dev, device_t child, struct resource *irq, void *cookie) { - if (ata_legacy(dev)) { + struct ata_pci_controller *controller = device_get_softc(dev); + + if (controller->legacy) { return BUS_TEARDOWN_INTR(device_get_parent(dev), child, irq, cookie); } else { @@ -352,7 +358,7 @@ ata_pci_allocate(device_t dev) ch->r_io[i].offset = i; } ch->r_io[ATA_CONTROL].res = ctlio; - ch->r_io[ATA_CONTROL].offset = ata_legacy(device_get_parent(dev)) ? 0 : 2; + ch->r_io[ATA_CONTROL].offset = ctlr->legacy ? 0 : 2; ch->r_io[ATA_IDX_ADDR].res = io; ata_default_registers(dev); if (ctlr->r_res1) { @@ -369,9 +375,11 @@ ata_pci_allocate(device_t dev) int ata_pci_status(device_t dev) { + struct ata_pci_controller *controller = + device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); - if ((dumping || !ata_legacy(device_get_parent(dev))) && + if ((dumping || !controller->legacy) && ((ch->flags & ATA_ALWAYS_DMASTAT) || (ch->dma.flags & ATA_DMA_ACTIVE))) { int bmstat = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; @@ -652,7 +660,7 @@ ata_setup_interrupt(device_t dev, void *intr_func) struct ata_pci_controller *ctlr = device_get_softc(dev); int rid = ATA_IRQ_RID; - if (!ata_legacy(dev)) { + if (!ctlr->legacy) { if (!(ctlr->r_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE))) { device_printf(dev, "unable to map interrupt\n"); diff --git a/sys/dev/ata/ata-pci.h b/sys/dev/ata/ata-pci.h index 0cbb0d5..e5edd87 100644 --- a/sys/dev/ata/ata-pci.h +++ b/sys/dev/ata/ata-pci.h @@ -48,6 +48,7 @@ struct ata_pci_controller { struct resource *r_irq; void *handle; struct ata_chip_id *chip; + int legacy; int channels; int (*chipinit)(device_t); int (*suspend)(device_t); diff --git a/sys/dev/ata/chipsets/ata-ahci.c b/sys/dev/ata/chipsets/ata-ahci.c index 4481d9a..4028466 100644 --- a/sys/dev/ata/chipsets/ata-ahci.c +++ b/sys/dev/ata/chipsets/ata-ahci.c @@ -73,8 +73,9 @@ ata_ahci_probe(device_t dev) char buffer[64]; /* is this a possible AHCI candidate ? */ - if (pci_get_subclass(dev) != PCIS_STORAGE_SATA) - return ENXIO; + if (pci_get_class(dev) != PCIC_STORAGE || + pci_get_subclass(dev) != PCIS_STORAGE_SATA) + return (ENXIO); /* is this PCI device flagged as an AHCI compliant chip ? */ if (pci_read_config(dev, PCIR_PROGIF, 1) != PCIP_STORAGE_SATA_AHCI_1_0) @@ -94,6 +95,7 @@ int ata_ahci_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); + int error; u_int32_t version; /* if we have a memory BAR(5) we are likely on an AHCI part */ @@ -105,14 +107,19 @@ ata_ahci_chipinit(device_t dev) /* setup interrupt delivery if not done allready by a vendor driver */ if (!ctlr->r_irq) { - if (ata_setup_interrupt(dev, ata_generic_intr)) + if (ata_setup_interrupt(dev, ata_generic_intr)) { + bus_release_resource(dev, ctlr->r_type2, ctlr->r_rid2, ctlr->r_res2); return ENXIO; + } } else device_printf(dev, "AHCI called from vendor specific driver\n"); /* reset controller */ - ata_ahci_ctlr_reset(dev); + if ((error = ata_ahci_ctlr_reset(dev)) != 0) { + bus_release_resource(dev, ctlr->r_type2, ctlr->r_rid2, ctlr->r_res2); + return (error); + }; /* get the number of HW channels */ ctlr->channels = @@ -154,7 +161,6 @@ ata_ahci_ctlr_reset(device_t dev) ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_HR); DELAY(1000000); if (ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) & ATA_AHCI_GHC_HR) { - bus_release_resource(dev, ctlr->r_type2, ctlr->r_rid2, ctlr->r_res2); device_printf(dev, "AHCI controller reset failure\n"); return ENXIO; } diff --git a/sys/dev/ata/chipsets/ata-sis.c b/sys/dev/ata/chipsets/ata-sis.c index e94bef5..56b194d 100644 --- a/sys/dev/ata/chipsets/ata-sis.c +++ b/sys/dev/ata/chipsets/ata-sis.c @@ -105,6 +105,9 @@ ata_sis_probe(device_t dev) char buffer[64]; int found = 0; + if (pci_get_class(dev) != PCIC_STORAGE) + return (ENXIO); + if (pci_get_vendor(dev) != ATA_SIS_ID) return ENXIO; diff --git a/sys/dev/ath/ath_hal/ah.c b/sys/dev/ath/ath_hal/ah.c index 18d31ec..668ace7 100644 --- a/sys/dev/ath/ath_hal/ah.c +++ b/sys/dev/ath/ath_hal/ah.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $Id: ah.c,v 1.15 2008/11/15 22:15:44 sam Exp $ + * $FreeBSD$ */ #include "opt_ah.h" @@ -32,7 +32,7 @@ OS_SET_DECLARE(ah_chips, struct ath_hal_chip); const char* ath_hal_probe(uint16_t vendorid, uint16_t devid) { - struct ath_hal_chip **pchip; + struct ath_hal_chip * const *pchip; OS_SET_FOREACH(pchip, ah_chips) { const char *name = (*pchip)->probe(vendorid, devid); @@ -53,7 +53,7 @@ struct ath_hal* ath_hal_attach(uint16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *error) { - struct ath_hal_chip **pchip; + struct ath_hal_chip * const *pchip; OS_SET_FOREACH(pchip, ah_chips) { struct ath_hal_chip *chip = *pchip; @@ -88,7 +88,7 @@ OS_SET_DECLARE(ah_rfs, struct ath_hal_rf); struct ath_hal_rf * ath_hal_rfprobe(struct ath_hal *ah, HAL_STATUS *ecode) { - struct ath_hal_rf **prf; + struct ath_hal_rf * const *prf; OS_SET_FOREACH(prf, ah_rfs) { struct ath_hal_rf *rf = *prf; diff --git a/sys/dev/ath/ath_hal/ah_eeprom_v14.c b/sys/dev/ath/ath_hal/ah_eeprom_v14.c index 45f998f..8793d3b 100644 --- a/sys/dev/ath/ath_hal/ah_eeprom_v14.c +++ b/sys/dev/ath/ath_hal/ah_eeprom_v14.c @@ -160,18 +160,6 @@ v14EepromDiag(struct ath_hal *ah, int request, return AH_FALSE; } -/* XXX conditionalize by target byte order */ -#ifndef bswap16 -static __inline__ uint16_t -__bswap16(uint16_t _x) -{ - return ((uint16_t)( - (((const uint8_t *)(&_x))[0] ) | - (((const uint8_t *)(&_x))[1]<< 8)) - ); -} -#endif - /* Do structure specific swaps if Eeprom format is non native to host */ static void eepromSwap(struct ar5416eeprom *ee) diff --git a/sys/dev/ath/ath_hal/ah_eeprom_v3.c b/sys/dev/ath/ath_hal/ah_eeprom_v3.c index b2c304b..20adb31 100644 --- a/sys/dev/ath/ath_hal/ah_eeprom_v3.c +++ b/sys/dev/ath/ath_hal/ah_eeprom_v3.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $Id: ah_eeprom_v3.c,v 1.4 2008/11/27 22:39:42 sam Exp $ + * $FreeBSD$ */ #include "opt_ah.h" @@ -26,9 +26,9 @@ static void getPcdacInterceptsFromPcdacMinMax(HAL_EEPROM *ee, uint16_t pcdacMin, uint16_t pcdacMax, uint16_t *vp) { - const static uint16_t intercepts3[] = + static const uint16_t intercepts3[] = { 0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100 }; - const static uint16_t intercepts3_2[] = + static const uint16_t intercepts3_2[] = { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 }; const uint16_t *ip = ee->ee_version < AR_EEPROM_VER3_2 ? intercepts3 : intercepts3_2; diff --git a/sys/dev/ath/ath_hal/ah_internal.h b/sys/dev/ath/ath_hal/ah_internal.h index da09c68..9feb295 100644 --- a/sys/dev/ath/ath_hal/ah_internal.h +++ b/sys/dev/ath/ath_hal/ah_internal.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $Id: ah_internal.h,v 1.21 2008/11/27 22:29:27 sam Exp $ + * $FreeBSD$ */ #ifndef _ATH_AH_INTERAL_H_ #define _ATH_AH_INTERAL_H_ @@ -42,23 +42,6 @@ #define offsetof(type, field) ((size_t)(&((type *)0)->field)) #endif -/* - * Remove const in a way that keeps the compiler happy. - * This works for gcc but may require other magic for - * other compilers (not sure where this should reside). - * Note that uintptr_t is C99. - */ -#ifndef __DECONST -#ifndef _UINTPTR_T -#if AH_WORDSIZE == 64 -typedef unsigned long int uintptr_t; -#else -typedef unsigned int uintptr_t; -#endif -#endif -#define __DECONST(type, var) ((type)(uintptr_t)(const void *)(var)) -#endif - typedef struct { uint16_t start; /* first register */ uint16_t end; /* ending register or zero */ @@ -114,12 +97,12 @@ struct ath_hal_rf { }; #ifndef AH_RF #define AH_RF(_name, _probe, _attach) \ -static struct ath_hal_rf name##_rf = { \ - .name = #_name, \ +static struct ath_hal_rf _name##_rf = { \ + .name = __STRING(_name), \ .probe = _probe, \ .attach = _attach \ }; \ -OS_DATA_SET(ah_rfs, name##_rf) +OS_DATA_SET(ah_rfs, _name##_rf) #endif struct ath_hal_rf *ath_hal_rfprobe(struct ath_hal *ah, HAL_STATUS *ecode); diff --git a/sys/dev/ath/ath_hal/ar5212/ar5111.c b/sys/dev/ath/ath_hal/ar5212/ar5111.c index 95dbbd5..f009ebe 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5111.c +++ b/sys/dev/ath/ath_hal/ar5212/ar5111.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $Id: ar5111.c,v 1.7 2008/11/10 04:08:03 sam Exp $ + * $FreeBSD$ */ #include "opt_ah.h" @@ -90,7 +90,7 @@ ar5111SetChannel(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) uint16_t channel5111; /* 11a channel for 5111 */ } CHAN_INFO_2GHZ; - const static CHAN_INFO_2GHZ chan2GHzData[] = { + static const CHAN_INFO_2GHZ chan2GHzData[] = { { 1, 0x46, 96 }, /* 2312 -19 */ { 1, 0x46, 97 }, /* 2317 -18 */ { 1, 0x46, 98 }, /* 2322 -17 */ diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_ani.c b/sys/dev/ath/ath_hal/ar5212/ar5212_ani.c index 645c56c..bef9c28e 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212_ani.c +++ b/sys/dev/ath/ath_hal/ar5212/ar5212_ani.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $Id: ar5212_ani.c,v 1.7 2008/11/21 00:16:21 sam Exp $ + * $FreeBSD$ */ #include "opt_ah.h" @@ -267,7 +267,7 @@ ar5212AniControl(struct ath_hal *ah, HAL_ANI_CMD cmd, int param) case HAL_ANI_NOISE_IMMUNITY_LEVEL: { u_int level = param; - if (level >= params->maxNoiseImmunityLevel) { + if (level > params->maxNoiseImmunityLevel) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: level out of range (%u > %u)\n", __func__, level, params->maxNoiseImmunityLevel); @@ -342,7 +342,7 @@ ar5212AniControl(struct ath_hal *ah, HAL_ANI_CMD cmd, int param) case HAL_ANI_FIRSTEP_LEVEL: { u_int level = param; - if (level >= params->maxFirstepLevel) { + if (level > params->maxFirstepLevel) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: level out of range (%u > %u)\n", __func__, level, params->maxFirstepLevel); @@ -360,7 +360,7 @@ ar5212AniControl(struct ath_hal *ah, HAL_ANI_CMD cmd, int param) case HAL_ANI_SPUR_IMMUNITY_LEVEL: { u_int level = param; - if (level >= params->maxSpurImmunityLevel) { + if (level > params->maxSpurImmunityLevel) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: level out of range (%u > %u)\n", __func__, level, params->maxSpurImmunityLevel); @@ -433,7 +433,7 @@ ar5212AniOfdmErrTrigger(struct ath_hal *ah) aniState = ahp->ah_curani; params = aniState->params; /* First, raise noise immunity level, up to max */ - if (aniState->noiseImmunityLevel+1 < params->maxNoiseImmunityLevel) { + if (aniState->noiseImmunityLevel+1 <= params->maxNoiseImmunityLevel) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: raise NI to %u\n", __func__, aniState->noiseImmunityLevel + 1); ar5212AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, @@ -441,7 +441,7 @@ ar5212AniOfdmErrTrigger(struct ath_hal *ah) return; } /* then, raise spur immunity level, up to max */ - if (aniState->spurImmunityLevel+1 < params->maxSpurImmunityLevel) { + if (aniState->spurImmunityLevel+1 <= params->maxSpurImmunityLevel) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: raise SI to %u\n", __func__, aniState->spurImmunityLevel + 1); ar5212AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, @@ -470,7 +470,7 @@ ar5212AniOfdmErrTrigger(struct ath_hal *ah) * If weak sig detect is already off, as last resort, * raise firstep level */ - if (aniState->firstepLevel+1 < params->maxFirstepLevel) { + if (aniState->firstepLevel+1 <= params->maxFirstepLevel) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: rssi %d raise ST %u\n", __func__, rssi, aniState->firstepLevel+1); @@ -490,7 +490,7 @@ ar5212AniOfdmErrTrigger(struct ath_hal *ah) HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, AH_TRUE); } - if (aniState->firstepLevel+1 < params->maxFirstepLevel) { + if (aniState->firstepLevel+1 <= params->maxFirstepLevel) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: rssi %d raise ST %u\n", __func__, rssi, aniState->firstepLevel+1); @@ -544,7 +544,7 @@ ar5212AniCckErrTrigger(struct ath_hal *ah) /* first, raise noise immunity level, up to max */ aniState = ahp->ah_curani; params = aniState->params; - if (aniState->noiseImmunityLevel+1 < params->maxNoiseImmunityLevel) { + if (aniState->noiseImmunityLevel+1 <= params->maxNoiseImmunityLevel) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: raise NI to %u\n", __func__, aniState->noiseImmunityLevel + 1); ar5212AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, @@ -559,7 +559,7 @@ ar5212AniCckErrTrigger(struct ath_hal *ah) * Beacon signal in mid and high range, * raise firstep level. */ - if (aniState->firstepLevel+1 < params->maxFirstepLevel) { + if (aniState->firstepLevel+1 <= params->maxFirstepLevel) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: rssi %d raise ST %u\n", __func__, rssi, aniState->firstepLevel+1); diff --git a/sys/dev/ath/ath_hal/ar5312/ar5312.h b/sys/dev/ath/ath_hal/ar5312/ar5312.h index 4714ea1..4943891 100644 --- a/sys/dev/ath/ath_hal/ar5312/ar5312.h +++ b/sys/dev/ath/ath_hal/ar5312/ar5312.h @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $Id: ar5312.h,v 1.5 2008/11/22 07:37:40 sam Exp $ + * $FreeBSD$ */ #ifndef _ATH_AR5312_H_ #define _ATH_AR5312_H_ @@ -38,8 +38,6 @@ AH_PRIVATE(ah)->ah_devid == AR5212_AR2317_REV1 || \ AH_PRIVATE(ah)->ah_devid == AR5212_AR2317_REV2) -extern struct ath_hal * ar5312Attach(uint16_t devid, HAL_SOFTC sc, - HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *status); extern HAL_BOOL ar5312IsInterruptPending(struct ath_hal *ah); /* AR5312 */ diff --git a/sys/dev/ath/ath_hal/ar5312/ar5312_attach.c b/sys/dev/ath/ath_hal/ar5312/ar5312_attach.c index b5a2dde..e38c50c 100644 --- a/sys/dev/ath/ath_hal/ar5312/ar5312_attach.c +++ b/sys/dev/ath/ath_hal/ar5312/ar5312_attach.c @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $Id: ar5312_attach.c,v 1.8 2008/11/27 22:30:03 sam Exp $ + * $FreeBSD$ */ #include "opt_ah.h" @@ -122,7 +122,7 @@ ar5312Attach(uint16_t devid, HAL_SOFTC sc, /* setup common ini data; rf backends handle remainder */ HAL_INI_INIT(&ahp->ah_ini_modes, ar5212Modes, 6); - HAL_INI_INIT(&ahp->ah_ini_common, ar5212Common, 6); + HAL_INI_INIT(&ahp->ah_ini_common, ar5212Common, 2); if (!ar5312ChipReset(ah, AH_NULL)) { /* reset chip */ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); @@ -318,7 +318,6 @@ ar5312Probe(uint16_t vendorid, uint16_t devid) case AR5212_AR2313_REV8: return "Atheros 2313 WiSoC"; case AR5212_AR2315_REV6: - case AR5212_AR2315_REV6: case AR5212_AR2315_REV7: return "Atheros 2315 WiSoC"; case AR5212_AR2317_REV1: diff --git a/sys/dev/atkbdc/psm.c b/sys/dev/atkbdc/psm.c index 2b1117f..338d8f2 100644 --- a/sys/dev/atkbdc/psm.c +++ b/sys/dev/atkbdc/psm.c @@ -3956,6 +3956,9 @@ static void synaptics_sysctl_create_tree(struct psm_softc *sc) { + if (sc->syninfo.sysctl_tree != NULL) + return; + /* Attach extra synaptics sysctl nodes under hw.psm.synaptics */ sysctl_ctx_init(&sc->syninfo.sysctl_ctx); sc->syninfo.sysctl_tree = SYSCTL_ADD_NODE(&sc->syninfo.sysctl_ctx, @@ -4263,14 +4266,18 @@ enable_synaptics(struct psm_softc *sc) kbdc = sc->kbdc; VLOG(3, (LOG_DEBUG, "synaptics: BEGIN init\n")); - disable_aux_dev(kbdc); sc->hw.buttons = 3; sc->squelch = 0; - /* Just to be on the safe side */ + /* + * Just to be on the safe side: this avoids troubles with + * following mouse_ext_command() when the previous command + * was PSMC_SET_RESOLUTION. Set Scaling has no effect on + * Synaptics Touchpad behaviour. + */ set_mouse_scaling(kbdc, 1); - /* Identify the Touchpad version */ + /* Identify the Touchpad version. */ if (mouse_ext_command(kbdc, 0) == 0) return (FALSE); if (get_mouse_status(kbdc, status, 0, 3) != 3) @@ -4290,7 +4297,7 @@ enable_synaptics(struct psm_softc *sc) return (FALSE); } - /* Get the Touchpad model information */ + /* Get the Touchpad model information. */ if (mouse_ext_command(kbdc, 3) == 0) return (FALSE); if (get_mouse_status(kbdc, status, 0, 3) != 3) @@ -4321,7 +4328,7 @@ enable_synaptics(struct psm_softc *sc) printf(" infoGeometry: %d\n", sc->synhw.infoGeometry); } - /* Read the extended capability bits */ + /* Read the extended capability bits. */ if (mouse_ext_command(kbdc, 2) == 0) return (FALSE); if (get_mouse_status(kbdc, status, 0, 3) != 3) @@ -4331,7 +4338,7 @@ enable_synaptics(struct psm_softc *sc) return (FALSE); } - /* Set the different capabilities when they exist */ + /* Set the different capabilities when they exist. */ if ((status[0] & 0x80) >> 7) { sc->synhw.capExtended = (status[0] & 0x80) >> 7; sc->synhw.capPassthrough = (status[2] & 0x80) >> 7; @@ -4355,8 +4362,8 @@ enable_synaptics(struct psm_softc *sc) } /* - * if we have bits set in status[0] & 0x70 - then we can load - * more information about buttons using query 0x09 + * If we have bits set in status[0] & 0x70, then we can load + * more information about buttons using query 0x09. */ if (status[0] & 0x70) { if (mouse_ext_command(kbdc, 0x09) == 0) @@ -4376,7 +4383,7 @@ enable_synaptics(struct psm_softc *sc) } /* - * Read the mode byte + * Read the mode byte. * * XXX: Note the Synaptics documentation also defines the first * byte of the response to this query to be a constant 0x3b, this @@ -4391,13 +4398,13 @@ enable_synaptics(struct psm_softc *sc) return (FALSE); } - /* Set the mode byte -- request wmode where available */ + /* Set the mode byte; request wmode where available. */ if (sc->synhw.capExtended) mouse_ext_command(kbdc, 0xc1); else mouse_ext_command(kbdc, 0xc0); - /* Reset the sampling rate */ + /* "Commit" the Set Mode Byte command sent above. */ set_mouse_sampling_rate(kbdc, 20); /* @@ -4414,6 +4421,12 @@ enable_synaptics(struct psm_softc *sc) /* Create sysctl tree. */ synaptics_sysctl_create_tree(sc); + /* + * The touchpad will have to be reinitialized after + * suspend/resume. + */ + sc->config |= PSM_CONFIG_HOOKRESUME | PSM_CONFIG_INITAFTERSUSPEND; + return (TRUE); } diff --git a/sys/dev/bce/if_bce.c b/sys/dev/bce/if_bce.c index 15dc633..ff78453 100644 --- a/sys/dev/bce/if_bce.c +++ b/sys/dev/bce/if_bce.c @@ -5114,7 +5114,7 @@ bce_free_tx_chain(struct bce_softc *sc) /* Unmap, unload, and free any mbufs still in the TX mbuf chain. */ for (i = 0; i < TOTAL_TX_BD; i++) { if (sc->tx_mbuf_ptr[i] != NULL) { - if (sc->tx_mbuf_map != NULL) + if (sc->tx_mbuf_map[i] != NULL) bus_dmamap_sync(sc->tx_mbuf_tag, sc->tx_mbuf_map[i], BUS_DMASYNC_POSTWRITE); m_freem(sc->tx_mbuf_ptr[i]); @@ -7408,7 +7408,6 @@ bce_stats_update(struct bce_softc *sc) (u_long) sc->stat_IfInMBUFDiscards + (u_long) sc->stat_Dot3StatsAlignmentErrors + (u_long) sc->stat_Dot3StatsFCSErrors + - (u_long) sc->stat_IfInFramesL2FilterDiscards + (u_long) sc->stat_IfInRuleCheckerDiscards + (u_long) sc->stat_IfInFTQDiscards + (u_long) sc->com_no_buffers; diff --git a/sys/dev/cxgb/common/cxgb_ael1002.c b/sys/dev/cxgb/common/cxgb_ael1002.c index 55c6421..97d4419 100644 --- a/sys/dev/cxgb/common/cxgb_ael1002.c +++ b/sys/dev/cxgb/common/cxgb_ael1002.c @@ -71,6 +71,74 @@ struct reg_val { unsigned short set_bits; }; +static int ael2005_i2c_rd(struct cphy *phy, int dev_addr, int word_addr); + +static int get_module_type (struct cphy *phy, int hint) +{ + int v; + + v = hint ? hint : ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 0); + if (v < 0) + return v; + + if (v == 0x3) { + /* SFP: see SFF-8472 for below */ + v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 3); + if (v < 0) + return v; + + if (v == 0x1) + return phy_modtype_twinax; + if (v == 0x10) + return phy_modtype_sr; + if (v == 0x20) + return phy_modtype_lr; + if (v == 0x40) + return phy_modtype_lrm; + + v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 6); + if (v < 0) + return v; + if (v != 4) + return phy_modtype_unknown; + + v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 10); + if (v < 0) + return v; + + if (v & 0x80) { + v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 0x12); + if (v < 0) + return v; + return v > 10 ? phy_modtype_twinax_long : + phy_modtype_twinax; + } + } else if (v == 0x6) { + /* XFP: See INF-8077i for details. */ + + v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 127); + if (v < 0) + return v; + + if (v != 1) { + /* XXX: set page select to table 1 yourself */ + return phy_modtype_unknown; + } + + v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 131); + if (v < 0) + return v; + if (v == 0x10) + return phy_modtype_lrm; + if (v == 0x40) + return phy_modtype_lr; + if (v == 0x80) + return phy_modtype_sr; + } + + return phy_modtype_unknown; +} + static int set_phy_regs(struct cphy *phy, const struct reg_val *rv) { int err; @@ -107,6 +175,18 @@ static int ael1002_power_down(struct cphy *phy, int enable) return err; } +static int ael1002_get_module_type(struct cphy *phy, int delay_ms) +{ + int v; + + if (delay_ms) + msleep(delay_ms); + + v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 0); + + return v == -ETIMEDOUT ? phy_modtype_none : get_module_type(phy, v); +} + static int ael1002_reset(struct cphy *phy, int wait) { int err; @@ -119,6 +199,11 @@ static int ael1002_reset(struct cphy *phy, int wait) (err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, AEL1002_LB_EN, 0, 1 << 5))) return err; + + err = ael1002_get_module_type(phy, 300); + if (err >= 0) + phy->modtype = err; + return 0; } @@ -182,10 +267,17 @@ static struct cphy_ops ael1002_ops = { int t3_ael1002_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr, const struct mdio_ops *mdio_ops) { + int err; + cphy_init(phy, adapter, phy_addr, &ael1002_ops, mdio_ops, SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE, "10GBASE-R"); ael100x_txon(phy); + + err = ael1002_get_module_type(phy, 0); + if (err >= 0) + phy->modtype = err; + return 0; } @@ -983,7 +1075,7 @@ static int ael2005_i2c_rd(struct cphy *phy, int dev_addr, int word_addr) return -ETIMEDOUT; } -static int get_module_type(struct cphy *phy, int delay_ms) +static int ael2005_get_module_type(struct cphy *phy, int delay_ms) { int v; unsigned int stat; @@ -998,36 +1090,8 @@ static int get_module_type(struct cphy *phy, int delay_ms) if (delay_ms) msleep(delay_ms); - /* see SFF-8472 for below */ - v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 3); - if (v < 0) - return v; - - if (v == 0x10) - return phy_modtype_sr; - if (v == 0x20) - return phy_modtype_lr; - if (v == 0x40) - return phy_modtype_lrm; - - v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 6); - if (v < 0) - return v; - if (v != 4) - goto unknown; - - v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 10); - if (v < 0) - return v; + return get_module_type(phy, 0); - if (v & 0x80) { - v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 0x12); - if (v < 0) - return v; - return v > 10 ? phy_modtype_twinax_long : phy_modtype_twinax; - } -unknown: - return phy_modtype_unknown; } static int ael2005_intr_enable(struct cphy *phy) @@ -1084,7 +1148,7 @@ static int ael2005_reset(struct cphy *phy, int wait) msleep(50); - err = get_module_type(phy, 0); + err = ael2005_get_module_type(phy, 0); if (err < 0) return err; phy->modtype = (u8)err; @@ -1122,7 +1186,7 @@ static int ael2005_intr_handler(struct cphy *phy) return ret; /* modules have max 300 ms init time after hot plug */ - ret = get_module_type(phy, 300); + ret = ael2005_get_module_type(phy, 300); if (ret < 0) return ret; @@ -1176,10 +1240,16 @@ static struct cphy_ops ael2005_ops = { int t3_ael2005_phy_prep(struct cphy *phy, adapter_t *adapter, int phy_addr, const struct mdio_ops *mdio_ops) { + int err; cphy_init(phy, adapter, phy_addr, &ael2005_ops, mdio_ops, SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE | SUPPORTED_IRQ, "10GBASE-R"); msleep(125); + + err = ael2005_get_module_type(phy, 0); + if (err >= 0) + phy->modtype = err; + return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, AEL_OPT_SETTINGS, 0, 1 << 5); } diff --git a/sys/dev/cxgb/cxgb_main.c b/sys/dev/cxgb/cxgb_main.c index 2cbd801..90df817 100644 --- a/sys/dev/cxgb/cxgb_main.c +++ b/sys/dev/cxgb/cxgb_main.c @@ -90,6 +90,7 @@ static void cxgb_stop_locked(struct port_info *); static void cxgb_set_rxmode(struct port_info *); static int cxgb_ioctl(struct ifnet *, unsigned long, caddr_t); static int cxgb_media_change(struct ifnet *); +static int cxgb_ifm_type(int); static void cxgb_media_status(struct ifnet *, struct ifmediareq *); static int setup_sge_qsets(adapter_t *); static void cxgb_async_intr(void *); @@ -976,7 +977,7 @@ cxgb_port_attach(device_t dev) } else if (!strcmp(p->phy.desc, "10GBASE-SR")) { media_flags = IFM_ETHER | IFM_10G_SR | IFM_FDX; } else if (!strcmp(p->phy.desc, "10GBASE-R")) { - media_flags = IFM_ETHER | IFM_10G_LR | IFM_FDX; + media_flags = cxgb_ifm_type(p->phy.modtype); } else if (!strcmp(p->phy.desc, "10/100/1000BASE-T")) { ifmedia_add(&p->media, IFM_ETHER | IFM_10_T, 0, NULL); ifmedia_add(&p->media, IFM_ETHER | IFM_10_T | IFM_FDX, @@ -992,6 +993,9 @@ cxgb_port_attach(device_t dev) /* * XXX: This is not very accurate. Fix when common code * returns more specific value - eg 1000BASE-SX, LX, etc. + * + * XXX: In the meantime, don't lie. Consider setting IFM_AUTO + * instead of SX. */ media_flags = IFM_ETHER | IFM_1000_SX | IFM_FDX; } else { @@ -999,7 +1003,13 @@ cxgb_port_attach(device_t dev) return (ENXIO); } if (media_flags) { - ifmedia_add(&p->media, media_flags, 0, NULL); + /* + * Note the modtype on which we based our flags. If modtype + * changes, we'll redo the ifmedia for this ifp. modtype may + * change when transceivers are plugged in/out, and in other + * situations. + */ + ifmedia_add(&p->media, media_flags, p->phy.modtype, NULL); ifmedia_set(&p->media, media_flags); } else { ifmedia_add(&p->media, IFM_ETHER | IFM_AUTO, 0, NULL); @@ -1827,7 +1837,7 @@ cxgb_init_locked(struct port_info *p) cxgb_link_start(p); t3_link_changed(sc, p->port_id); #endif - ifp->if_baudrate = p->link_config.speed * 1000000; + ifp->if_baudrate = IF_Mbps(p->link_config.speed); device_printf(sc->dev, "enabling interrupts on port=%d\n", p->port_id); t3_port_intr_enable(sc, p->port_id); @@ -1990,7 +2000,9 @@ cxgb_ioctl(struct ifnet *ifp, unsigned long command, caddr_t data) break; case SIOCSIFMEDIA: case SIOCGIFMEDIA: + PORT_LOCK(p); error = ifmedia_ioctl(ifp, ifr, &p->media, command); + PORT_UNLOCK(p); break; case SIOCSIFCAP: PORT_LOCK(p); @@ -2066,10 +2078,64 @@ cxgb_media_change(struct ifnet *ifp) return (ENXIO); } +/* + * Translates from phy->modtype to IFM_TYPE. + */ +static int +cxgb_ifm_type(int phymod) +{ + int rc = IFM_ETHER | IFM_FDX; + + switch (phymod) { + case phy_modtype_sr: + rc |= IFM_10G_SR; + break; + case phy_modtype_lr: + rc |= IFM_10G_LR; + break; + case phy_modtype_lrm: +#ifdef IFM_10G_LRM + rc |= IFM_10G_LRM; +#endif + break; + case phy_modtype_twinax: +#ifdef IFM_10G_TWINAX + rc |= IFM_10G_TWINAX; +#endif + break; + case phy_modtype_twinax_long: +#ifdef IFM_10G_TWINAX_LONG + rc |= IFM_10G_TWINAX_LONG; +#endif + break; + case phy_modtype_none: + rc = IFM_ETHER | IFM_NONE; + break; + case phy_modtype_unknown: + break; + } + + return (rc); +} + static void cxgb_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) { struct port_info *p = ifp->if_softc; + struct ifmedia_entry *cur = p->media.ifm_cur; + int m; + + if (cur->ifm_data != p->phy.modtype) { + /* p->media about to be rebuilt, must hold lock */ + PORT_LOCK_ASSERT_OWNED(p); + + m = cxgb_ifm_type(p->phy.modtype); + ifmedia_removeall(&p->media); + ifmedia_add(&p->media, m, p->phy.modtype, NULL); + ifmedia_set(&p->media, m); + cur = p->media.ifm_cur; /* ifmedia_set modified ifm_cur */ + ifmr->ifm_current = m; + } ifmr->ifm_status = IFM_AVALID; ifmr->ifm_active = IFM_ETHER; @@ -2089,6 +2155,9 @@ cxgb_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) case 1000: ifmr->ifm_active |= IFM_1000_T; break; + case 10000: + ifmr->ifm_active |= IFM_SUBTYPE(cur->ifm_media); + break; } if (p->link_config.duplex) @@ -2140,7 +2209,7 @@ check_link_status(adapter_t *sc) if (!(p->phy.caps & SUPPORTED_IRQ)) t3_link_changed(sc, i); - p->ifp->if_baudrate = p->link_config.speed * 1000000; + p->ifp->if_baudrate = IF_Mbps(p->link_config.speed); } } diff --git a/sys/dev/cxgb/ulp/tom/cxgb_cpl_io.c b/sys/dev/cxgb/ulp/tom/cxgb_cpl_io.c index 334f315..f11aaf0 100644 --- a/sys/dev/cxgb/ulp/tom/cxgb_cpl_io.c +++ b/sys/dev/cxgb/ulp/tom/cxgb_cpl_io.c @@ -3269,8 +3269,6 @@ syncache_add_accept_req(struct cpl_pass_accept_req *req, struct socket *lso, str toep->tp_iss = toep->tp_delack_seq = toep->tp_rcv_wup = toep->tp_copied_seq = rcv_isn + 1; - - inc.inc_isipv6 = 0; inc.inc_len = 0; inc.inc_faddr.s_addr = req->peer_ip; inc.inc_laddr.s_addr = req->local_ip; @@ -3610,7 +3608,6 @@ syncache_expand_establish_req(struct cpl_pass_establish *req, struct socket **so th.th_seq = req->rcv_isn; th.th_flags = TH_ACK; - inc.inc_isipv6 = 0; inc.inc_len = 0; inc.inc_faddr.s_addr = req->peer_ip; inc.inc_laddr.s_addr = req->local_ip; diff --git a/sys/dev/cxgb/ulp/tom/cxgb_l2t.c b/sys/dev/cxgb/ulp/tom/cxgb_l2t.c index 67856e6..2484923 100644 --- a/sys/dev/cxgb/ulp/tom/cxgb_l2t.c +++ b/sys/dev/cxgb/ulp/tom/cxgb_l2t.c @@ -93,15 +93,15 @@ arp_hash(u32 key, int ifindex, const struct l2t_data *d) } static inline void -neigh_replace(struct l2t_entry *e, struct rtentry *rt) +neigh_replace(struct l2t_entry *e, struct llentry *neigh) { - RT_LOCK(rt); - RT_ADDREF(rt); - RT_UNLOCK(rt); + LLE_WLOCK(neigh); + LLE_ADDREF(neigh); + LLE_WUNLOCK(neigh); if (e->neigh) - RTFREE(e->neigh); - e->neigh = rt; + LLE_FREE(e->neigh); + e->neigh = neigh; } /* @@ -164,7 +164,7 @@ arpq_enqueue(struct l2t_entry *e, struct mbuf *m) int t3_l2t_send_slow(struct t3cdev *dev, struct mbuf *m, struct l2t_entry *e) { - struct rtentry *rt = e->neigh; + struct llentry *lle = e->neigh; struct sockaddr_in sin; bzero(&sin, sizeof(struct sockaddr_in)); @@ -177,7 +177,7 @@ again: switch (e->state) { case L2T_STATE_STALE: /* entry is stale, kick off revalidation */ arpresolve(rt->rt_ifp, rt, NULL, - (struct sockaddr *)&sin, e->dmac); + (struct sockaddr *)&sin, e->dmac, &lle); mtx_lock(&e->lock); if (e->state == L2T_STATE_STALE) e->state = L2T_STATE_VALID; @@ -201,7 +201,7 @@ again: * entries when there's no memory. */ if (arpresolve(rt->rt_ifp, rt, NULL, - (struct sockaddr *)&sin, e->dmac) == 0) { + (struct sockaddr *)&sin, e->dmac, &lle) == 0) { CTR6(KTR_CXGB, "mac=%x:%x:%x:%x:%x:%x\n", e->dmac[0], e->dmac[1], e->dmac[2], e->dmac[3], e->dmac[4], e->dmac[5]); @@ -222,12 +222,12 @@ again: void t3_l2t_send_event(struct t3cdev *dev, struct l2t_entry *e) { - struct rtentry *rt; struct mbuf *m0; struct sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_len = sizeof(struct sockaddr_in); sin.sin_addr.s_addr = e->addr; + struct llentry *lle; if ((m0 = m_gethdr(M_NOWAIT, MT_DATA)) == NULL) return; @@ -237,7 +237,7 @@ again: switch (e->state) { case L2T_STATE_STALE: /* entry is stale, kick off revalidation */ arpresolve(rt->rt_ifp, rt, NULL, - (struct sockaddr *)&sin, e->dmac); + (struct sockaddr *)&sin, e->dmac, &lle); mtx_lock(&e->lock); if (e->state == L2T_STATE_STALE) { e->state = L2T_STATE_VALID; @@ -263,7 +263,7 @@ again: * entries when there's no memory. */ arpresolve(rt->rt_ifp, rt, NULL, - (struct sockaddr *)&sin, e->dmac); + (struct sockaddr *)&sin, e->dmac, &lle); } return; @@ -321,18 +321,18 @@ found: void t3_l2e_free(struct l2t_data *d, struct l2t_entry *e) { - struct rtentry *rt = NULL; - + struct llentry *lle; + mtx_lock(&e->lock); if (atomic_load_acq_int(&e->refcnt) == 0) { /* hasn't been recycled */ - rt = e->neigh; + lle = e->neigh; e->neigh = NULL; } mtx_unlock(&e->lock); atomic_add_int(&d->nfree, 1); - if (rt) - RTFREE(rt); + if (lle) + LLE_FREE(lle); } @@ -341,11 +341,8 @@ t3_l2e_free(struct l2t_data *d, struct l2t_entry *e) * Must be called with softirqs disabled. */ static inline void -reuse_entry(struct l2t_entry *e, struct rtentry *neigh) +reuse_entry(struct l2t_entry *e, struct llentry *neigh) { - struct llinfo_arp *la; - - la = (struct llinfo_arp *)neigh->rt_llinfo; mtx_lock(&e->lock); /* avoid race with t3_l2t_free */ if (neigh != e->neigh) @@ -362,13 +359,13 @@ reuse_entry(struct l2t_entry *e, struct rtentry *neigh) } struct l2t_entry * -t3_l2t_get(struct t3cdev *dev, struct rtentry *neigh, struct ifnet *ifp, +t3_l2t_get(struct t3cdev *dev, struct llentry *neigh, struct ifnet *ifp, struct sockaddr *sa) { struct l2t_entry *e; struct l2t_data *d = L2DATA(dev); u32 addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; - int ifidx = neigh->rt_ifp->if_index; + int ifidx = ifp->if_index; int hash = arp_hash(addr, ifidx, d); unsigned int smt_idx = ((struct port_info *)ifp->if_softc)->port_id; @@ -448,20 +445,19 @@ handle_failed_resolution(struct t3cdev *dev, struct mbuf *arpq) } void -t3_l2t_update(struct t3cdev *dev, struct rtentry *neigh, +t3_l2t_update(struct t3cdev *dev, struct llentry *neigh, uint8_t *enaddr, struct sockaddr *sa) { struct l2t_entry *e; struct mbuf *arpq = NULL; struct l2t_data *d = L2DATA(dev); u32 addr = *(u32 *) &((struct sockaddr_in *)sa)->sin_addr; - int ifidx = neigh->rt_ifp->if_index; int hash = arp_hash(addr, ifidx, d); struct llinfo_arp *la; rw_rlock(&d->lock); for (e = d->l2tab[hash].first; e; e = e->next) - if (e->addr == addr && e->ifindex == ifidx) { + if (e->addr == addr) { mtx_lock(&e->lock); goto found; } diff --git a/sys/dev/cxgb/ulp/tom/cxgb_l2t.h b/sys/dev/cxgb/ulp/tom/cxgb_l2t.h index 1d547d3..308ba66 100644 --- a/sys/dev/cxgb/ulp/tom/cxgb_l2t.h +++ b/sys/dev/cxgb/ulp/tom/cxgb_l2t.h @@ -68,7 +68,7 @@ struct l2t_entry { int ifindex; /* neighbor's net_device's ifindex */ uint16_t smt_idx; /* SMT index */ uint16_t vlan; /* VLAN TCI (id: bits 0-11, prio: 13-15 */ - struct rtentry *neigh; /* associated neighbour */ + struct llentry *neigh; /* associated neighbour */ struct l2t_entry *first; /* start of hash chain */ struct l2t_entry *next; /* next l2t_entry on chain */ struct mbuf *arpq_head; /* queue of packets awaiting resolution */ diff --git a/sys/dev/drm/drmP.h b/sys/dev/drm/drmP.h index eb91214..25a3fa8 100644 --- a/sys/dev/drm/drmP.h +++ b/sys/dev/drm/drmP.h @@ -87,6 +87,7 @@ struct drm_file; #include <sys/agpio.h> #include <sys/mutex.h> #include <dev/pci/pcivar.h> +#include <dev/pci/pcireg.h> #include <sys/selinfo.h> #include <sys/bus.h> @@ -211,15 +212,6 @@ enum { #define DRM_MTRR_WC MDF_WRITECOMBINE #define jiffies ticks -/* Capabilities taken from src/sys/dev/pci/pcireg.h. */ -#ifndef PCIY_AGP -#define PCIY_AGP 0x02 -#endif - -#ifndef PCIY_EXPRESS -#define PCIY_EXPRESS 0x10 -#endif - typedef unsigned long dma_addr_t; typedef u_int64_t u64; typedef u_int32_t u32; @@ -473,11 +465,13 @@ typedef struct drm_agp_head { } drm_agp_head_t; typedef struct drm_sg_mem { - unsigned long handle; - void *virtual; - int pages; - dma_addr_t *busaddr; - drm_dma_handle_t *dmah; /* Handle to PCI memory for ATI PCIGART table */ + unsigned long handle; + void *virtual; + int pages; + dma_addr_t *busaddr; + struct drm_dma_handle *sg_dmah; /* Handle for sg_pages */ + struct drm_dma_handle *dmah; /* Handle to PCI memory */ + /* for ATI PCIGART table */ } drm_sg_mem_t; typedef TAILQ_HEAD(drm_map_list, drm_local_map) drm_map_list_t; diff --git a/sys/dev/drm/drm_drv.c b/sys/dev/drm/drm_drv.c index 8a0cdf4..63be19b 100644 --- a/sys/dev/drm/drm_drv.c +++ b/sys/dev/drm/drm_drv.c @@ -152,6 +152,10 @@ int drm_probe(device_t dev, drm_pci_id_list_t *idlist) device = pci_get_device(dev); #endif + if (pci_get_class(dev) != PCIC_DISPLAY + || pci_get_subclass(dev) != PCIS_DISPLAY_VGA) + return ENXIO; + id_entry = drm_find_description(vendor, device, idlist); if (id_entry != NULL) { device_set_desc(dev, id_entry->name); diff --git a/sys/dev/drm/drm_scatter.c b/sys/dev/drm/drm_scatter.c index c94976a..bf0cbeb 100644 --- a/sys/dev/drm/drm_scatter.c +++ b/sys/dev/drm/drm_scatter.c @@ -39,20 +39,16 @@ __FBSDID("$FreeBSD$"); #include "dev/drm/drmP.h" -#define DEBUG_SCATTER 0 +static void drm_sg_alloc_cb(void *arg, bus_dma_segment_t *segs, + int nsegs, int error); -void drm_sg_cleanup(drm_sg_mem_t *entry) +int +drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather *request) { - free((void *)entry->handle, DRM_MEM_PAGES); - free(entry->busaddr, DRM_MEM_PAGES); - free(entry, DRM_MEM_SGLISTS); -} - -int drm_sg_alloc(struct drm_device * dev, struct drm_scatter_gather * request) -{ - drm_sg_mem_t *entry; + struct drm_sg_mem *entry; + struct drm_dma_handle *dmah; unsigned long pages; - int i; + int ret; if (dev->sg) return EINVAL; @@ -69,21 +65,56 @@ int drm_sg_alloc(struct drm_device * dev, struct drm_scatter_gather * request) entry->busaddr = malloc(pages * sizeof(*entry->busaddr), DRM_MEM_PAGES, M_WAITOK | M_ZERO); if (!entry->busaddr) { - drm_sg_cleanup(entry); + free(entry, DRM_MEM_SGLISTS); return ENOMEM; } - entry->handle = (long)malloc(pages << PAGE_SHIFT, DRM_MEM_PAGES, - M_WAITOK | M_ZERO); - if (entry->handle == 0) { - drm_sg_cleanup(entry); + dmah = malloc(sizeof(struct drm_dma_handle), DRM_MEM_DMA, + M_ZERO | M_NOWAIT); + if (dmah == NULL) { + free(entry->busaddr, DRM_MEM_PAGES); + free(entry, DRM_MEM_SGLISTS); + return ENOMEM; + } + + ret = bus_dma_tag_create(NULL, PAGE_SIZE, 0, /* tag, align, boundary */ + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, /* lowaddr, highaddr */ + NULL, NULL, /* filtfunc, filtfuncargs */ + request->size, pages, /* maxsize, nsegs */ + PAGE_SIZE, 0, /* maxsegsize, flags */ + NULL, NULL, /* lockfunc, lockfuncargs */ + &dmah->tag); + if (ret != 0) { + free(dmah, DRM_MEM_DMA); + free(entry->busaddr, DRM_MEM_PAGES); + free(entry, DRM_MEM_SGLISTS); return ENOMEM; } - for (i = 0; i < pages; i++) { - entry->busaddr[i] = vtophys(entry->handle + i * PAGE_SIZE); + ret = bus_dmamem_alloc(dmah->tag, &dmah->vaddr, + BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_NOCACHE, &dmah->map); + if (ret != 0) { + bus_dma_tag_destroy(dmah->tag); + free(dmah, DRM_MEM_DMA); + free(entry->busaddr, DRM_MEM_PAGES); + free(entry, DRM_MEM_SGLISTS); + return ENOMEM; } + ret = bus_dmamap_load(dmah->tag, dmah->map, dmah->vaddr, + request->size, drm_sg_alloc_cb, entry, 0); + if (ret != 0) { + bus_dmamem_free(dmah->tag, dmah->vaddr, dmah->map); + bus_dma_tag_destroy(dmah->tag); + free(dmah, DRM_MEM_DMA); + free(entry->busaddr, DRM_MEM_PAGES); + free(entry, DRM_MEM_SGLISTS); + return ENOMEM; + } + + entry->sg_dmah = dmah; + entry->handle = (unsigned long)dmah->vaddr; + DRM_DEBUG("sg alloc handle = %08lx\n", entry->handle); entry->virtual = (void *)entry->handle; @@ -101,22 +132,49 @@ int drm_sg_alloc(struct drm_device * dev, struct drm_scatter_gather * request) return 0; } -int drm_sg_alloc_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) +static void +drm_sg_alloc_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) +{ + struct drm_sg_mem *entry = arg; + int i; + + if (error != 0) + return; + + for(i = 0 ; i < nsegs ; i++) { + entry->busaddr[i] = segs[i].ds_addr; + } +} + +int +drm_sg_alloc_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) { struct drm_scatter_gather *request = data; - int ret; - DRM_DEBUG("%s\n", __FUNCTION__); + DRM_DEBUG("\n"); + + return drm_sg_alloc(dev, request); +} - ret = drm_sg_alloc(dev, request); - return ret; +void +drm_sg_cleanup(struct drm_sg_mem *entry) +{ + struct drm_dma_handle *dmah = entry->sg_dmah; + + bus_dmamap_unload(dmah->tag, dmah->map); + bus_dmamem_free(dmah->tag, dmah->vaddr, dmah->map); + bus_dma_tag_destroy(dmah->tag); + free(dmah, DRM_MEM_DMA); + free(entry->busaddr, DRM_MEM_PAGES); + free(entry, DRM_MEM_SGLISTS); } -int drm_sg_free(struct drm_device *dev, void *data, struct drm_file *file_priv) +int +drm_sg_free(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_scatter_gather *request = data; - drm_sg_mem_t *entry; + struct drm_sg_mem *entry; DRM_LOCK(); entry = dev->sg; diff --git a/sys/dev/fxp/if_fxp.c b/sys/dev/fxp/if_fxp.c index f79282e..9a6851c 100644 --- a/sys/dev/fxp/if_fxp.c +++ b/sys/dev/fxp/if_fxp.c @@ -1540,8 +1540,8 @@ fxp_encap(struct fxp_softc *sc, struct mbuf **m_head) * the chip is an 82550/82551 or not. */ if (sc->flags & FXP_FLAG_EXT_RFA) { - cbp->tbd[i + 2].tb_addr = htole32(segs[i].ds_addr); - cbp->tbd[i + 2].tb_size = htole32(segs[i].ds_len); + cbp->tbd[i + 1].tb_addr = htole32(segs[i].ds_addr); + cbp->tbd[i + 1].tb_size = htole32(segs[i].ds_len); } else { cbp->tbd[i].tb_addr = htole32(segs[i].ds_addr); cbp->tbd[i].tb_size = htole32(segs[i].ds_len); @@ -1550,13 +1550,13 @@ fxp_encap(struct fxp_softc *sc, struct mbuf **m_head) if (sc->flags & FXP_FLAG_EXT_RFA) { /* Configure dynamic TBD for 82550/82551. */ cbp->tbd_number = 0xFF; - cbp->tbd[nseg + 1].tb_size |= htole32(0x8000); + cbp->tbd[nseg].tb_size |= htole32(0x8000); } else cbp->tbd_number = nseg; /* Configure TSO. */ if (m->m_pkthdr.csum_flags & CSUM_TSO) { cbp->tbd[-1].tb_size = htole32(m->m_pkthdr.tso_segsz << 16); - cbp->tbd[1].tb_size = htole32(tcp_payload << 16); + cbp->tbd[1].tb_size |= htole32(tcp_payload << 16); cbp->ipcb_ip_schedule |= FXP_IPCB_LARGESEND_ENABLE | FXP_IPCB_IP_CHECKSUM_ENABLE | FXP_IPCB_TCP_PACKET | diff --git a/sys/dev/hwpmc/hwpmc_core.c b/sys/dev/hwpmc/hwpmc_core.c index c34a969..8d17679 100644 --- a/sys/dev/hwpmc/hwpmc_core.c +++ b/sys/dev/hwpmc/hwpmc_core.c @@ -1491,17 +1491,18 @@ core_intr(int cpu, struct trapframe *tf) PMCDBG(MDP,INT, 1, "cpu=%d tf=0x%p um=%d", cpu, (void *) tf, TRAPF_USERMODE(tf)); + found_interrupt = 0; cc = core_pcpu[cpu]; for (ri = 0; ri < core_iap_npmc; ri++) { - if (!iap_pmc_has_overflowed(ri)) - continue; - if ((pm = cc->pc_corepmcs[ri].phw_pmc) == NULL || !PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) continue; + if (!iap_pmc_has_overflowed(ri)) + continue; + found_interrupt = 1; if (pm->pm_state != PMC_STATE_RUNNING) @@ -1560,7 +1561,9 @@ core2_intr(int cpu, struct trapframe *tf) PMCDBG(MDP,INT, 1, "cpu=%d intrstatus=%jx", cpu, (uintmax_t) intrstatus); + found_interrupt = 0; cc = core_pcpu[cpu]; + KASSERT(cc != NULL, ("[core,%d] null pcpu", __LINE__)); cc->pc_globalctrl &= ~intrenable; @@ -1574,7 +1577,6 @@ core2_intr(int cpu, struct trapframe *tf) IA_GLOBAL_STATUS_FLAG_OVFBUF | IA_GLOBAL_STATUS_FLAG_CONDCHG); - /* * Look for interrupts from fixed function PMCs. */ @@ -1634,9 +1636,6 @@ core2_intr(int cpu, struct trapframe *tf) wrmsr(IAP_PMC0 + n, v); } - KASSERT(found_interrupt, - ("[core,%d] no interrupting PMCs were found", __LINE__)); - /* * Reenable all non-stalled PMCs. */ diff --git a/sys/dev/hwpmc/hwpmc_logging.c b/sys/dev/hwpmc/hwpmc_logging.c index cef1453..6612203 100644 --- a/sys/dev/hwpmc/hwpmc_logging.c +++ b/sys/dev/hwpmc/hwpmc_logging.c @@ -199,7 +199,7 @@ pmclog_get_buffer(struct pmc_owner *po) mtx_assert(&po->po_mtx, MA_OWNED); KASSERT(po->po_curbuf == NULL, - ("[pmc,%d] po=%p current buffer still valid", __LINE__, po)); + ("[pmclog,%d] po=%p current buffer still valid", __LINE__, po)); mtx_lock_spin(&pmc_bufferlist_mtx); if ((plb = TAILQ_FIRST(&pmc_bufferlist)) != NULL) @@ -212,7 +212,7 @@ pmclog_get_buffer(struct pmc_owner *po) if (plb) KASSERT(plb->plb_ptr == plb->plb_base && plb->plb_base < plb->plb_fence, - ("[pmc,%d] po=%p buffer invariants: ptr=%p " + ("[pmclog,%d] po=%p buffer invariants: ptr=%p " "base=%p fence=%p", __LINE__, po, plb->plb_ptr, plb->plb_base, plb->plb_fence)); #endif @@ -224,7 +224,7 @@ pmclog_get_buffer(struct pmc_owner *po) if (plb == NULL) atomic_add_int(&pmc_stats.pm_buffer_requests_failed, 1); - return plb ? 0 : ENOMEM; + return (plb ? 0 : ENOMEM); } /* @@ -256,7 +256,7 @@ pmclog_loop(void *arg) PMCDBG(LOG,INI,1, "po=%p kt=%p", po, po->po_kthread); KASSERT(po->po_kthread == curthread->td_proc, - ("[pmc,%d] proc mismatch po=%p po/kt=%p curproc=%p", __LINE__, + ("[pmclog,%d] proc mismatch po=%p po/kt=%p curproc=%p", __LINE__, po, po->po_kthread, curthread->td_proc)); lb = NULL; @@ -381,10 +381,10 @@ static void pmclog_release(struct pmc_owner *po) { KASSERT(po->po_curbuf->plb_ptr >= po->po_curbuf->plb_base, - ("[pmc,%d] buffer invariants po=%p ptr=%p base=%p", __LINE__, + ("[pmclog,%d] buffer invariants po=%p ptr=%p base=%p", __LINE__, po, po->po_curbuf->plb_ptr, po->po_curbuf->plb_base)); KASSERT(po->po_curbuf->plb_ptr <= po->po_curbuf->plb_fence, - ("[pmc,%d] buffer invariants po=%p ptr=%p fenc=%p", __LINE__, + ("[pmclog,%d] buffer invariants po=%p ptr=%p fenc=%p", __LINE__, po, po->po_curbuf->plb_ptr, po->po_curbuf->plb_fence)); /* schedule an I/O if we've filled a buffer */ @@ -423,15 +423,15 @@ pmclog_reserve(struct pmc_owner *po, int length) if (po->po_curbuf == NULL) if (pmclog_get_buffer(po) != 0) { mtx_unlock_spin(&po->po_mtx); - return NULL; + return (NULL); } KASSERT(po->po_curbuf != NULL, - ("[pmc,%d] po=%p no current buffer", __LINE__, po)); + ("[pmclog,%d] po=%p no current buffer", __LINE__, po)); KASSERT(po->po_curbuf->plb_ptr >= po->po_curbuf->plb_base && po->po_curbuf->plb_ptr <= po->po_curbuf->plb_fence, - ("[pmc,%d] po=%p buffer invariants: ptr=%p base=%p fence=%p", + ("[pmclog,%d] po=%p buffer invariants: ptr=%p base=%p fence=%p", __LINE__, po, po->po_curbuf->plb_ptr, po->po_curbuf->plb_base, po->po_curbuf->plb_fence)); @@ -439,7 +439,7 @@ pmclog_reserve(struct pmc_owner *po, int length) newptr = oldptr + length; KASSERT(oldptr != (uintptr_t) NULL, - ("[pmc,%d] po=%p Null log buffer pointer", __LINE__, po)); + ("[pmclog,%d] po=%p Null log buffer pointer", __LINE__, po)); /* * If we have space in the current buffer, return a pointer to @@ -458,18 +458,18 @@ pmclog_reserve(struct pmc_owner *po, int length) if (pmclog_get_buffer(po) != 0) { mtx_unlock_spin(&po->po_mtx); - return NULL; + return (NULL); } KASSERT(po->po_curbuf != NULL, - ("[pmc,%d] po=%p no current buffer", __LINE__, po)); + ("[pmclog,%d] po=%p no current buffer", __LINE__, po)); KASSERT(po->po_curbuf->plb_ptr != NULL, - ("[pmc,%d] null return from pmc_get_log_buffer", __LINE__)); + ("[pmclog,%d] null return from pmc_get_log_buffer", __LINE__)); KASSERT(po->po_curbuf->plb_ptr == po->po_curbuf->plb_base && po->po_curbuf->plb_ptr <= po->po_curbuf->plb_fence, - ("[pmc,%d] po=%p buffer invariants: ptr=%p base=%p fence=%p", + ("[pmclog,%d] po=%p buffer invariants: ptr=%p base=%p fence=%p", __LINE__, po, po->po_curbuf->plb_ptr, po->po_curbuf->plb_base, po->po_curbuf->plb_fence)); @@ -481,7 +481,7 @@ pmclog_reserve(struct pmc_owner *po, int length) getnanotime(&ts); /* fill in the timestamp */ *lh++ = ts.tv_sec & 0xFFFFFFFF; *lh++ = ts.tv_nsec & 0xFFFFFFF; - return (uint32_t *) oldptr; + return ((uint32_t *) oldptr); } /* @@ -494,13 +494,13 @@ static void pmclog_schedule_io(struct pmc_owner *po) { KASSERT(po->po_curbuf != NULL, - ("[pmc,%d] schedule_io with null buffer po=%p", __LINE__, po)); + ("[pmclog,%d] schedule_io with null buffer po=%p", __LINE__, po)); KASSERT(po->po_curbuf->plb_ptr >= po->po_curbuf->plb_base, - ("[pmc,%d] buffer invariants po=%p ptr=%p base=%p", __LINE__, + ("[pmclog,%d] buffer invariants po=%p ptr=%p base=%p", __LINE__, po, po->po_curbuf->plb_ptr, po->po_curbuf->plb_base)); KASSERT(po->po_curbuf->plb_ptr <= po->po_curbuf->plb_fence, - ("[pmc,%d] buffer invariants po=%p ptr=%p fenc=%p", __LINE__, + ("[pmclog,%d] buffer invariants po=%p ptr=%p fenc=%p", __LINE__, po, po->po_curbuf->plb_ptr, po->po_curbuf->plb_fence)); PMCDBG(LOG,SIO, 1, "po=%p", po); @@ -558,13 +558,13 @@ pmclog_configure_log(struct pmc_mdep *md, struct pmc_owner *po, int logfd) /* return EBUSY if a log file was already present */ if (po->po_flags & PMC_PO_OWNS_LOGFILE) - return EBUSY; + return (EBUSY); KASSERT(po->po_kthread == NULL, - ("[pmc,%d] po=%p kthread (%p) already present", __LINE__, po, + ("[pmclog,%d] po=%p kthread (%p) already present", __LINE__, po, po->po_kthread)); KASSERT(po->po_file == NULL, - ("[pmc,%d] po=%p file (%p) already present", __LINE__, po, + ("[pmclog,%d] po=%p file (%p) already present", __LINE__, po, po->po_file)); /* get a reference to the file state */ @@ -591,7 +591,7 @@ pmclog_configure_log(struct pmc_mdep *md, struct pmc_owner *po, int logfd) PMCLOG_EMIT32(md->pmd_cputype); PMCLOG_DESPATCH(po); - return 0; + return (0); error: /* shutdown the thread */ @@ -600,15 +600,15 @@ pmclog_configure_log(struct pmc_mdep *md, struct pmc_owner *po, int logfd) pmclog_stop_kthread(po); mtx_unlock(&pmc_kthread_mtx); - KASSERT(po->po_kthread == NULL, ("[pmc,%d] po=%p kthread not stopped", - __LINE__, po)); + KASSERT(po->po_kthread == NULL, ("[pmclog,%d] po=%p kthread not " + "stopped", __LINE__, po)); if (po->po_file) (void) fdrop(po->po_file, curthread); po->po_file = NULL; /* clear file and error state */ po->po_error = 0; - return error; + return (error); } @@ -626,12 +626,12 @@ pmclog_deconfigure_log(struct pmc_owner *po) PMCDBG(LOG,CFG,1, "de-config po=%p", po); if ((po->po_flags & PMC_PO_OWNS_LOGFILE) == 0) - return EINVAL; + return (EINVAL); KASSERT(po->po_sscount == 0, - ("[pmc,%d] po=%p still owning SS PMCs", __LINE__, po)); + ("[pmclog,%d] po=%p still owning SS PMCs", __LINE__, po)); KASSERT(po->po_file != NULL, - ("[pmc,%d] po=%p no log file", __LINE__, po)); + ("[pmclog,%d] po=%p no log file", __LINE__, po)); /* stop the kthread, this will reset the 'OWNS_LOGFILE' flag */ mtx_lock(&pmc_kthread_mtx); @@ -640,7 +640,7 @@ pmclog_deconfigure_log(struct pmc_owner *po) mtx_unlock(&pmc_kthread_mtx); KASSERT(po->po_kthread == NULL, - ("[pmc,%d] po=%p kthread not stopped", __LINE__, po)); + ("[pmclog,%d] po=%p kthread not stopped", __LINE__, po)); /* return all queued log buffers to the global pool */ while ((lb = TAILQ_FIRST(&po->po_logbuffers)) != NULL) { @@ -664,7 +664,7 @@ pmclog_deconfigure_log(struct pmc_owner *po) po->po_file = NULL; po->po_error = 0; - return error; + return (error); } /* @@ -683,7 +683,7 @@ pmclog_flush(struct pmc_owner *po) * return that. */ if (po->po_error) - return po->po_error; + return (po->po_error); error = 0; @@ -709,12 +709,14 @@ pmclog_flush(struct pmc_owner *po) po->po_flags |= PMC_PO_IN_FLUSH; /* ask for a wakeup */ error = msleep(po->po_kthread, &pmc_kthread_mtx, PWAIT, "pmcflush", 0); + if (error == 0) + error = po->po_error; } error: mtx_unlock(&pmc_kthread_mtx); - return error; + return (error); } @@ -948,7 +950,7 @@ pmclog_process_userlog(struct pmc_owner *po, struct pmc_op_writelog *wl) PMCLOG_DESPATCH(po); error: - return error; + return (error); } /* @@ -964,8 +966,8 @@ pmclog_initialize() struct pmclog_buffer *plb; if (pmclog_buffer_size <= 0) { - (void) printf("hwpmc: tunable logbuffersize=%d must be greater " - "than zero.\n", pmclog_buffer_size); + (void) printf("hwpmc: tunable logbuffersize=%d must be " + "greater than zero.\n", pmclog_buffer_size); pmclog_buffer_size = PMC_LOG_BUFFER_SIZE; } diff --git a/sys/dev/hwpmc/hwpmc_mod.c b/sys/dev/hwpmc/hwpmc_mod.c index a38921f..c239a69 100644 --- a/sys/dev/hwpmc/hwpmc_mod.c +++ b/sys/dev/hwpmc/hwpmc_mod.c @@ -1863,8 +1863,11 @@ pmc_hook_handler(struct thread *td, int function, void *arg) /* * Record a call chain. */ + KASSERT(td == curthread, ("[pmc,%d] td != curthread", + __LINE__)); pmc_capture_user_callchain(PCPU_GET(cpuid), (struct trapframe *) arg); + td->td_pflags &= ~TDP_CALLCHAIN; break; default: @@ -3794,30 +3797,28 @@ pmc_syscall_handler(struct thread *td, void *syscall_args) */ static void -pmc_post_callchain_ast(void) +pmc_post_callchain_callback(void) { struct thread *td; td = curthread; + KASSERT((td->td_pflags & TDP_CALLCHAIN) == 0, + ("[pmc,%d] thread %p already marked for callchain capture", + __LINE__, (void *) td)); + /* - * Mark this thread as needing processing in ast(). - * td->td_pflags will be safe to touch as the process was in - * user space when it was interrupted. + * Mark this thread as needing callchain capture. + * `td->td_pflags' will be safe to touch because this thread + * was in user space when it was interrupted. */ td->td_pflags |= TDP_CALLCHAIN; /* - * Again, since we've entered this function directly from - * userland, `td' is guaranteed to be not locked by this CPU, - * so its safe to try acquire the thread lock even though we - * are executing in an NMI context. We need to acquire this - * lock before touching `td_flags' because other CPUs may be - * in the process of touching this field. + * Don't let this thread migrate between CPUs until callchain + * capture completes. */ - thread_lock(td); - td->td_flags |= TDF_ASTPENDING; - thread_unlock(td); + sched_pin(); return; } @@ -3869,6 +3870,10 @@ pmc_process_interrupt(int cpu, struct pmc *pm, struct trapframe *tf, (int) (psb->ps_write - psb->ps_samples), (int) (psb->ps_read - psb->ps_samples)); + KASSERT(pm->pm_runcount >= 0, + ("[pmc,%d] pm=%p runcount %d", __LINE__, (void *) pm, + pm->pm_runcount)); + atomic_add_rel_32(&pm->pm_runcount, 1); /* hold onto PMC */ ps->ps_pmc = pm; if ((td = curthread) && td->td_proc) @@ -3876,6 +3881,7 @@ pmc_process_interrupt(int cpu, struct pmc *pm, struct trapframe *tf, else ps->ps_pid = -1; ps->ps_cpu = cpu; + ps->ps_td = td; ps->ps_flags = inuserspace ? PMC_CC_F_USERSPACE : 0; callchaindepth = (pm->pm_flags & PMC_F_CALLCHAIN) ? @@ -3893,7 +3899,7 @@ pmc_process_interrupt(int cpu, struct pmc *pm, struct trapframe *tf, pmc_save_kernel_callchain(ps->ps_pc, callchaindepth, tf); else { - pmc_post_callchain_ast(); + pmc_post_callchain_callback(); callchaindepth = PMC_SAMPLE_INUSE; } } @@ -3925,20 +3931,41 @@ pmc_capture_user_callchain(int cpu, struct trapframe *tf) { int i; struct pmc *pm; + struct thread *td; struct pmc_sample *ps; struct pmc_samplebuffer *psb; +#ifdef INVARIANTS + int ncallchains; +#endif + + sched_unpin(); /* Can migrate safely now. */ psb = pmc_pcpu[cpu]->pc_sb; + td = curthread; + + KASSERT(td->td_pflags & TDP_CALLCHAIN, + ("[pmc,%d] Retrieving callchain for thread that doesn't want it", + __LINE__)); + +#ifdef INVARIANTS + ncallchains = 0; +#endif /* * Iterate through all deferred callchain requests. */ - for (i = 0; i < pmc_nsamples; i++) { + ps = psb->ps_samples; + for (i = 0; i < pmc_nsamples; i++, ps++) { - ps = &psb->ps_samples[i]; if (ps->ps_nsamples != PMC_SAMPLE_INUSE) continue; + if (ps->ps_td != td) + continue; + + KASSERT(ps->ps_cpu == cpu, + ("[pmc,%d] cpu mismatch ps_cpu=%d pcpu=%d", __LINE__, + ps->ps_cpu, PCPU_GET(cpuid))); pm = ps->ps_pmc; @@ -3946,14 +3973,26 @@ pmc_capture_user_callchain(int cpu, struct trapframe *tf) ("[pmc,%d] Retrieving callchain for PMC that doesn't " "want it", __LINE__)); + KASSERT(pm->pm_runcount > 0, + ("[pmc,%d] runcount %d", __LINE__, pm->pm_runcount)); + /* * Retrieve the callchain and mark the sample buffer * as 'processable' by the timer tick sweep code. */ ps->ps_nsamples = pmc_save_user_callchain(ps->ps_pc, pmc_callchaindepth, tf); + +#ifdef INVARIANTS + ncallchains++; +#endif + } + KASSERT(ncallchains > 0, + ("[pmc,%d] cpu %d didn't find a sample to collect", __LINE__, + cpu)); + return; } @@ -3991,6 +4030,11 @@ pmc_process_samples(int cpu) } pm = ps->ps_pmc; + + KASSERT(pm->pm_runcount > 0, + ("[pmc,%d] pm=%p runcount %d", __LINE__, (void *) pm, + pm->pm_runcount)); + po = pm->pm_owner; KASSERT(PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)), diff --git a/sys/dev/isp/isp.c b/sys/dev/isp/isp.c index e22b7bf..1ad4e91 100644 --- a/sys/dev/isp/isp.c +++ b/sys/dev/isp/isp.c @@ -335,6 +335,23 @@ isp_reset(ispsoftc_t *isp) /* * XXX: Should probably do some bus sensing. */ + } else if (IS_ULTRA3(isp)) { + sdparam *sdp = isp->isp_param; + + isp->isp_clock = 100; + + if (IS_10160(isp)) + btype = "10160"; + else if (IS_12160(isp)) + btype = "12160"; + else + btype = "<UNKLVD>"; + sdp->isp_lvdmode = 1; + + if (IS_DUALBUS(isp)) { + sdp++; + sdp->isp_lvdmode = 1; + } } else if (IS_ULTRA2(isp)) { static const char m[] = "bus %d is in %s Mode"; uint16_t l; @@ -346,10 +363,6 @@ isp_reset(ispsoftc_t *isp) btype = "1280"; else if (IS_1080(isp)) btype = "1080"; - else if (IS_10160(isp)) - btype = "10160"; - else if (IS_12160(isp)) - btype = "12160"; else btype = "<UNKLVD>"; diff --git a/sys/dev/md/md.c b/sys/dev/md/md.c index f4230a2..bb9e64b 100644 --- a/sys/dev/md/md.c +++ b/sys/dev/md/md.c @@ -374,8 +374,11 @@ g_md_access(struct g_provider *pp, int r, int w, int e) struct md_s *sc; sc = pp->geom->softc; - if (sc == NULL) + if (sc == NULL) { + if (r <= 0 && w <= 0 && e <= 0) + return (0); return (ENXIO); + } r += pp->acr; w += pp->acw; e += pp->ace; diff --git a/sys/dev/mfi/mfi.c b/sys/dev/mfi/mfi.c index a2af0ba..7cdb304 100644 --- a/sys/dev/mfi/mfi.c +++ b/sys/dev/mfi/mfi.c @@ -296,7 +296,8 @@ mfi_attach(struct mfi_softc *sc) uint32_t status; int error, commsz, framessz, sensesz; int frames, unit, max_fw_sge; - device_printf(sc->mfi_dev, "Megaraid SAS driver Ver 2.00 \n"); + + device_printf(sc->mfi_dev, "Megaraid SAS driver Ver 3.00 \n"); mtx_init(&sc->mfi_io_lock, "MFI I/O lock", NULL, MTX_DEF); sx_init(&sc->mfi_config_lock, "MFI config"); diff --git a/sys/dev/mfi/mfi_pci.c b/sys/dev/mfi/mfi_pci.c index 902dce5..5f0b341 100644 --- a/sys/dev/mfi/mfi_pci.c +++ b/sys/dev/mfi/mfi_pci.c @@ -123,7 +123,7 @@ struct mfi_ident { {0x1000, 0x0079, 0x1028, 0x1f18, MFI_FLAGS_GEN2, "Dell PERC H700 Modular"}, {0x1000, 0x0079, 0x1028, 0x1f19, MFI_FLAGS_GEN2, "Dell PERC H700"}, {0x1000, 0x0079, 0x1028, 0x1f1b, MFI_FLAGS_GEN2, "Dell PERC H800"}, - {0x1000, 0x0079, 0x1028, 0xffff, MFI_FLAGS_GEN2, "Dell PERC H700/H800"}, + {0x1000, 0x0079, 0x1028, 0xffff, MFI_FLAGS_GEN2, "Dell PERC Gen2"}, {0x1000, 0x0079, 0xffff, 0xffff, MFI_FLAGS_GEN2, "LSI MegaSAS Gen2"}, {0x1000, 0x007c, 0xffff, 0xffff, MFI_FLAGS_1078, "LSI MegaSAS 1078"}, {0x1000, 0x0411, 0xffff, 0xffff, MFI_FLAGS_1064R, "LSI MegaSAS 1064R"}, /* Brocton IOP */ diff --git a/sys/dev/nfe/if_nfe.c b/sys/dev/nfe/if_nfe.c index 7a36a2e..e5a5294 100644 --- a/sys/dev/nfe/if_nfe.c +++ b/sys/dev/nfe/if_nfe.c @@ -3080,7 +3080,7 @@ nfe_sysctl_node(struct nfe_softc *sc) &stats->rx_unicast, "Unicast Frames"); NFE_SYSCTL_STAT_ADD32(ctx, child, "multicast", &stats->rx_multicast, "Multicast Frames"); - NFE_SYSCTL_STAT_ADD32(ctx, child, "brocadcast", + NFE_SYSCTL_STAT_ADD32(ctx, child, "broadcast", &stats->rx_broadcast, "Broadcast Frames"); if ((sc->nfe_flags & NFE_MIB_V2) != 0) { NFE_SYSCTL_STAT_ADD64(ctx, child, "octets", diff --git a/sys/dev/ofw/ofw_bus_subr.c b/sys/dev/ofw/ofw_bus_subr.c index 7a394c1..19de2b97 100644 --- a/sys/dev/ofw/ofw_bus_subr.c +++ b/sys/dev/ofw/ofw_bus_subr.c @@ -1,4 +1,5 @@ /*- + * Copyright (c) 2001 - 2003 by Thomas Moestl <tmm@FreeBSD.org>. * Copyright (c) 2005 Marius Strobl <marius@FreeBSD.org> * All rights reserved. * @@ -33,7 +34,9 @@ __FBSDID("$FreeBSD$"); #include <sys/systm.h> #include <sys/bus.h> #include <sys/errno.h> +#include <sys/libkern.h> +#include <dev/ofw/ofw_bus.h> #include <dev/ofw/ofw_bus_subr.h> #include <dev/ofw/openfirm.h> @@ -71,6 +74,22 @@ ofw_bus_gen_destroy_devinfo(struct ofw_bus_devinfo *obd) free(obd->obd_type, M_OFWPROP); } +int +ofw_bus_gen_child_pnpinfo_str(device_t cbdev, device_t child, char *buf, + size_t buflen) +{ + if (ofw_bus_get_name(child) != NULL) { + strlcat(buf, "name=", buflen); + strlcat(buf, ofw_bus_get_name(child), buflen); + } + + if (ofw_bus_get_compat(child) != NULL) { + strlcat(buf, " compat=", buflen); + strlcat(buf, ofw_bus_get_compat(child), buflen); + } + + return (0); +}; const char * ofw_bus_gen_get_compat(device_t bus, device_t dev) @@ -126,3 +145,135 @@ ofw_bus_gen_get_type(device_t bus, device_t dev) return (NULL); return (obd->obd_type); } + +static int +ofw_bus_searchprop(phandle_t node, char *propname, void *buf, int buflen) +{ + int rv; + + for (; node != 0; node = OF_parent(node)) { + if ((rv = OF_getprop(node, propname, buf, buflen)) != -1) + return (rv); + } + return (-1); +} + +void +ofw_bus_setup_iinfo(phandle_t node, struct ofw_bus_iinfo *ii, int intrsz) +{ + pcell_t addrc; + int msksz; + + if (OF_getprop(node, "#address-cells", &addrc, sizeof(addrc)) == -1) + addrc = 2; + ii->opi_addrc = addrc * sizeof(pcell_t); + + ii->opi_imapsz = OF_getprop_alloc(node, "interrupt-map", 1, + (void **)&ii->opi_imap); + if (ii->opi_imapsz > 0) { + msksz = OF_getprop_alloc(node, "interrupt-map-mask", 1, + (void **)&ii->opi_imapmsk); + /* + * Failure to get the mask is ignored; a full mask is used then. + * Barf on bad mask sizes, however. + */ + if (msksz != -1 && msksz != ii->opi_addrc + intrsz) { + panic("ofw_bus_setup_iinfo: bad interrupt-map-mask " + "property!"); + } + } + +} + +int +ofw_bus_lookup_imap(phandle_t node, struct ofw_bus_iinfo *ii, void *reg, + int regsz, void *pintr, int pintrsz, void *mintr, int mintrsz, + void *maskbuf) +{ + int rv; + + if (ii->opi_imapsz <= 0) + return (0); + KASSERT(regsz >= ii->opi_addrc, + ("ofw_bus_lookup_imap: register size too small: %d < %d", + regsz, ii->opi_addrc)); + rv = OF_getprop(node, "reg", reg, regsz); + if (rv < regsz) + panic("ofw_bus_lookup_imap: could not get reg property"); + return (ofw_bus_search_intrmap(pintr, pintrsz, reg, ii->opi_addrc, + ii->opi_imap, ii->opi_imapsz, ii->opi_imapmsk, maskbuf, mintr, + mintrsz)); +} + +/* + * Map an interrupt using the firmware reg, interrupt-map and + * interrupt-map-mask properties. + * The interrupt property to be mapped must be of size intrsz, and pointed to + * by intr. The regs property of the node for which the mapping is done must + * be passed as regs. This property is an array of register specifications; + * the size of the address part of such a specification must be passed as + * physsz. Only the first element of the property is used. + * imap and imapsz hold the interrupt mask and it's size. + * imapmsk is a pointer to the interrupt-map-mask property, which must have + * a size of physsz + intrsz; it may be NULL, in which case a full mask is + * assumed. + * maskbuf must point to a buffer of length physsz + intrsz. + * The interrupt is returned in result, which must point to a buffer of length + * rintrsz (which gives the expected size of the mapped interrupt). + * Returns 1 if a mapping was found, 0 otherwise. + */ +int +ofw_bus_search_intrmap(void *intr, int intrsz, void *regs, int physsz, + void *imap, int imapsz, void *imapmsk, void *maskbuf, void *result, + int rintrsz) +{ + phandle_t parent; + u_int8_t *ref = maskbuf; + u_int8_t *uiintr = intr; + u_int8_t *uiregs = regs; + u_int8_t *uiimapmsk = imapmsk; + u_int8_t *mptr; + pcell_t pintrsz; + int i, rsz, tsz; + + rsz = -1; + if (imapmsk != NULL) { + for (i = 0; i < physsz; i++) + ref[i] = uiregs[i] & uiimapmsk[i]; + for (i = 0; i < intrsz; i++) + ref[physsz + i] = uiintr[i] & uiimapmsk[physsz + i]; + } else { + bcopy(regs, ref, physsz); + bcopy(intr, ref + physsz, intrsz); + } + + mptr = imap; + i = imapsz; + tsz = physsz + intrsz + sizeof(phandle_t) + rintrsz; + while (i > 0) { + KASSERT(i >= tsz, ("ofw_bus_search_intrmap: truncated map")); + bcopy(mptr + physsz + intrsz, &parent, sizeof(parent)); + if (ofw_bus_searchprop(parent, "#interrupt-cells", + &pintrsz, sizeof(pintrsz)) == -1) + pintrsz = 1; /* default */ + pintrsz *= sizeof(pcell_t); + if (pintrsz != rintrsz) + panic("ofw_bus_search_intrmap: expected interrupt cell " + "size incorrect: %d > %d", rintrsz, pintrsz); + + /* + * XXX: Apple hardware uses a second cell to set information + * on the interrupt trigger type. This information should + * be used somewhere to program the PIC. + */ + + if (bcmp(ref, mptr, physsz + intrsz) == 0) { + bcopy(mptr + physsz + intrsz + sizeof(parent), + result, rintrsz); + return (1); + } + mptr += tsz; + i -= tsz; + } + return (0); +} diff --git a/sys/dev/ofw/ofw_bus_subr.h b/sys/dev/ofw/ofw_bus_subr.h index 6096b3e..58dd587 100644 --- a/sys/dev/ofw/ofw_bus_subr.h +++ b/sys/dev/ofw/ofw_bus_subr.h @@ -37,9 +37,30 @@ #include "ofw_bus_if.h" +#define ORIP_NOINT -1 +#define ORIR_NOTFOUND 0xffffffff + +struct ofw_bus_iinfo { + u_int8_t *opi_imap; + u_int8_t *opi_imapmsk; + int opi_imapsz; + pcell_t opi_addrc; +}; + int ofw_bus_gen_setup_devinfo(struct ofw_bus_devinfo *, phandle_t); void ofw_bus_gen_destroy_devinfo(struct ofw_bus_devinfo *); +/* Helper method to report interesting OF properties in pnpinfo */ +int ofw_bus_gen_child_pnpinfo_str(device_t, device_t, char *, size_t); + +/* Routines for processing firmware interrupt maps */ + +void ofw_bus_setup_iinfo(phandle_t, struct ofw_bus_iinfo *, int); +int ofw_bus_lookup_imap(phandle_t, struct ofw_bus_iinfo *, void *, int, + void *, int, void *, int, void *); +int ofw_bus_search_intrmap(void *, int, void *, int, void *, int, void *, + void *, void *, int); + ofw_bus_get_compat_t ofw_bus_gen_get_compat; ofw_bus_get_model_t ofw_bus_gen_get_model; ofw_bus_get_name_t ofw_bus_gen_get_name; diff --git a/sys/dev/ofw/ofw_if.m b/sys/dev/ofw/ofw_if.m new file mode 100644 index 0000000..431ac91 --- /dev/null +++ b/sys/dev/ofw/ofw_if.m @@ -0,0 +1,357 @@ +#- +# Copyright (c) 2008 Nathan Whitehorn +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +#include <dev/ofw/openfirm.h> +#include <dev/ofw/ofwvar.h> + +/** + * @defgroup OFW ofw - KObj methods for Open Firmware RTAS implementations + * @brief A set of methods to implement the Open Firmware client side interface. + *@{ + */ + +INTERFACE ofw; + +/** + * @brief Initialize OFW client interface + * + * @param _cookie A handle to the client interface, generally the OF + * callback routine. + */ +METHOD void init { + ofw_t _ofw; + void *_cookie; +}; + +/** + * @brief Return next sibling of node + * + * @param _node Selected node + */ +METHOD phandle_t peer { + ofw_t _ofw; + phandle_t _node; +}; + +/** + * @brief Return parent of node + * + * @param _node Selected node + */ +METHOD phandle_t parent { + ofw_t _ofw; + phandle_t _node; +}; + +/** + * @brief Return first child of node + * + * @param _node Selected node + */ +METHOD phandle_t child { + ofw_t _ofw; + phandle_t _node; +}; + +/** + * @brief Return package corresponding to instance + * + * @param _handle Selected instance + */ +METHOD phandle_t instance_to_package { + ofw_t _ofw; + ihandle_t _handle; +}; + +/** + * @brief Return length of node property + * + * @param _node Selected node + * @param _prop Property name + */ +METHOD ssize_t getproplen { + ofw_t _ofw; + phandle_t _node; + const char *_prop; +}; + +/** + * @brief Read node property + * + * @param _node Selected node + * @param _prop Property name + * @param _buf Pointer to buffer + * @param _size Size of buffer + */ +METHOD ssize_t getprop { + ofw_t _ofw; + phandle_t _node; + const char *_prop; + void *_buf; + size_t _size; +}; + +/** + * @brief Get next property name + * + * @param _node Selected node + * @param _prop Current property name + * @param _buf Buffer for next property name + * @param _size Size of buffer + */ +METHOD int nextprop { + ofw_t _ofw; + phandle_t _node; + const char *_prop; + char *_buf; + size_t _size; +}; + +/** + * @brief Set property + * + * @param _node Selected node + * @param _prop Property name + * @param _buf Value to set + * @param _size Size of buffer + */ +METHOD int setprop { + ofw_t _ofw; + phandle_t _node; + const char *_prop; + const void *_buf; + size_t _size; +}; + +/** + * @brief Canonicalize path + * + * @param _path Path to canonicalize + * @param _buf Buffer for canonicalized path + * @param _size Size of buffer + */ +METHOD ssize_t canon { + ofw_t _ofw; + const char *_path; + char *_buf; + size_t _size; +}; + +/** + * @brief Return phandle for named device + * + * @param _path Device path + */ +METHOD phandle_t finddevice { + ofw_t _ofw; + const char *_path; +}; + +/** + * @brief Return path for node instance + * + * @param _handle Instance handle + * @param _path Buffer for path + * @param _size Size of buffer + */ +METHOD ssize_t instance_to_path { + ofw_t _ofw; + ihandle_t _handle; + char *_path; + size_t _size; +}; + +/** + * @brief Return path for node + * + * @param _node Package node + * @param _path Buffer for path + * @param _size Size of buffer + */ +METHOD ssize_t package_to_path { + ofw_t _ofw; + phandle_t _node; + char *_path; + size_t _size; +}; + + +# Methods for OF method calls (optional) + +/** + * @brief Test to see if a service exists. + * + * @param _name name of the service + */ +METHOD int test { + ofw_t _ofw; + const char *_name; +}; + +/** + * @brief Call method belonging to an instance handle + * + * @param _instance Instance handle + * @param _method Method name + * @param _nargs Number of arguments + * @param _nreturns Number of return values + * @param _args_and_returns Values for arguments, followed by returns + */ + +METHOD int call_method { + ofw_t _ofw; + ihandle_t _instance; + const char *_method; + int _nargs; + int _nreturns; + + unsigned long *_args_and_returns; +}; + +/** + * @brief Interpret a forth command + * + * @param _cmd Command + * @param _nreturns Number of return values + * @param _returns Values for returns + */ + +METHOD int interpret { + ofw_t _ofw; + const char *_cmd; + int _nreturns; + unsigned long *_returns; +}; + +# Device I/O Functions (optional) + +/** + * @brief Open node, returning instance handle + * + * @param _path Path to node + */ +METHOD ihandle_t open { + ofw_t _ofw; + const char *_path; +} + +/** + * @brief Close node instance + * + * @param _instance Instance to close + */ +METHOD void close { + ofw_t _ofw; + ihandle_t _instance; +} + +/** + * @brief Read from device + * + * @param _instance Device instance + * @param _buf Buffer to read to + * @param _size Size of buffer + */ +METHOD ssize_t read { + ofw_t _ofw; + ihandle_t _instance; + void *_buf; + size_t size; +} + +/** + * @brief Write to device + * + * @param _instance Device instance + * @param _buf Buffer to write from + * @param _size Size of buffer + */ +METHOD ssize_t write { + ofw_t _ofw; + ihandle_t _instance; + const void *_buf; + size_t size; +} + +/** + * @brief Seek device + * + * @param _instance Device instance + * @param _off Offset to which to seek + */ +METHOD int seek { + ofw_t _ofw; + ihandle_t _instance; + uint64_t _off; +} + +# Open Firmware memory management + +/** + * @brief Claim virtual memory + * + * @param _addr Requested memory location (NULL for first available) + * @param _size Requested size in bytes + * @param _align Requested alignment + */ +METHOD caddr_t claim { + ofw_t _ofw; + void *_addr; + size_t _size; + u_int _align; +} + +/** + * @brief Release virtual memory + * + * @param _addr Memory location + * @param _size Size in bytes + */ +METHOD void release { + ofw_t _ofw; + void *_addr; + size_t _size; +}; + +# Commands for returning control to the firmware + +/** + * @brief Temporarily return control to firmware + */ +METHOD void enter { + ofw_t _ofw; +}; + +/** + * @brief Halt and return control to firmware + */ +METHOD void exit { + ofw_t _ofw; +}; + + diff --git a/sys/dev/ofw/ofw_standard.c b/sys/dev/ofw/ofw_standard.c new file mode 100644 index 0000000..e097145 --- /dev/null +++ b/sys/dev/ofw/ofw_standard.c @@ -0,0 +1,763 @@ +/* $NetBSD: Locore.c,v 1.7 2000/08/20 07:04:59 tsubai Exp $ */ + +/*- + * Copyright (C) 1995, 1996 Wolfgang Solfrank. + * Copyright (C) 1995, 1996 TooLs GmbH. + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by TooLs GmbH. + * 4. The name of TooLs GmbH may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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. + */ +/*- + * Copyright (C) 2000 Benno Rice. + * 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 Benno Rice ``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 TOOLS GMBH 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/systm.h> + +#include <machine/stdarg.h> + +#include <dev/ofw/openfirm.h> +#include <dev/ofw/ofwvar.h> +#include "ofw_if.h" + +static void ofw_std_init(ofw_t ofw, void *openfirm); +static int ofw_std_test(ofw_t ofw, const char *name); +static int ofw_std_interpret(ofw_t ofw, const char *cmd, int nreturns, + unsigned long *returns); +static phandle_t ofw_std_peer(ofw_t ofw, phandle_t node); +static phandle_t ofw_std_child(ofw_t ofw, phandle_t node); +static phandle_t ofw_std_parent(ofw_t ofw, phandle_t node); +static phandle_t ofw_std_instance_to_package(ofw_t ofw, ihandle_t instance); +static ssize_t ofw_std_getproplen(ofw_t ofw, phandle_t package, + const char *propname); +static ssize_t ofw_std_getprop(ofw_t ofw, phandle_t package, + const char *propname, void *buf, size_t buflen); +static int ofw_std_nextprop(ofw_t ofw, phandle_t package, const char *previous, + char *buf, size_t); +static int ofw_std_setprop(ofw_t ofw, phandle_t package, char *propname, + void *buf, size_t len); +static ssize_t ofw_std_canon(ofw_t ofw, const char *device, char *buf, + size_t len); +static phandle_t ofw_std_finddevice(ofw_t ofw, const char *device); +static ssize_t ofw_std_instance_to_path(ofw_t ofw, ihandle_t instance, + char *buf, size_t len); +static ssize_t ofw_std_package_to_path(ofw_t ofw, phandle_t package, char *buf, + size_t len); +static int ofw_std_call_method(ofw_t ofw, ihandle_t instance, + const char *method, int nargs, int nreturns, + unsigned long *args_and_returns); +static ihandle_t ofw_std_open(ofw_t ofw, const char *device); +static void ofw_std_close(ofw_t ofw, ihandle_t instance); +static ssize_t ofw_std_read(ofw_t ofw, ihandle_t instance, void *addr, + size_t len); +static ssize_t ofw_std_write(ofw_t ofw, ihandle_t instance, const void *addr, + size_t len); +static int ofw_std_seek(ofw_t ofw, ihandle_t instance, u_int64_t pos); +static caddr_t ofw_std_claim(ofw_t ofw, void *virt, size_t size, u_int align); +static void ofw_std_release(ofw_t ofw, void *virt, size_t size); +static void ofw_std_enter(ofw_t ofw); +static void ofw_std_exit(ofw_t ofw); + +static ofw_method_t ofw_std_methods[] = { + OFWMETHOD(ofw_init, ofw_std_init), + OFWMETHOD(ofw_peer, ofw_std_peer), + OFWMETHOD(ofw_child, ofw_std_child), + OFWMETHOD(ofw_parent, ofw_std_parent), + OFWMETHOD(ofw_instance_to_package, ofw_std_instance_to_package), + OFWMETHOD(ofw_getproplen, ofw_std_getproplen), + OFWMETHOD(ofw_getprop, ofw_std_getprop), + OFWMETHOD(ofw_nextprop, ofw_std_nextprop), + OFWMETHOD(ofw_setprop, ofw_std_setprop), + OFWMETHOD(ofw_canon, ofw_std_canon), + OFWMETHOD(ofw_finddevice, ofw_std_finddevice), + OFWMETHOD(ofw_instance_to_path, ofw_std_instance_to_path), + OFWMETHOD(ofw_package_to_path, ofw_std_package_to_path), + + OFWMETHOD(ofw_test, ofw_std_test), + OFWMETHOD(ofw_call_method, ofw_std_call_method), + OFWMETHOD(ofw_interpret, ofw_std_interpret), + OFWMETHOD(ofw_open, ofw_std_open), + OFWMETHOD(ofw_close, ofw_std_close), + OFWMETHOD(ofw_read, ofw_std_read), + OFWMETHOD(ofw_write, ofw_std_write), + OFWMETHOD(ofw_seek, ofw_std_seek), + OFWMETHOD(ofw_claim, ofw_std_claim), + OFWMETHOD(ofw_release, ofw_std_release), + OFWMETHOD(ofw_enter, ofw_std_enter), + OFWMETHOD(ofw_exit, ofw_std_exit), + + { 0, 0 } +}; + +static ofw_def_t ofw_std = { + OFW_STD_DIRECT, + ofw_std_methods, + 0 +}; +OFW_DEF(ofw_std); + +static int (*openfirmware)(void *); + +/* Initialiser */ + +static void +ofw_std_init(ofw_t ofw, void *openfirm) +{ + openfirmware = (int (*)(void *))openfirm; +} + +/* + * Generic functions + */ + +/* Test to see if a service exists. */ +static int +ofw_std_test(ofw_t ofw, const char *name) +{ + static struct { + cell_t name; + cell_t nargs; + cell_t nreturns; + cell_t service; + cell_t missing; + } args = { + (cell_t)"test", + 1, + 1, + }; + + args.service = (cell_t)name; + if (openfirmware(&args) == -1) + return (-1); + return (args.missing); +} + +static int +ofw_std_interpret(ofw_t ofw, const char *cmd, int nreturns, + unsigned long *returns) +{ + static struct { + cell_t name; + cell_t nargs; + cell_t nreturns; + cell_t slot[16]; + } args = { + (cell_t)"interpret", + 1, + }; + cell_t status; + int i = 0, j = 0; + + args.nreturns = ++nreturns; + args.slot[i++] = (cell_t)cmd; + if (openfirmware(&args) == -1) { + return (-1); + } + status = args.slot[i++]; + while (i < 1 + nreturns) + returns[j] = args.slot[i++]; + return (status); +} + +/* + * Device tree functions + */ + +/* Return the next sibling of this node or 0. */ +static phandle_t +ofw_std_peer(ofw_t ofw, phandle_t node) +{ + static struct { + cell_t name; + cell_t nargs; + cell_t nreturns; + cell_t node; + cell_t next; + } args = { + (cell_t)"peer", + 1, + 1, + }; + + args.node = node; + if (openfirmware(&args) == -1) + return (-1); + return (args.next); +} + +/* Return the first child of this node or 0. */ +static phandle_t +ofw_std_child(ofw_t ofw, phandle_t node) +{ + static struct { + cell_t name; + cell_t nargs; + cell_t nreturns; + cell_t node; + cell_t child; + } args = { + (cell_t)"child", + 1, + 1, + }; + + args.node = node; + if (openfirmware(&args) == -1) + return (-1); + return (args.child); +} + +/* Return the parent of this node or 0. */ +static phandle_t +ofw_std_parent(ofw_t ofw, phandle_t node) +{ + static struct { + cell_t name; + cell_t nargs; + cell_t nreturns; + cell_t node; + cell_t parent; + } args = { + (cell_t)"parent", + 1, + 1, + }; + + args.node = node; + if (openfirmware(&args) == -1) + return (-1); + return (args.parent); +} + +/* Return the package handle that corresponds to an instance handle. */ +static phandle_t +ofw_std_instance_to_package(ofw_t ofw, ihandle_t instance) +{ + static struct { + cell_t name; + cell_t nargs; + cell_t nreturns; + cell_t instance; + cell_t package; + } args = { + (cell_t)"instance-to-package", + 1, + 1, + }; + + args.instance = instance; + if (openfirmware(&args) == -1) + return (-1); + return (args.package); +} + +/* Get the length of a property of a package. */ +static ssize_t +ofw_std_getproplen(ofw_t ofw, phandle_t package, const char *propname) +{ + static struct { + cell_t name; + cell_t nargs; + cell_t nreturns; + cell_t package; + cell_t propname; + cell_t proplen; + } args = { + (cell_t)"getproplen", + 2, + 1, + }; + + args.package = package; + args.propname = (cell_t)propname; + if (openfirmware(&args) == -1) + return (-1); + return (args.proplen); +} + +/* Get the value of a property of a package. */ +static ssize_t +ofw_std_getprop(ofw_t ofw, phandle_t package, const char *propname, void *buf, + size_t buflen) +{ + static struct { + cell_t name; + cell_t nargs; + cell_t nreturns; + cell_t package; + cell_t propname; + cell_t buf; + cell_t buflen; + cell_t size; + } args = { + (cell_t)"getprop", + 4, + 1, + }; + + args.package = package; + args.propname = (cell_t)propname; + args.buf = (cell_t)buf; + args.buflen = buflen; + if (openfirmware(&args) == -1) + return (-1); + return (args.size); +} + +/* Get the next property of a package. */ +static int +ofw_std_nextprop(ofw_t ofw, phandle_t package, const char *previous, char *buf, + size_t size) +{ + static struct { + cell_t name; + cell_t nargs; + cell_t nreturns; + cell_t package; + cell_t previous; + cell_t buf; + cell_t flag; + } args = { + (cell_t)"nextprop", + 3, + 1, + }; + + args.package = package; + args.previous = (cell_t)previous; + args.buf = (cell_t)buf; + if (openfirmware(&args) == -1) + return (-1); + return (args.flag); +} + +/* Set the value of a property of a package. */ +/* XXX Has a bug on FirePower */ +static int +ofw_std_setprop(ofw_t ofw, phandle_t package, char *propname, void *buf, + size_t len) +{ + static struct { + cell_t name; + cell_t nargs; + cell_t nreturns; + cell_t package; + cell_t propname; + cell_t buf; + cell_t len; + cell_t size; + } args = { + (cell_t)"setprop", + 4, + 1, + }; + + args.package = package; + args.propname = (cell_t)propname; + args.buf = (cell_t)buf; + args.len = len; + if (openfirmware(&args) == -1) + return (-1); + return (args.size); +} + +/* Convert a device specifier to a fully qualified pathname. */ +static ssize_t +ofw_std_canon(ofw_t ofw, const char *device, char *buf, size_t len) +{ + static struct { + cell_t name; + cell_t nargs; + cell_t nreturns; + cell_t device; + cell_t buf; + cell_t len; + cell_t size; + } args = { + (cell_t)"canon", + 3, + 1, + }; + + args.device = (cell_t)device; + args.buf = (cell_t)buf; + args.len = len; + if (openfirmware(&args) == -1) + return (-1); + return (args.size); +} + +/* Return a package handle for the specified device. */ +static phandle_t +ofw_std_finddevice(ofw_t ofw, const char *device) +{ + static struct { + cell_t name; + cell_t nargs; + cell_t nreturns; + cell_t device; + cell_t package; + } args = { + (cell_t)"finddevice", + 1, + 1, + }; + + args.device = (cell_t)device; + if (openfirmware(&args) == -1) + return (-1); + return (args.package); +} + +/* Return the fully qualified pathname corresponding to an instance. */ +static ssize_t +ofw_std_instance_to_path(ofw_t ofw, ihandle_t instance, char *buf, size_t len) +{ + static struct { + cell_t name; + cell_t nargs; + cell_t nreturns; + cell_t instance; + cell_t buf; + cell_t len; + cell_t size; + } args = { + (cell_t)"instance-to-path", + 3, + 1, + }; + + args.instance = instance; + args.buf = (cell_t)buf; + args.len = len; + if (openfirmware(&args) == -1) + return (-1); + return (args.size); +} + +/* Return the fully qualified pathname corresponding to a package. */ +static ssize_t +ofw_std_package_to_path(ofw_t ofw, phandle_t package, char *buf, size_t len) +{ + static struct { + cell_t name; + cell_t nargs; + cell_t nreturns; + cell_t package; + cell_t buf; + cell_t len; + cell_t size; + } args = { + (cell_t)"package-to-path", + 3, + 1, + }; + + args.package = package; + args.buf = (cell_t)buf; + args.len = len; + if (openfirmware(&args) == -1) + return (-1); + return (args.size); +} + +/* Call the method in the scope of a given instance. */ +static int +ofw_std_call_method(ofw_t ofw, ihandle_t instance, const char *method, + int nargs, int nreturns, unsigned long *args_and_returns) +{ + static struct { + cell_t name; + cell_t nargs; + cell_t nreturns; + cell_t method; + cell_t instance; + cell_t args_n_results[12]; + } args = { + (cell_t)"call-method", + 2, + 1, + }; + cell_t *cp; + unsigned long *ap; + int n; + + if (nargs > 6) + return (-1); + args.nargs = nargs + 2; + args.nreturns = nreturns + 1; + args.method = (cell_t)method; + args.instance = instance; + + ap = args_and_returns; + for (cp = args.args_n_results + (n = nargs); --n >= 0;) + *--cp = *(ap++); + if (openfirmware(&args) == -1) + return (-1); + if (args.args_n_results[nargs]) + return (args.args_n_results[nargs]); + for (cp = args.args_n_results + nargs + (n = args.nreturns); --n > 0;) + *(ap++) = *--cp; + return (0); +} + +/* + * Device I/O functions + */ + +/* Open an instance for a device. */ +static ihandle_t +ofw_std_open(ofw_t ofw, const char *device) +{ + static struct { + cell_t name; + cell_t nargs; + cell_t nreturns; + cell_t device; + cell_t instance; + } args = { + (cell_t)"open", + 1, + 1, + }; + + args.device = (cell_t)device; + if (openfirmware(&args) == -1 || args.instance == 0) { + return (-1); + } + return (args.instance); +} + +/* Close an instance. */ +static void +ofw_std_close(ofw_t ofw, ihandle_t instance) +{ + static struct { + cell_t name; + cell_t nargs; + cell_t nreturns; + cell_t instance; + } args = { + (cell_t)"close", + 1, + }; + + args.instance = instance; + openfirmware(&args); +} + +/* Read from an instance. */ +static ssize_t +ofw_std_read(ofw_t ofw, ihandle_t instance, void *addr, size_t len) +{ + static struct { + cell_t name; + cell_t nargs; + cell_t nreturns; + cell_t instance; + cell_t addr; + cell_t len; + cell_t actual; + } args = { + (cell_t)"read", + 3, + 1, + }; + + args.instance = instance; + args.addr = (cell_t)addr; + args.len = len; + if (openfirmware(&args) == -1) + return (-1); + + return (args.actual); +} + +/* Write to an instance. */ +static ssize_t +ofw_std_write(ofw_t ofw, ihandle_t instance, const void *addr, size_t len) +{ + static struct { + cell_t name; + cell_t nargs; + cell_t nreturns; + cell_t instance; + cell_t addr; + cell_t len; + cell_t actual; + } args = { + (cell_t)"write", + 3, + 1, + }; + + args.instance = instance; + args.addr = (cell_t)addr; + args.len = len; + if (openfirmware(&args) == -1) + return (-1); + return (args.actual); +} + +/* Seek to a position. */ +static int +ofw_std_seek(ofw_t ofw, ihandle_t instance, u_int64_t pos) +{ + static struct { + cell_t name; + cell_t nargs; + cell_t nreturns; + cell_t instance; + cell_t poshi; + cell_t poslo; + cell_t status; + } args = { + (cell_t)"seek", + 3, + 1, + }; + + args.instance = instance; + args.poshi = pos >> 32; + args.poslo = pos; + if (openfirmware(&args) == -1) + return (-1); + return (args.status); +} + +/* + * Memory functions + */ + +/* Claim an area of memory. */ +static caddr_t +ofw_std_claim(ofw_t ofw, void *virt, size_t size, u_int align) +{ + static struct { + cell_t name; + cell_t nargs; + cell_t nreturns; + cell_t virt; + cell_t size; + cell_t align; + cell_t baseaddr; + } args = { + (cell_t)"claim", + 3, + 1, + }; + + args.virt = (cell_t)virt; + args.size = size; + args.align = align; + if (openfirmware(&args) == -1) + return ((void *)-1); + return ((void *)args.baseaddr); +} + +/* Release an area of memory. */ +static void +ofw_std_release(ofw_t ofw, void *virt, size_t size) +{ + static struct { + cell_t name; + cell_t nargs; + cell_t nreturns; + cell_t virt; + cell_t size; + } args = { + (cell_t)"release", + 2, + }; + + args.virt = (cell_t)virt; + args.size = size; + openfirmware(&args); +} + +/* + * Control transfer functions + */ + +/* Suspend and drop back to the Open Firmware interface. */ +static void +ofw_std_enter(ofw_t ofw) +{ + static struct { + cell_t name; + cell_t nargs; + cell_t nreturns; + } args = { + (cell_t)"enter", + }; + + openfirmware(&args); + /* We may come back. */ +} + +/* Shut down and drop back to the Open Firmware interface. */ +static void +ofw_std_exit(ofw_t ofw) +{ + static struct { + cell_t name; + cell_t nargs; + cell_t nreturns; + } args = { + (cell_t)"exit", + }; + + openfirmware(&args); + for (;;) /* just in case */ + ; +} + diff --git a/sys/dev/ofw/ofwvar.h b/sys/dev/ofw/ofwvar.h new file mode 100644 index 0000000..950dded --- /dev/null +++ b/sys/dev/ofw/ofwvar.h @@ -0,0 +1,89 @@ +/*- + * Copyright (c) 2005 Peter Grehan + * Copyright (c) 2008 Nathan Whitehorn + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _OFW_OFWVAR_H_ +#define _OFW_OFWVAR_H_ + +/* + * An Open Firmware client implementation is declared with a kernel object and + * an associated method table, similar to a device driver. + * + * e.g. + * + * static ofw_method_t fdt_methods[] = { + * OFWMETHOD(ofw_init, fdt_init), + * OFWMETHOD(ofw_finddevice, fdt_finddevice), + * ... + * OFWMETHOD(ofw_nextprop, fdt_nextprop), + * { 0, 0 } + * }; + * + * static ofw_def_t ofw_fdt = { + * "ofw_fdt", + * fdt_methods, + * sizeof(fdt_softc), // or 0 if no softc + * }; + * + * OFW_DEF(ofw_fdt); + */ + +#include <sys/kobj.h> + +struct ofw_kobj { + /* + * An OFW instance is a kernel object. + */ + KOBJ_FIELDS; + + /* + * Utility elements that an instance may use + */ + struct mtx ofw_mtx; /* available for instance use */ + void *ofw_iptr; /* instance data pointer */ + + /* + * Opaque data that can be overlaid with an instance-private + * structure. OFW code can test that this is large enough at + * compile time with a sizeof() test againt it's softc. There + * is also a run-time test when the MMU kernel object is + * registered. + */ +#define OFW_OPAQUESZ 64 + u_int ofw_opaque[OFW_OPAQUESZ]; +}; + +typedef struct ofw_kobj *ofw_t; +typedef struct kobj_class ofw_def_t; + +#define ofw_method_t kobj_method_t +#define OFWMETHOD KOBJMETHOD + +#define OFW_DEF(name) DATA_SET(ofw_set, name) + +#endif /* _OFW_OFWVAR_H_ */ diff --git a/sys/dev/ofw/openfirm.c b/sys/dev/ofw/openfirm.c index ff889e5..c7b2203 100644 --- a/sys/dev/ofw/openfirm.c +++ b/sys/dev/ofw/openfirm.c @@ -66,23 +66,70 @@ __FBSDID("$FreeBSD$"); #include <machine/stdarg.h> #include <dev/ofw/openfirm.h> +#include <dev/ofw/ofwvar.h> + +#include "ofw_if.h" MALLOC_DEFINE(M_OFWPROP, "openfirm", "Open Firmware properties"); static ihandle_t stdout; +static ofw_def_t *ofw_def_impl; +static ofw_t ofw_obj; +static struct ofw_kobj ofw_kernel_obj; +static struct kobj_ops ofw_kernel_kops; + +/* + * OFW install routines. Highest priority wins, equal priority also + * overrides allowing last-set to win. + */ +SET_DECLARE(ofw_set, ofw_def_t); + +boolean_t +OF_install(char *name, int prio) +{ + ofw_def_t **ofwpp, *ofwp; + static int curr_prio = 0; + + /* + * Try and locate the OFW kobj corresponding to the name + */ + SET_FOREACH(ofwpp, ofw_set) { + ofwp = *ofwpp; + + if (ofwp->name && + !strcmp(ofwp->name, name) && + prio >= curr_prio) { + curr_prio = prio; + ofw_def_impl = ofwp; + return (TRUE); + } + } + + return (FALSE); +} + /* Initialiser */ void -OF_init(int (*openfirm)(void *)) +OF_init(void *cookie) { phandle_t chosen; - set_openfirm_callback(openfirm); + ofw_obj = &ofw_kernel_obj; + /* + * Take care of compiling the selected class, and + * then statically initialize the OFW object + */ + kobj_class_compile_static(ofw_def_impl, &ofw_kernel_kops); + kobj_init((kobj_t)ofw_obj, ofw_def_impl); + + OFW_INIT(ofw_obj, cookie); + if ((chosen = OF_finddevice("/chosen")) == -1) OF_exit(); if (OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)) == -1) - OF_exit(); + stdout = -1; } void @@ -103,75 +150,27 @@ OF_printf(const char *fmt, ...) /* Test to see if a service exists. */ int -OF_test(char *name) +OF_test(const char *name) { - static struct { - cell_t name; - cell_t nargs; - cell_t nreturns; - cell_t service; - cell_t missing; - } args = { - (cell_t)"test", - 1, - 1, - }; - - args.service = (cell_t)name; - if (openfirmware(&args) == -1) - return (-1); - return (args.missing); + return (OFW_TEST(ofw_obj, name)); } int -OF_interpret(char *cmd, int nreturns, ...) +OF_interpret(const char *cmd, int nreturns, ...) { va_list ap; - static struct { - cell_t name; - cell_t nargs; - cell_t nreturns; - cell_t slot[16]; - } args = { - (cell_t)"interpret", - 1, - }; - cell_t status; + unsigned long slots[16]; int i = 0; + int status; + + status = OFW_INTERPRET(ofw_obj, cmd, nreturns, slots); va_start(ap, nreturns); - args.nreturns = ++nreturns; - args.slot[i++] = (cell_t)cmd; - while (i < 1) - args.slot[i++] = va_arg(ap, cell_t); - if (openfirmware(&args) == -1) { - va_end(ap); - return (-1); - } - status = args.slot[i++]; while (i < 1 + nreturns) - *va_arg(ap, cell_t *) = args.slot[i++]; + *va_arg(ap, cell_t *) = slots[i++]; va_end(ap); - return (status); -} -/* Return firmware millisecond count. */ -int -OF_milliseconds() -{ - static struct { - cell_t name; - cell_t nargs; - cell_t nreturns; - cell_t ms; - } args = { - (cell_t)"milliseconds", - 0, - 1, - }; - - openfirmware(&args); - return (args.ms); + return (status); } /* @@ -182,140 +181,42 @@ OF_milliseconds() phandle_t OF_peer(phandle_t node) { - static struct { - cell_t name; - cell_t nargs; - cell_t nreturns; - cell_t node; - cell_t next; - } args = { - (cell_t)"peer", - 1, - 1, - }; - - args.node = node; - if (openfirmware(&args) == -1) - return (-1); - return (args.next); + return (OFW_PEER(ofw_obj, node)); } /* Return the first child of this node or 0. */ phandle_t OF_child(phandle_t node) { - static struct { - cell_t name; - cell_t nargs; - cell_t nreturns; - cell_t node; - cell_t child; - } args = { - (cell_t)"child", - 1, - 1, - }; - - args.node = node; - if (openfirmware(&args) == -1) - return (-1); - return (args.child); + return (OFW_CHILD(ofw_obj, node)); } /* Return the parent of this node or 0. */ phandle_t OF_parent(phandle_t node) { - static struct { - cell_t name; - cell_t nargs; - cell_t nreturns; - cell_t node; - cell_t parent; - } args = { - (cell_t)"parent", - 1, - 1, - }; - - args.node = node; - if (openfirmware(&args) == -1) - return (-1); - return (args.parent); + return (OFW_PARENT(ofw_obj, node)); } /* Return the package handle that corresponds to an instance handle. */ phandle_t OF_instance_to_package(ihandle_t instance) { - static struct { - cell_t name; - cell_t nargs; - cell_t nreturns; - cell_t instance; - cell_t package; - } args = { - (cell_t)"instance-to-package", - 1, - 1, - }; - - args.instance = instance; - if (openfirmware(&args) == -1) - return (-1); - return (args.package); + return (OFW_INSTANCE_TO_PACKAGE(ofw_obj, instance)); } /* Get the length of a property of a package. */ -int -OF_getproplen(phandle_t package, char *propname) +ssize_t +OF_getproplen(phandle_t package, const char *propname) { - static struct { - cell_t name; - cell_t nargs; - cell_t nreturns; - cell_t package; - cell_t propname; - cell_t proplen; - } args = { - (cell_t)"getproplen", - 2, - 1, - }; - - args.package = package; - args.propname = (cell_t)propname; - if (openfirmware(&args) == -1) - return (-1); - return (args.proplen); + return (OFW_GETPROPLEN(ofw_obj, package, propname)); } /* Get the value of a property of a package. */ -int -OF_getprop(phandle_t package, char *propname, void *buf, int buflen) +ssize_t +OF_getprop(phandle_t package, const char *propname, void *buf, size_t buflen) { - static struct { - cell_t name; - cell_t nargs; - cell_t nreturns; - cell_t package; - cell_t propname; - cell_t buf; - cell_t buflen; - cell_t size; - } args = { - (cell_t)"getprop", - 4, - 1, - }; - - args.package = package; - args.propname = (cell_t)propname; - args.buf = (cell_t)buf; - args.buflen = buflen; - if (openfirmware(&args) == -1) - return (-1); - return (args.size); + return (OFW_GETPROP(ofw_obj, package, propname, buf, buflen)); } /* @@ -323,8 +224,8 @@ OF_getprop(phandle_t package, char *propname, void *buf, int buflen) * (using the M_OFWPROP malloc pool and M_WAITOK). elsz is the size of a * single element, the number of elements is return in number. */ -int -OF_getprop_alloc(phandle_t package, char *propname, int elsz, void **buf) +ssize_t +OF_getprop_alloc(phandle_t package, const char *propname, int elsz, void **buf) { int len; @@ -344,194 +245,69 @@ OF_getprop_alloc(phandle_t package, char *propname, int elsz, void **buf) /* Get the next property of a package. */ int -OF_nextprop(phandle_t package, char *previous, char *buf) +OF_nextprop(phandle_t package, const char *previous, char *buf, size_t size) { - static struct { - cell_t name; - cell_t nargs; - cell_t nreturns; - cell_t package; - cell_t previous; - cell_t buf; - cell_t flag; - } args = { - (cell_t)"nextprop", - 3, - 1, - }; - - args.package = package; - args.previous = (cell_t)previous; - args.buf = (cell_t)buf; - if (openfirmware(&args) == -1) - return (-1); - return (args.flag); + return (OFW_NEXTPROP(ofw_obj, package, previous, buf, size)); } /* Set the value of a property of a package. */ -/* XXX Has a bug on FirePower */ int -OF_setprop(phandle_t package, char *propname, void *buf, int len) +OF_setprop(phandle_t package, const char *propname, const void *buf, size_t len) { - static struct { - cell_t name; - cell_t nargs; - cell_t nreturns; - cell_t package; - cell_t propname; - cell_t buf; - cell_t len; - cell_t size; - } args = { - (cell_t)"setprop", - 4, - 1, - }; - - args.package = package; - args.propname = (cell_t)propname; - args.buf = (cell_t)buf; - args.len = len; - if (openfirmware(&args) == -1) - return (-1); - return (args.size); + return (OFW_SETPROP(ofw_obj, package, propname, buf,len)); } /* Convert a device specifier to a fully qualified pathname. */ -int -OF_canon(const char *device, char *buf, int len) +ssize_t +OF_canon(const char *device, char *buf, size_t len) { - static struct { - cell_t name; - cell_t nargs; - cell_t nreturns; - cell_t device; - cell_t buf; - cell_t len; - cell_t size; - } args = { - (cell_t)"canon", - 3, - 1, - }; - - args.device = (cell_t)device; - args.buf = (cell_t)buf; - args.len = len; - if (openfirmware(&args) == -1) - return (-1); - return (args.size); + return (OFW_CANON(ofw_obj, device, buf, len)); } /* Return a package handle for the specified device. */ phandle_t OF_finddevice(const char *device) { - static struct { - cell_t name; - cell_t nargs; - cell_t nreturns; - cell_t device; - cell_t package; - } args = { - (cell_t)"finddevice", - 1, - 1, - }; - - args.device = (cell_t)device; - if (openfirmware(&args) == -1) - return (-1); - return (args.package); + return (OFW_FINDDEVICE(ofw_obj, device)); } /* Return the fully qualified pathname corresponding to an instance. */ -int -OF_instance_to_path(ihandle_t instance, char *buf, int len) +ssize_t +OF_instance_to_path(ihandle_t instance, char *buf, size_t len) { - static struct { - cell_t name; - cell_t nargs; - cell_t nreturns; - cell_t instance; - cell_t buf; - cell_t len; - cell_t size; - } args = { - (cell_t)"instance-to-path", - 3, - 1, - }; - - args.instance = instance; - args.buf = (cell_t)buf; - args.len = len; - if (openfirmware(&args) == -1) - return (-1); - return (args.size); + return (OFW_INSTANCE_TO_PATH(ofw_obj, instance, buf, len)); } /* Return the fully qualified pathname corresponding to a package. */ -int -OF_package_to_path(phandle_t package, char *buf, int len) +ssize_t +OF_package_to_path(phandle_t package, char *buf, size_t len) { - static struct { - cell_t name; - cell_t nargs; - cell_t nreturns; - cell_t package; - cell_t buf; - cell_t len; - cell_t size; - } args = { - (cell_t)"package-to-path", - 3, - 1, - }; - - args.package = package; - args.buf = (cell_t)buf; - args.len = len; - if (openfirmware(&args) == -1) - return (-1); - return (args.size); + return (OFW_PACKAGE_TO_PATH(ofw_obj, package, buf, len)); } /* Call the method in the scope of a given instance. */ int -OF_call_method(char *method, ihandle_t instance, int nargs, int nreturns, ...) +OF_call_method(const char *method, ihandle_t instance, int nargs, int nreturns, + ...) { va_list ap; - static struct { - cell_t name; - cell_t nargs; - cell_t nreturns; - cell_t method; - cell_t instance; - cell_t args_n_results[12]; - } args = { - (cell_t)"call-method", - 2, - 1, - }; - cell_t *cp; - int n; + unsigned long args_n_results[12]; + int n, status; if (nargs > 6) return (-1); - args.nargs = nargs + 2; - args.nreturns = nreturns + 1; - args.method = (cell_t)method; - args.instance = instance; va_start(ap, nreturns); - for (cp = args.args_n_results + (n = nargs); --n >= 0;) - *--cp = va_arg(ap, cell_t); - if (openfirmware(&args) == -1) - return (-1); - if (args.args_n_results[nargs]) - return (args.args_n_results[nargs]); - for (cp = args.args_n_results + nargs + (n = args.nreturns); --n > 0;) - *va_arg(ap, cell_t *) = *--cp; + for (n = 0; n < nargs; n++) + args_n_results[n] = va_arg(ap, unsigned long); + + status = OFW_CALL_METHOD(ofw_obj, instance, method, nargs, nreturns, + args_n_results); + + if (status != 0) + return (status); + + for (; n < nargs + nreturns; n++) + *va_arg(ap, unsigned long *) = args_n_results[n]; va_end(ap); return (0); } @@ -542,122 +318,37 @@ OF_call_method(char *method, ihandle_t instance, int nargs, int nreturns, ...) /* Open an instance for a device. */ ihandle_t -OF_open(char *device) +OF_open(const char *device) { - static struct { - cell_t name; - cell_t nargs; - cell_t nreturns; - cell_t device; - cell_t instance; - } args = { - (cell_t)"open", - 1, - 1, - }; - - args.device = (cell_t)device; - if (openfirmware(&args) == -1 || args.instance == 0) { - return (-1); - } - return (args.instance); + return (OFW_OPEN(ofw_obj, device)); } /* Close an instance. */ void OF_close(ihandle_t instance) { - static struct { - cell_t name; - cell_t nargs; - cell_t nreturns; - cell_t instance; - } args = { - (cell_t)"close", - 1, - }; - - args.instance = instance; - openfirmware(&args); + OFW_CLOSE(ofw_obj, instance); } /* Read from an instance. */ -int -OF_read(ihandle_t instance, void *addr, int len) +ssize_t +OF_read(ihandle_t instance, void *addr, size_t len) { - static struct { - cell_t name; - cell_t nargs; - cell_t nreturns; - cell_t instance; - cell_t addr; - cell_t len; - cell_t actual; - } args = { - (cell_t)"read", - 3, - 1, - }; - - args.instance = instance; - args.addr = (cell_t)addr; - args.len = len; - if (openfirmware(&args) == -1) - return (-1); - - return (args.actual); + return (OFW_READ(ofw_obj, instance, addr, len)); } /* Write to an instance. */ -int -OF_write(ihandle_t instance, void *addr, int len) +ssize_t +OF_write(ihandle_t instance, const void *addr, size_t len) { - static struct { - cell_t name; - cell_t nargs; - cell_t nreturns; - cell_t instance; - cell_t addr; - cell_t len; - cell_t actual; - } args = { - (cell_t)"write", - 3, - 1, - }; - - args.instance = instance; - args.addr = (cell_t)addr; - args.len = len; - if (openfirmware(&args) == -1) - return (-1); - return (args.actual); + return (OFW_WRITE(ofw_obj, instance, addr, len)); } /* Seek to a position. */ int -OF_seek(ihandle_t instance, u_int64_t pos) +OF_seek(ihandle_t instance, uint64_t pos) { - static struct { - cell_t name; - cell_t nargs; - cell_t nreturns; - cell_t instance; - cell_t poshi; - cell_t poslo; - cell_t status; - } args = { - (cell_t)"seek", - 3, - 1, - }; - - args.instance = instance; - args.poshi = pos >> 32; - args.poslo = pos; - if (openfirmware(&args) == -1) - return (-1); - return (args.status); + return (OFW_SEEK(ofw_obj, instance, pos)); } /* @@ -666,145 +357,37 @@ OF_seek(ihandle_t instance, u_int64_t pos) /* Claim an area of memory. */ void * -OF_claim(void *virt, u_int size, u_int align) +OF_claim(void *virt, size_t size, u_int align) { - static struct { - cell_t name; - cell_t nargs; - cell_t nreturns; - cell_t virt; - cell_t size; - cell_t align; - cell_t baseaddr; - } args = { - (cell_t)"claim", - 3, - 1, - }; - - args.virt = (cell_t)virt; - args.size = size; - args.align = align; - if (openfirmware(&args) == -1) - return ((void *)-1); - return ((void *)args.baseaddr); + return (OFW_CLAIM(ofw_obj, virt, size, align)); } /* Release an area of memory. */ void -OF_release(void *virt, u_int size) +OF_release(void *virt, size_t size) { - static struct { - cell_t name; - cell_t nargs; - cell_t nreturns; - cell_t virt; - cell_t size; - } args = { - (cell_t)"release", - 2, - }; - - args.virt = (cell_t)virt; - args.size = size; - openfirmware(&args); + OFW_RELEASE(ofw_obj, virt, size); } /* * Control transfer functions */ -/* Reset the system and call "boot <bootspec>". */ -void -OF_boot(char *bootspec) -{ - static struct { - cell_t name; - cell_t nargs; - cell_t nreturns; - cell_t bootspec; - } args = { - (cell_t)"boot", - 1, - }; - - args.bootspec = (cell_t)bootspec; - openfirmware(&args); - for (;;) /* just in case */ - ; -} - /* Suspend and drop back to the Open Firmware interface. */ void OF_enter() { - static struct { - cell_t name; - cell_t nargs; - cell_t nreturns; - } args = { - (cell_t)"enter", - }; - - openfirmware(&args); - /* We may come back. */ + OFW_ENTER(ofw_obj); } /* Shut down and drop back to the Open Firmware interface. */ void OF_exit() { - static struct { - cell_t name; - cell_t nargs; - cell_t nreturns; - } args = { - (cell_t)"exit", - }; - - openfirmware(&args); + /* Should not return */ + OFW_EXIT(ofw_obj); + for (;;) /* just in case */ ; } -/* Free <size> bytes starting at <virt>, then call <entry> with <arg>. */ -#if 0 -void -OF_chain(void *virt, u_int size, void (*entry)(), void *arg, u_int len) -{ - static struct { - cell_t name; - cell_t nargs; - cell_t nreturns; - cell_t virt; - cell_t size; - cell_t entry; - cell_t arg; - cell_t len; - } args = { - (cell_t)"chain", - 5, - }; - - args.virt = (cell_t)virt; - args.size = size; - args.entry = (cell_t)entry; - args.arg = (cell_t)arg; - args.len = len; - openfirmware(&args); -} -#else -void -OF_chain(void *virt, u_int size, - void (*entry)(void *, u_int, void *, void *, u_int), void *arg, u_int len) -{ - /* - * This is a REALLY dirty hack till the firmware gets this going - */ -#if 0 - if (size > 0) - OF_release(virt, size); -#endif - entry(0, 0, openfirmware, arg, len); -} -#endif diff --git a/sys/dev/ofw/openfirm.h b/sys/dev/ofw/openfirm.h index a8c0633..08a0544 100644 --- a/sys/dev/ofw/openfirm.h +++ b/sys/dev/ofw/openfirm.h @@ -60,78 +60,82 @@ #ifndef _OPENFIRM_H_ #define _OPENFIRM_H_ +#include <sys/types.h> + /* * Prototypes for Open Firmware Interface Routines */ -typedef unsigned long cell_t; - -typedef unsigned int ihandle_t; -typedef unsigned int phandle_t; +typedef uint32_t ihandle_t; +typedef uint32_t phandle_t; +typedef uint32_t pcell_t; #ifdef _KERNEL -#include <sys/cdefs.h> -#include <sys/types.h> #include <sys/malloc.h> +#include <machine/ofw_machdep.h> + MALLOC_DECLARE(M_OFWPROP); /* - * Stuff that is used by the Open Firmware code. + * Open Firmware interface initialization. OF_install installs the named + * interface as the Open Firmware access mechanism, OF_init initializes it. */ -void set_openfirm_callback(int (*)(void *)); -int openfirmware(void *); + +boolean_t OF_install(char *name, int prio); +void OF_init(void *cookie); /* - * This isn't actually an Open Firmware function, but it seemed like the right - * place for it to go. + * Known Open Firmware interface names */ -void OF_init(int (*openfirm)(void *)); + +#define OFW_STD_DIRECT "ofw_std" /* Standard OF interface */ +#define OFW_STD_REAL "ofw_real" /* Real-mode OF interface */ +#define OFW_FDT "ofw_fdt" /* Flattened Device Tree */ /* Generic functions */ -int OF_test(char *); +int OF_test(const char *); void OF_printf(const char *, ...); /* Device tree functions */ -phandle_t OF_peer(phandle_t); -phandle_t OF_child(phandle_t); -phandle_t OF_parent(phandle_t); -phandle_t OF_instance_to_package(ihandle_t); -int OF_getproplen(phandle_t, char *); -int OF_getprop(phandle_t, char *, void *, int); -int OF_getprop_alloc(phandle_t package, char *propname, int elsz, - void **buf); -int OF_nextprop(phandle_t, char *, char *); -int OF_setprop(phandle_t, char *, void *, int); -int OF_canon(const char *, char *, int); -phandle_t OF_finddevice(const char *); -int OF_instance_to_path(ihandle_t, char *, int); -int OF_package_to_path(phandle_t, char *, int); -int OF_call_method(char *, ihandle_t, int, int, ...); +phandle_t OF_peer(phandle_t node); +phandle_t OF_child(phandle_t node); +phandle_t OF_parent(phandle_t node); +ssize_t OF_getproplen(phandle_t node, const char *propname); +ssize_t OF_getprop(phandle_t node, const char *propname, void *buf, + size_t len); +ssize_t OF_getprop_alloc(phandle_t node, const char *propname, + int elsz, void **buf); +int OF_nextprop(phandle_t node, const char *propname, char *buf, + size_t len); +int OF_setprop(phandle_t node, const char *name, const void *buf, + size_t len); +ssize_t OF_canon(const char *path, char *buf, size_t len); +phandle_t OF_finddevice(const char *path); +ssize_t OF_package_to_path(phandle_t node, char *buf, size_t len); /* Device I/O functions */ -ihandle_t OF_open(char *); -void OF_close(ihandle_t); -int OF_read(ihandle_t, void *, int); -int OF_write(ihandle_t, void *, int); -int OF_seek(ihandle_t, u_quad_t); +ihandle_t OF_open(const char *path); +void OF_close(ihandle_t instance); +ssize_t OF_read(ihandle_t instance, void *buf, size_t len); +ssize_t OF_write(ihandle_t instance, const void *buf, size_t len); +int OF_seek(ihandle_t instance, uint64_t where); + +phandle_t OF_instance_to_package(ihandle_t instance); +ssize_t OF_instance_to_path(ihandle_t instance, char *buf, size_t len); +int OF_call_method(const char *method, ihandle_t instance, + int nargs, int nreturns, ...); /* Memory functions */ -void *OF_claim(void *, u_int, u_int); -void OF_release(void *, u_int); +void *OF_claim(void *virtrequest, size_t size, u_int align); +void OF_release(void *virt, size_t size); /* Control transfer functions */ -void OF_boot(char *); void OF_enter(void); void OF_exit(void) __attribute__((noreturn)); -void OF_chain(void *, u_int, - void (*)(void *, u_int, void *, void *, u_int), void *, u_int); /* User interface functions */ -int OF_interpret(char *, int, ...); - -/* Time function */ -int OF_milliseconds(void); +int OF_interpret(const char *cmd, int nreturns, ...); #endif /* _KERNEL */ #endif /* _OPENFIRM_H_ */ diff --git a/sys/dev/ofw/openfirmio.c b/sys/dev/ofw/openfirmio.c index 47f2517..d042f02 100644 --- a/sys/dev/ofw/openfirmio.c +++ b/sys/dev/ofw/openfirmio.c @@ -221,7 +221,7 @@ openfirm_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, if (error) break; } - ok = OF_nextprop(node, name, newname); + ok = OF_nextprop(node, name, newname, sizeof(newname)); if (ok == 0) { error = ENOENT; break; diff --git a/sys/dev/ofw/openpromio.c b/sys/dev/ofw/openpromio.c index cb7343f..8ba6d3a 100644 --- a/sys/dev/ofw/openpromio.c +++ b/sys/dev/ofw/openpromio.c @@ -174,7 +174,7 @@ openprom_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, error = OF_getprop(node, prop, buf, proplen); break; case OPROMNXTPROP: - error = OF_nextprop(node, prop, buf); + error = OF_nextprop(node, prop, buf, OPROMMAXPARAM); proplen = strlen(buf); break; } diff --git a/sys/dev/re/if_re.c b/sys/dev/re/if_re.c index 6709d6d..2ad55fd 100644 --- a/sys/dev/re/if_re.c +++ b/sys/dev/re/if_re.c @@ -1157,6 +1157,7 @@ re_attach(device_t dev) msic = 0; if (pci_find_extcap(dev, PCIY_EXPRESS, ®) == 0) { + sc->rl_flags |= RL_FLAG_PCIE; msic = pci_msi_count(dev); if (bootverbose) device_printf(dev, "MSI count : %d\n", msic); @@ -1262,8 +1263,13 @@ re_attach(device_t dev) sc->rl_flags |= RL_FLAG_INVMAR | RL_FLAG_PHYWAKE | RL_FLAG_MACSTAT; break; - case RL_HWREV_8168C: case RL_HWREV_8168C_SPIN2: + sc->rl_flags |= RL_FLAG_MACSLEEP; + /* FALLTHROUGH */ + case RL_HWREV_8168C: + if ((hwrev & 0x00700000) == 0x00200000) + sc->rl_flags |= RL_FLAG_MACSLEEP; + /* FALLTHROUGH */ case RL_HWREV_8168CP: case RL_HWREV_8168D: sc->rl_flags |= RL_FLAG_INVMAR | RL_FLAG_PHYWAKE | @@ -1351,6 +1357,16 @@ re_attach(device_t dev) goto fail; } + /* Take controller out of deep sleep mode. */ + if ((sc->rl_flags & RL_FLAG_MACSLEEP) != 0) { + if ((CSR_READ_1(sc, RL_MACDBG) & 0x80) == 0x80) + CSR_WRITE_1(sc, RL_GPIO, + CSR_READ_1(sc, RL_GPIO) | 0x01); + else + CSR_WRITE_1(sc, RL_GPIO, + CSR_READ_1(sc, RL_GPIO) & ~0x01); + } + /* Take PHY out of power down mode. */ if ((sc->rl_flags & RL_FLAG_PHYWAKE) != 0) { re_gmii_writereg(dev, 1, 0x1f, 0); @@ -2027,16 +2043,6 @@ re_txeof(struct rl_softc *sc) /* No changes made to the TX ring, so no flush needed */ if (sc->rl_ldata.rl_tx_free != sc->rl_ldata.rl_tx_desc_cnt) { - /* - * Some chips will ignore a second TX request issued - * while an existing transmission is in progress. If - * the transmitter goes idle but there are still - * packets waiting to be sent, we need to restart the - * channel here to flush them out. This only seems to - * be required with the PCIe devices. - */ - CSR_WRITE_1(sc, sc->rl_txstart, RL_TXSTART_START); - #ifdef RE_TX_MODERATION /* * If not all descriptors have been reaped yet, reload @@ -2100,6 +2106,9 @@ re_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count) return; if (status) CSR_WRITE_2(sc, RL_ISR, status); + if ((status & (RL_ISR_TX_OK | RL_ISR_TX_DESC_UNAVAIL)) && + (sc->rl_flags & RL_FLAG_PCIE)) + CSR_WRITE_1(sc, sc->rl_txstart, RL_TXSTART_START); /* * XXX check behaviour on receiver stalls. @@ -2161,6 +2170,17 @@ re_int_task(void *arg, int npending) if (status & (RL_ISR_RX_OK|RL_ISR_RX_ERR|RL_ISR_FIFO_OFLOW)) rval = re_rxeof(sc); + /* + * Some chips will ignore a second TX request issued + * while an existing transmission is in progress. If + * the transmitter goes idle but there are still + * packets waiting to be sent, we need to restart the + * channel here to flush them out. This only seems to + * be required with the PCIe devices. + */ + if ((status & (RL_ISR_TX_OK | RL_ISR_TX_DESC_UNAVAIL)) && + (sc->rl_flags & RL_FLAG_PCIE)) + CSR_WRITE_1(sc, sc->rl_txstart, RL_TXSTART_START); if (status & ( #ifdef RE_TX_MODERATION RL_ISR_TIMEOUT_EXPIRED| @@ -2963,6 +2983,12 @@ re_resume(device_t dev) RL_LOCK(sc); ifp = sc->rl_ifp; + /* Take controller out of sleep mode. */ + if ((sc->rl_flags & RL_FLAG_MACSLEEP) != 0) { + if ((CSR_READ_1(sc, RL_MACDBG) & 0x80) == 0x80) + CSR_WRITE_1(sc, RL_GPIO, + CSR_READ_1(sc, RL_GPIO) | 0x01); + } /* reinitialize interface if necessary */ if (ifp->if_flags & IFF_UP) @@ -3018,6 +3044,12 @@ re_setwol(struct rl_softc *sc) return; ifp = sc->rl_ifp; + /* Put controller into sleep mode. */ + if ((sc->rl_flags & RL_FLAG_MACSLEEP) != 0) { + if ((CSR_READ_1(sc, RL_MACDBG) & 0x80) == 0x80) + CSR_WRITE_1(sc, RL_GPIO, + CSR_READ_1(sc, RL_GPIO) & ~0x01); + } if ((ifp->if_capenable & IFCAP_WOL) != 0 && (sc->rl_flags & RL_FLAG_WOLRXENB) != 0) CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_RX_ENB); diff --git a/sys/dev/snp/snp.c b/sys/dev/snp/snp.c index f2dcc1b..8d6485c 100644 --- a/sys/dev/snp/snp.c +++ b/sys/dev/snp/snp.c @@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$"); #include <sys/malloc.h> #include <sys/module.h> #include <sys/poll.h> +#include <sys/proc.h> #include <sys/snoop.h> #include <sys/sx.h> #include <sys/systm.h> @@ -246,7 +247,7 @@ snp_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, sx_xunlock(&snp_register_lock); return (EBUSY); } - error = ttyhook_register(&ss->snp_tty, td, *(int *)data, + error = ttyhook_register(&ss->snp_tty, td->td_proc, *(int *)data, &snp_hook, ss); sx_xunlock(&snp_register_lock); if (error != 0) diff --git a/sys/dev/sound/pci/hda/hdac.c b/sys/dev/sound/pci/hda/hdac.c index 4be21fb1..a185f51 100644 --- a/sys/dev/sound/pci/hda/hdac.c +++ b/sys/dev/sound/pci/hda/hdac.c @@ -83,7 +83,7 @@ #include "mixer_if.h" -#define HDA_DRV_TEST_REV "20081123_0118" +#define HDA_DRV_TEST_REV "20081219_0119" SND_DECLARE_FILE("$FreeBSD$"); @@ -180,6 +180,11 @@ SND_DECLARE_FILE("$FreeBSD$"); #define HDA_SIS_966 HDA_MODEL_CONSTRUCT(SIS, 0x7502) #define HDA_SIS_ALL HDA_MODEL_CONSTRUCT(SIS, 0xffff) +/* ULI */ +#define ULI_VENDORID 0x10b9 +#define HDA_ULI_M5461 HDA_MODEL_CONSTRUCT(ULI, 0x5461) +#define HDA_ULI_ALL HDA_MODEL_CONSTRUCT(ULI, 0xffff) + /* OEM/subvendors */ /* Intel */ @@ -467,12 +472,14 @@ static const struct { { HDA_ATI_SB600, "ATI SB600" }, { HDA_VIA_VT82XX, "VIA VT8251/8237A" }, { HDA_SIS_966, "SiS 966" }, + { HDA_ULI_M5461, "ULI M5461" }, /* Unknown */ { HDA_INTEL_ALL, "Intel (Unknown)" }, { HDA_NVIDIA_ALL, "NVidia (Unknown)" }, { HDA_ATI_ALL, "ATI (Unknown)" }, { HDA_VIA_ALL, "VIA (Unknown)" }, { HDA_SIS_ALL, "SiS (Unknown)" }, + { HDA_ULI_ALL, "ULI (Unknown)" }, }; #define HDAC_DEVICES_LEN (sizeof(hdac_devices) / sizeof(hdac_devices[0])) @@ -635,6 +642,7 @@ static const struct { /* Silicon Image */ #define SII_VENDORID 0x1095 +#define HDA_CODEC_SII1392 HDA_CODEC_CONSTRUCT(SII, 0x1392) #define HDA_CODEC_SIIXXXX HDA_CODEC_CONSTRUCT(SII, 0xffff) /* Lucent/Agere */ @@ -669,9 +677,21 @@ static const struct { #define HDA_CODEC_VT1709_5 HDA_CODEC_CONSTRUCT(VIA, 0xe715) #define HDA_CODEC_VT1709_6 HDA_CODEC_CONSTRUCT(VIA, 0xe716) #define HDA_CODEC_VT1709_7 HDA_CODEC_CONSTRUCT(VIA, 0xe717) +#define HDA_CODEC_VT1708B_0 HDA_CODEC_CONSTRUCT(VIA, 0xe720) +#define HDA_CODEC_VT1708B_1 HDA_CODEC_CONSTRUCT(VIA, 0xe721) +#define HDA_CODEC_VT1708B_2 HDA_CODEC_CONSTRUCT(VIA, 0xe722) +#define HDA_CODEC_VT1708B_3 HDA_CODEC_CONSTRUCT(VIA, 0xe723) +#define HDA_CODEC_VT1708B_4 HDA_CODEC_CONSTRUCT(VIA, 0xe724) +#define HDA_CODEC_VT1708B_5 HDA_CODEC_CONSTRUCT(VIA, 0xe725) +#define HDA_CODEC_VT1708B_6 HDA_CODEC_CONSTRUCT(VIA, 0xe726) +#define HDA_CODEC_VT1708B_7 HDA_CODEC_CONSTRUCT(VIA, 0xe727) #define HDA_CODEC_VTXXXX HDA_CODEC_CONSTRUCT(VIA, 0xffff) /* ATI */ +#define HDA_CODEC_ATIRS600_1 HDA_CODEC_CONSTRUCT(ATI, 0x793c) +#define HDA_CODEC_ATIRS600_2 HDA_CODEC_CONSTRUCT(ATI, 0x7919) +#define HDA_CODEC_ATIRS690 HDA_CODEC_CONSTRUCT(ATI, 0x791a) +#define HDA_CODEC_ATIR6XX HDA_CODEC_CONSTRUCT(ATI, 0xaa01) #define HDA_CODEC_ATIXXXX HDA_CODEC_CONSTRUCT(ATI, 0xffff) /* NVIDIA */ @@ -774,6 +794,19 @@ static const struct { { HDA_CODEC_VT1709_5, "VIA VT1709_5" }, { HDA_CODEC_VT1709_6, "VIA VT1709_6" }, { HDA_CODEC_VT1709_7, "VIA VT1709_7" }, + { HDA_CODEC_VT1708B_0, "VIA VT1708B_0" }, + { HDA_CODEC_VT1708B_1, "VIA VT1708B_1" }, + { HDA_CODEC_VT1708B_2, "VIA VT1708B_2" }, + { HDA_CODEC_VT1708B_3, "VIA VT1708B_3" }, + { HDA_CODEC_VT1708B_4, "VIA VT1708B_4" }, + { HDA_CODEC_VT1708B_5, "VIA VT1708B_5" }, + { HDA_CODEC_VT1708B_6, "VIA VT1708B_6" }, + { HDA_CODEC_VT1708B_7, "VIA VT1708B_7" }, + { HDA_CODEC_ATIRS600_1,"ATI RS600 HDMI" }, + { HDA_CODEC_ATIRS600_2,"ATI RS600 HDMI" }, + { HDA_CODEC_ATIRS690, "ATI RS690/780 HDMI" }, + { HDA_CODEC_ATIR6XX, "ATI R6xx HDMI" }, + { HDA_CODEC_SII1392, "Silicon Image SiI1392 HDMI" }, /* Unknown codec */ { HDA_CODEC_ALCXXXX, "Realtek (Unknown)" }, { HDA_CODEC_ADXXXX, "Analog Devices (Unknown)" }, diff --git a/sys/dev/usb/ucom.c b/sys/dev/usb/ucom.c index 7496d40..ae263a0 100644 --- a/sys/dev/usb/ucom.c +++ b/sys/dev/usb/ucom.c @@ -700,6 +700,29 @@ ucomstartread(struct ucom_softc *sc) return (USBD_NORMAL_COMPLETION); } +void +ucomrxchars(struct ucom_softc *sc, u_char *cp, u_int32_t cc) +{ + struct tty *tp = sc->sc_tty; + + /* Give characters to tty layer. */ + if (ttydisc_can_bypass(tp)) { + DPRINTFN(7, ("ucomreadcb: buf = %*D\n", cc, cp, "")); + cc -= ttydisc_rint_bypass(tp, cp, cc); + } else { + while (cc > 0) { + DPRINTFN(7, ("ucomreadcb: char = 0x%02x\n", *cp)); + if (ttydisc_rint(tp, *cp, 0) == -1) + break; + cc--; + cp++; + } + } + if (cc > 0) + device_printf(sc->sc_dev, "lost %d chars\n", cc); + ttydisc_rint_done(tp); +} + static void ucomreadcb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status) { @@ -709,6 +732,7 @@ ucomreadcb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status) u_int32_t cc; u_char *cp; + (void)tp; /* Used for debugging */ DPRINTF(("ucomreadcb: status = %d\n", status)); if (status != USBD_NORMAL_COMPLETION) { @@ -737,22 +761,8 @@ ucomreadcb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status) device_get_nameunit(sc->sc_dev), cc); goto resubmit; } - if (cc < 1) - goto resubmit; - - /* Give characters to tty layer. */ - while (cc > 0) { - DPRINTFN(7, ("ucomreadcb: char = 0x%02x\n", *cp)); - if (ttydisc_rint(tp, *cp, 0) == -1) { - /* XXX what should we do? */ - printf("%s: lost %d chars\n", - device_get_nameunit(sc->sc_dev), cc); - break; - } - cc--; - cp++; - } - ttydisc_rint_done(tp); + if (cc > 0) + ucomrxchars(sc, cp, cc); resubmit: err = ucomstartread(sc); diff --git a/sys/dev/usb/ucomvar.h b/sys/dev/usb/ucomvar.h index 0fcd7f3..4433a1a 100644 --- a/sys/dev/usb/ucomvar.h +++ b/sys/dev/usb/ucomvar.h @@ -166,3 +166,4 @@ void ucom_attach_tty(struct ucom_softc *, char*, int); int ucom_attach(struct ucom_softc *); int ucom_detach(struct ucom_softc *); void ucom_status_change(struct ucom_softc *); +void ucomrxchars(struct ucom_softc *sc, u_char *cp, u_int32_t cc); diff --git a/sys/dev/usb/uftdi.c b/sys/dev/usb/uftdi.c index 5a9921b..c32bfa6 100644 --- a/sys/dev/usb/uftdi.c +++ b/sys/dev/usb/uftdi.c @@ -100,7 +100,7 @@ SYSCTL_INT(_hw_usb_uftdi, OID_AUTO, debug, CTLFLAG_RW, * These are the maximum number of bytes transferred per frame. * The output buffer size cannot be increased due to the size encoding. */ -#define UFTDIIBUFSIZE 64 +#define UFTDIIBUFSIZE 256 #define UFTDIOBUFSIZE 64 struct uftdi_softc { @@ -458,32 +458,33 @@ uftdi_read(void *vsc, int portno, u_char **ptr, u_int32_t *count) { struct uftdi_softc *sc = vsc; u_char msr, lsr; + unsigned l; + + DPRINTFN(15,("uftdi_read: sc=%p, port=%d count=%d\n", + sc, portno, *count)); + while (*count > 0) { + l = *count; + if (l > 64) + l = 64; + + msr = FTDI_GET_MSR(*ptr); + lsr = FTDI_GET_LSR(*ptr); + + if (sc->sc_msr != msr || + (sc->sc_lsr & FTDI_LSR_MASK) != (lsr & FTDI_LSR_MASK)) { + DPRINTF(("uftdi_read: status change msr=0x%02x(0x%02x) " + "lsr=0x%02x(0x%02x)\n", msr, sc->sc_msr, + lsr, sc->sc_lsr)); + sc->sc_msr = msr; + sc->sc_lsr = lsr; + ucom_status_change(&sc->sc_ucom); + } - DPRINTFN(15,("uftdi_read: sc=%p, port=%d count=%d\n", sc, portno, - *count)); - - msr = FTDI_GET_MSR(*ptr); - lsr = FTDI_GET_LSR(*ptr); - -#ifdef USB_DEBUG - if (*count != 2) - DPRINTFN(10,("uftdi_read: sc=%p, port=%d count=%d data[0]=" - "0x%02x\n", sc, portno, *count, (*ptr)[2])); -#endif - - if (sc->sc_msr != msr || - (sc->sc_lsr & FTDI_LSR_MASK) != (lsr & FTDI_LSR_MASK)) { - DPRINTF(("uftdi_read: status change msr=0x%02x(0x%02x) " - "lsr=0x%02x(0x%02x)\n", msr, sc->sc_msr, - lsr, sc->sc_lsr)); - sc->sc_msr = msr; - sc->sc_lsr = lsr; - ucom_status_change(&sc->sc_ucom); + if (l > 2) + ucomrxchars(&sc->sc_ucom, (*ptr) + 2, l - 2); + *ptr += l; + *count -= l; } - - /* Pick up status and adjust data part. */ - *ptr += 2; - *count -= 2; } static size_t diff --git a/sys/fs/hpfs/hpfs_vnops.c b/sys/fs/hpfs/hpfs_vnops.c index c5a2a06..4ec6b1e 100644 --- a/sys/fs/hpfs/hpfs_vnops.c +++ b/sys/fs/hpfs/hpfs_vnops.c @@ -661,7 +661,7 @@ hpfs_strategy(ap) bp->b_error = error; bp->b_ioflags |= BIO_ERROR; bufdone(bp); - return (error); + return (0); } if ((long)bp->b_blkno == -1) vfs_bio_clrbuf(bp); diff --git a/sys/fs/msdosfs/msdosfs_vnops.c b/sys/fs/msdosfs/msdosfs_vnops.c index ccbd0b1..9dc547f 100644 --- a/sys/fs/msdosfs/msdosfs_vnops.c +++ b/sys/fs/msdosfs/msdosfs_vnops.c @@ -1880,7 +1880,7 @@ msdosfs_strategy(ap) bp->b_error = error; bp->b_ioflags |= BIO_ERROR; bufdone(bp); - return (error); + return (0); } if ((long)bp->b_blkno == -1) vfs_bio_clrbuf(bp); diff --git a/sys/fs/ntfs/ntfs_vnops.c b/sys/fs/ntfs/ntfs_vnops.c index 76c3c64..ee62a5c 100644 --- a/sys/fs/ntfs/ntfs_vnops.c +++ b/sys/fs/ntfs/ntfs_vnops.c @@ -339,7 +339,7 @@ ntfs_strategy(ap) } } bufdone(bp); - return (error); + return (0); } static int diff --git a/sys/fs/nwfs/nwfs_vnops.c b/sys/fs/nwfs/nwfs_vnops.c index 9dcd9aa..ca0a887 100644 --- a/sys/fs/nwfs/nwfs_vnops.c +++ b/sys/fs/nwfs/nwfs_vnops.c @@ -804,7 +804,7 @@ static int nwfs_strategy (ap) */ if ((bp->b_flags & B_ASYNC) == 0 ) error = nwfs_doio(ap->a_vp, bp, cr, td); - return (error); + return (0); } diff --git a/sys/fs/smbfs/smbfs_vnops.c b/sys/fs/smbfs/smbfs_vnops.c index e34ebe2..9b1e76d 100644 --- a/sys/fs/smbfs/smbfs_vnops.c +++ b/sys/fs/smbfs/smbfs_vnops.c @@ -864,7 +864,7 @@ smbfs_strategy (ap) if ((bp->b_flags & B_ASYNC) == 0 ) error = smbfs_doio(ap->a_vp, bp, cr, td); - return error; + return (0); } int diff --git a/sys/geom/geom_vfs.c b/sys/geom/geom_vfs.c index 0621eff..86c909d 100644 --- a/sys/geom/geom_vfs.c +++ b/sys/geom/geom_vfs.c @@ -93,10 +93,23 @@ g_vfs_strategy(struct bufobj *bo, struct buf *bp) { struct g_consumer *cp; struct bio *bip; + int vfslocked; cp = bo->bo_private; G_VALID_CONSUMER(cp); + /* + * If the the provider has orphaned us, just return EXIO. + */ + if (cp->provider == NULL) { + bp->b_error = ENXIO; + bp->b_ioflags |= BIO_ERROR; + vfslocked = VFS_LOCK_GIANT(((struct mount *)NULL)); + bufdone(bp); + VFS_UNLOCK_GIANT(vfslocked); + return; + } + bip = g_alloc_bio(); bip->bio_cmd = bp->b_iocmd; bip->bio_offset = bp->b_iooffset; @@ -110,18 +123,20 @@ g_vfs_strategy(struct bufobj *bo, struct buf *bp) static void g_vfs_orphan(struct g_consumer *cp) { + struct g_geom *gp; + struct bufobj *bo; + + g_topology_assert(); + + gp = cp->geom; + bo = gp->softc; + g_trace(G_T_TOPOLOGY, "g_vfs_orphan(%p(%s))", cp, gp->name); + if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0) + g_access(cp, -cp->acr, -cp->acw, -cp->ace); + g_detach(cp); /* - * Don't do anything here yet. - * - * Ideally we should detach the consumer already now, but that - * leads to a locking requirement in the I/O path to see if we have - * a consumer or not. Considering how ugly things are going to get - * anyway as none of our filesystems are graceful about i/o errors, - * this is not important right now. - * - * Down the road, this is the place where we could give the user - * a "Abort, Retry or Ignore" option to replace the media again. + * Do not destroy the geom. Filesystem will do this during unmount. */ } diff --git a/sys/gnu/fs/ext2fs/ext2_vnops.c b/sys/gnu/fs/ext2fs/ext2_vnops.c index f81d509..1b5023c 100644 --- a/sys/gnu/fs/ext2fs/ext2_vnops.c +++ b/sys/gnu/fs/ext2fs/ext2_vnops.c @@ -1399,7 +1399,7 @@ ext2_strategy(ap) bp->b_error = error; bp->b_ioflags |= BIO_ERROR; bufdone(bp); - return (error); + return (0); } if ((long)bp->b_blkno == -1) vfs_bio_clrbuf(bp); diff --git a/sys/gnu/fs/reiserfs/reiserfs_vnops.c b/sys/gnu/fs/reiserfs/reiserfs_vnops.c index e6323ea..12fe409 100644 --- a/sys/gnu/fs/reiserfs/reiserfs_vnops.c +++ b/sys/gnu/fs/reiserfs/reiserfs_vnops.c @@ -350,8 +350,13 @@ reiserfs_strategy(struct vop_strategy_args /* { bp->b_ioflags |= BIO_ERROR; } + if (error) { + bp->b_ioflags |= BIO_ERROR; + bp->b_error = error; + } + bufdone(bp); - return (error); + return (0); } /* diff --git a/sys/gnu/fs/xfs/FreeBSD/xfs_vnops.c b/sys/gnu/fs/xfs/FreeBSD/xfs_vnops.c index d0efcf2..6d8d4eb 100644 --- a/sys/gnu/fs/xfs/FreeBSD/xfs_vnops.c +++ b/sys/gnu/fs/xfs/FreeBSD/xfs_vnops.c @@ -1136,7 +1136,7 @@ _xfs_strategy( bp->b_error = error; bp->b_ioflags |= BIO_ERROR; bufdone(bp); - return (error); + return (0); } if ((long)bp->b_blkno == -1) vfs_bio_clrbuf(bp); diff --git a/sys/i386/conf/DEFAULTS b/sys/i386/conf/DEFAULTS index 2450f82..1411f09 100644 --- a/sys/i386/conf/DEFAULTS +++ b/sys/i386/conf/DEFAULTS @@ -20,8 +20,8 @@ device io # I/O device device uart_ns8250 # Default partitioning schemes -options GEOM_BSD -options GEOM_MBR +options GEOM_PART_BSD +options GEOM_PART_MBR # enable support for native hardware options NATIVE diff --git a/sys/i386/i386/exception.s b/sys/i386/i386/exception.s index 0ad2597..1451fa8 100644 --- a/sys/i386/i386/exception.s +++ b/sys/i386/i386/exception.s @@ -438,9 +438,18 @@ doreti_nmi: iret outofnmi: /* - * Clear interrupts and jump to AST handling code. + * Call the callchain capture hook after turning interrupts back on. */ + movl pmc_hook,%ecx + orl %ecx,%ecx + jz doreti_exit + pushl %esp /* frame pointer */ + pushl $PMC_FN_USER_CALLCHAIN /* command */ + movl PCPU(CURTHREAD),%eax + pushl %eax /* curthread */ sti + call *%ecx + addl $12,%esp jmp doreti_ast ENTRY(end_exceptions) #endif diff --git a/sys/i386/i386/identcpu.c b/sys/i386/i386/identcpu.c index 67ff943..cf70af7 100644 --- a/sys/i386/i386/identcpu.c +++ b/sys/i386/i386/identcpu.c @@ -826,15 +826,15 @@ printcpuinfo(void) "\003SVM" /* Secure Virtual Mode */ "\004ExtAPIC" /* Extended APIC register */ "\005CR8" /* CR8 in legacy mode */ - "\006<b5>" - "\007<b6>" - "\010<b7>" + "\006ABM" /* LZCNT instruction */ + "\007SSE4A" /* SSE4A */ + "\010MAS" /* Misaligned SSE mode */ "\011Prefetch" /* 3DNow! Prefetch/PrefetchW */ - "\012<b9>" - "\013<b10>" - "\014<b11>" - "\015<b12>" - "\016<b13>" + "\012OSVW" /* OS visible workaround */ + "\013IBS" /* Instruction based sampling */ + "\014SSE5" /* SSE5 */ + "\015SKINIT" /* SKINIT/STGI */ + "\016WDT" /* Watchdog timer */ "\017<b14>" "\020<b15>" "\021<b16>" diff --git a/sys/i386/include/elf.h b/sys/i386/include/elf.h index cf2a2d2..1470173 100644 --- a/sys/i386/include/elf.h +++ b/sys/i386/include/elf.h @@ -84,18 +84,6 @@ __ElfType(Auxinfo); #define AT_BASE 7 /* Interpreter's base address. */ #define AT_FLAGS 8 /* Flags (unused for i386). */ #define AT_ENTRY 9 /* Where interpreter should transfer control. */ - -/* - * The following non-standard values are used for passing information - * from John Polstra's testbed program to the dynamic linker. These - * are expected to go away soon. - * - * Unfortunately, these overlap the Linux non-standard values, so they - * must not be used in the same context. - */ -#define AT_BRK 10 /* Starting point for sbrk and brk. */ -#define AT_DEBUG 11 /* Debugging level. */ - /* * The following non-standard values are used in Linux ELF binaries. */ diff --git a/sys/i386/include/specialreg.h b/sys/i386/include/specialreg.h index b4842e9..c3cbec7 100644 --- a/sys/i386/include/specialreg.h +++ b/sys/i386/include/specialreg.h @@ -147,7 +147,15 @@ #define AMDID2_SVM 0x00000004 #define AMDID2_EXT_APIC 0x00000008 #define AMDID2_CR8 0x00000010 +#define AMDID2_ABM 0x00000020 +#define AMDID2_SSE4A 0x00000040 +#define AMDID2_MAS 0x00000080 #define AMDID2_PREFETCH 0x00000100 +#define AMDID2_OSVW 0x00000200 +#define AMDID2_IBS 0x00000400 +#define AMDID2_SSE5 0x00000800 +#define AMDID2_SKINIT 0x00001000 +#define AMDID2_WDT 0x00002000 /* * CPUID instruction 1 eax info diff --git a/sys/i386/linux/linux_sysvec.c b/sys/i386/linux/linux_sysvec.c index 7444901..42365fb 100644 --- a/sys/i386/linux/linux_sysvec.c +++ b/sys/i386/linux/linux_sysvec.c @@ -245,8 +245,6 @@ elf_linux_fixup(register_t **stack_base, struct image_params *imgp) args = (Elf32_Auxargs *)imgp->auxargs; pos = *stack_base + (imgp->args->argc + imgp->args->envc + 2); - if (args->trace) - AUXARGS_ENTRY(pos, AT_DEBUG, 1); if (args->execfd != -1) AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd); AUXARGS_ENTRY(pos, AT_PHDR, args->phdr); diff --git a/sys/ia64/include/elf.h b/sys/ia64/include/elf.h index ec22512..faab8d1 100644 --- a/sys/ia64/include/elf.h +++ b/sys/ia64/include/elf.h @@ -82,18 +82,6 @@ __ElfType(Auxinfo); #define AT_BASE 7 /* Interpreter's base address. */ #define AT_FLAGS 8 /* Flags (unused for i386). */ #define AT_ENTRY 9 /* Where interpreter should transfer control. */ - -/* - * The following non-standard values are used for passing information - * from John Polstra's testbed program to the dynamic linker. These - * are expected to go away soon. - * - * Unfortunately, these overlap the Linux non-standard values, so they - * must not be used in the same context. - */ -#define AT_BRK 10 /* Starting point for sbrk and brk. */ -#define AT_DEBUG 11 /* Debugging level. */ - /* * The following non-standard values are used in Linux ELF binaries. */ diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c index af78e55..431ee38 100644 --- a/sys/kern/imgact_elf.c +++ b/sys/kern/imgact_elf.c @@ -97,9 +97,6 @@ SYSCTL_INT(__CONCAT(_kern_elf, __ELF_WORD_SIZE), OID_AUTO, TUNABLE_INT("kern.elf" __XSTRING(__ELF_WORD_SIZE) ".fallback_brand", &__elfN(fallback_brand)); -static int elf_trace = 0; -SYSCTL_INT(_debug, OID_AUTO, __elfN(trace), CTLFLAG_RW, &elf_trace, 0, ""); - static int elf_legacy_coredump = 0; SYSCTL_INT(_debug, OID_AUTO, __elfN(legacy_coredump), CTLFLAG_RW, &elf_legacy_coredump, 0, ""); @@ -839,7 +836,6 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp) elf_auxargs->base = addr; elf_auxargs->flags = 0; elf_auxargs->entry = entry; - elf_auxargs->trace = elf_trace; imgp->auxargs = elf_auxargs; imgp->interpreted = 0; @@ -894,12 +890,8 @@ __elfN(freebsd_fixup)(register_t **stack_base, struct image_params *imgp) base = (Elf_Addr *)*stack_base; pos = base + (imgp->args->argc + imgp->args->envc + 2); - if (args->trace) { - AUXARGS_ENTRY(pos, AT_DEBUG, 1); - } - if (args->execfd != -1) { + if (args->execfd != -1) AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd); - } AUXARGS_ENTRY(pos, AT_PHDR, args->phdr); AUXARGS_ENTRY(pos, AT_PHENT, args->phent); AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum); diff --git a/sys/kern/kern_cpu.c b/sys/kern/kern_cpu.c index 50fff53..7b0b588 100644 --- a/sys/kern/kern_cpu.c +++ b/sys/kern/kern_cpu.c @@ -144,7 +144,9 @@ static int cpufreq_attach(device_t dev) { struct cpufreq_softc *sc; + struct pcpu *pc; device_t parent; + uint64_t rate; int numdevs; CF_DEBUG("initializing %s\n", device_get_nameunit(dev)); @@ -156,7 +158,12 @@ cpufreq_attach(device_t dev) CF_MTX_INIT(&sc->lock); sc->curr_level.total_set.freq = CPUFREQ_VAL_UNKNOWN; SLIST_INIT(&sc->saved_freq); - sc->max_mhz = CPUFREQ_VAL_UNKNOWN; + /* Try to get current CPU freq to use it as maximum later if needed */ + pc = cpu_get_pcpu(dev); + if (cpu_est_clockrate(pc->pc_cpuid, &rate) == 0) + sc->max_mhz = rate / 1000000; + else + sc->max_mhz = CPUFREQ_VAL_UNKNOWN; /* * Only initialize one set of sysctls for all CPUs. In the future, diff --git a/sys/kern/kern_mbuf.c b/sys/kern/kern_mbuf.c index 03581a4..a7810ef 100644 --- a/sys/kern/kern_mbuf.c +++ b/sys/kern/kern_mbuf.c @@ -120,7 +120,6 @@ tunable_mbinit(void *dummy) } SYSINIT(tunable_mbinit, SI_SUB_TUNABLES, SI_ORDER_MIDDLE, tunable_mbinit, NULL); -/* XXX: These should be tuneables. Can't change UMA limits on the fly. */ static int sysctl_nmbclusters(SYSCTL_HANDLER_ARGS) { diff --git a/sys/kern/subr_kobj.c b/sys/kern/subr_kobj.c index 4e2f096..bc36667 100644 --- a/sys/kern/subr_kobj.c +++ b/sys/kern/subr_kobj.c @@ -60,6 +60,19 @@ static struct mtx kobj_mtx; static int kobj_mutex_inited; static int kobj_next_id = 1; +/* + * In the event that kobj_mtx has not been initialized yet, + * we will ignore it, and run without locks in order to support + * use of KOBJ before mutexes are available. This early in the boot + * process, everything is single threaded and so races should not + * happen. This is used to provide the PMAP layer on PowerPC, as well + * as board support. + */ + +#define KOBJ_LOCK() if (kobj_mutex_inited) mtx_lock(&kobj_mtx); +#define KOBJ_UNLOCK() if (kobj_mutex_inited) mtx_unlock(&kobj_mtx); +#define KOBJ_ASSERT(what) if (kobj_mutex_inited) mtx_assert(&kobj_mtx,what); + SYSCTL_UINT(_kern, OID_AUTO, kobj_methodcount, CTLFLAG_RD, &kobj_next_id, 0, ""); @@ -74,12 +87,6 @@ kobj_init_mutex(void *arg) SYSINIT(kobj, SI_SUB_LOCK, SI_ORDER_ANY, kobj_init_mutex, NULL); -void -kobj_machdep_init(void) -{ - kobj_init_mutex(NULL); -} - /* * This method structure is used to initialise new caches. Since the * desc pointer is NULL, it is guaranteed never to match any read @@ -99,8 +106,8 @@ kobj_error_method(void) static void kobj_register_method(struct kobjop_desc *desc) { + KOBJ_ASSERT(MA_OWNED); - mtx_assert(&kobj_mtx, MA_OWNED); if (desc->id == 0) { desc->id = kobj_next_id++; } @@ -117,7 +124,7 @@ kobj_class_compile_common(kobj_class_t cls, kobj_ops_t ops) kobj_method_t *m; int i; - mtx_assert(&kobj_mtx, MA_OWNED); + KOBJ_ASSERT(MA_OWNED); /* * Don't do anything if we are already compiled. @@ -145,7 +152,7 @@ kobj_class_compile(kobj_class_t cls) { kobj_ops_t ops; - mtx_assert(&kobj_mtx, MA_NOTOWNED); + KOBJ_ASSERT(MA_NOTOWNED); /* * Allocate space for the compiled ops table. @@ -154,7 +161,7 @@ kobj_class_compile(kobj_class_t cls) if (!ops) panic("kobj_compile_methods: out of memory"); - mtx_lock(&kobj_mtx); + KOBJ_LOCK(); /* * We may have lost a race for kobj_class_compile here - check @@ -162,28 +169,30 @@ kobj_class_compile(kobj_class_t cls) * class. */ if (cls->ops) { - mtx_unlock(&kobj_mtx); + KOBJ_UNLOCK(); free(ops, M_KOBJ); return; } kobj_class_compile_common(cls, ops); - mtx_unlock(&kobj_mtx); + KOBJ_UNLOCK(); } void kobj_class_compile_static(kobj_class_t cls, kobj_ops_t ops) { - mtx_assert(&kobj_mtx, MA_NOTOWNED); + KOBJ_ASSERT(MA_NOTOWNED); /* * Increment refs to make sure that the ops table is not freed. */ - mtx_lock(&kobj_mtx); + KOBJ_LOCK(); + cls->refs++; kobj_class_compile_common(cls, ops); - mtx_unlock(&kobj_mtx); + + KOBJ_UNLOCK(); } static kobj_method_t* @@ -254,8 +263,8 @@ kobj_class_free(kobj_class_t cls) kobj_method_t *m; void* ops = 0; - mtx_assert(&kobj_mtx, MA_NOTOWNED); - mtx_lock(&kobj_mtx); + KOBJ_ASSERT(MA_NOTOWNED); + KOBJ_LOCK(); /* * Protect against a race between kobj_create and @@ -275,7 +284,7 @@ kobj_class_free(kobj_class_t cls) cls->ops = 0; } - mtx_unlock(&kobj_mtx); + KOBJ_UNLOCK(); if (ops) free(ops, M_KOBJ); @@ -302,9 +311,9 @@ kobj_create(kobj_class_t cls, void kobj_init(kobj_t obj, kobj_class_t cls) { - mtx_assert(&kobj_mtx, MA_NOTOWNED); + KOBJ_ASSERT(MA_NOTOWNED); retry: - mtx_lock(&kobj_mtx); + KOBJ_LOCK(); /* * Consider compiling the class' method table. @@ -315,7 +324,7 @@ kobj_init(kobj_t obj, kobj_class_t cls) * because of the call to malloc - we drop the lock * and re-try. */ - mtx_unlock(&kobj_mtx); + KOBJ_UNLOCK(); kobj_class_compile(cls); goto retry; } @@ -323,7 +332,7 @@ kobj_init(kobj_t obj, kobj_class_t cls) obj->ops = cls->ops; cls->refs++; - mtx_unlock(&kobj_mtx); + KOBJ_UNLOCK(); } void @@ -337,11 +346,11 @@ kobj_delete(kobj_t obj, struct malloc_type *mtype) * after its last instance is deleted. As an optimisation, we * should defer this for a short while to avoid thrashing. */ - mtx_assert(&kobj_mtx, MA_NOTOWNED); - mtx_lock(&kobj_mtx); + KOBJ_ASSERT(MA_NOTOWNED); + KOBJ_LOCK(); cls->refs--; refs = cls->refs; - mtx_unlock(&kobj_mtx); + KOBJ_UNLOCK(); if (!refs) kobj_class_free(cls); diff --git a/sys/kern/subr_param.c b/sys/kern/subr_param.c index 3701fda..6a0745f 100644 --- a/sys/kern/subr_param.c +++ b/sys/kern/subr_param.c @@ -73,6 +73,10 @@ __FBSDID("$FreeBSD$"); #define MAXFILES (maxproc * 2) #endif +enum VM_GUEST { VM_GUEST_NO, VM_GUEST_VM, VM_GUEST_XEN }; + +static int sysctl_kern_vm_guest(SYSCTL_HANDLER_ARGS); + int hz; int tick; int maxusers; /* base tunable */ @@ -86,6 +90,7 @@ int nswbuf; int maxswzone; /* max swmeta KVA storage */ int maxbcache; /* max buffer cache KVA storage */ int maxpipekva; /* Limit on pipe KVA */ +int vm_guest; /* Running as virtual machine guest? */ u_long maxtsiz; /* max text size */ u_long dfldsiz; /* initial data size limit */ u_long maxdsiz; /* max data size */ @@ -110,6 +115,9 @@ SYSCTL_ULONG(_kern, OID_AUTO, maxssiz, CTLFLAG_RDTUN, &maxssiz, 0, "max stack size"); SYSCTL_ULONG(_kern, OID_AUTO, sgrowsiz, CTLFLAG_RDTUN, &sgrowsiz, 0, "amount to grow stack"); +SYSCTL_PROC(_kern, OID_AUTO, vm_guest, CTLFLAG_RD | CTLTYPE_STRING, + NULL, 0, sysctl_kern_vm_guest, "A", + "Virtual machine detected? (none|generic|xen)"); /* * These have to be allocated somewhere; allocating @@ -133,7 +141,18 @@ static const char *const vm_pnames[] = { NULL }; -static int +static const char *const vm_guest_sysctl_names[] = { + "none", + "generic", + "xen", + NULL +}; + + +/* + * Detect known Virtual Machine hosts by inspecting the emulated BIOS. + */ +static enum VM_GUEST detect_virtual(void) { char *sysenv; @@ -144,7 +163,7 @@ detect_virtual(void) for (i = 0; vm_bnames[i] != NULL; i++) if (strcmp(sysenv, vm_bnames[i]) == 0) { freeenv(sysenv); - return (1); + return (VM_GUEST_VM); } freeenv(sysenv); } @@ -153,11 +172,11 @@ detect_virtual(void) for (i = 0; vm_pnames[i] != NULL; i++) if (strcmp(sysenv, vm_pnames[i]) == 0) { freeenv(sysenv); - return (1); + return (VM_GUEST_VM); } freeenv(sysenv); } - return (0); + return (VM_GUEST_NO); } /* @@ -166,11 +185,15 @@ detect_virtual(void) void init_param1(void) { - +#ifndef XEN + vm_guest = detect_virtual(); +#else + vm_guest = VM_GUEST_XEN; +#endif hz = -1; TUNABLE_INT_FETCH("kern.hz", &hz); if (hz == -1) - hz = detect_virtual() ? HZ_VM : HZ; + hz = vm_guest > VM_GUEST_NO ? HZ_VM : HZ; tick = 1000000 / hz; #ifdef VM_SWZONE_SIZE_MAX @@ -257,3 +280,13 @@ init_param3(long kmempages) maxpipekva = 512 * 1024; TUNABLE_INT_FETCH("kern.ipc.maxpipekva", &maxpipekva); } + +/* + * Sysctl stringiying handler for kern.vm_guest. + */ +static int +sysctl_kern_vm_guest(SYSCTL_HANDLER_ARGS) +{ + return (SYSCTL_OUT(req, vm_guest_sysctl_names[vm_guest], + strlen(vm_guest_sysctl_names[vm_guest]))); +} diff --git a/sys/kern/subr_trap.c b/sys/kern/subr_trap.c index e7e8120..ba54524 100644 --- a/sys/kern/subr_trap.c +++ b/sys/kern/subr_trap.c @@ -44,7 +44,6 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include "opt_hwpmc_hooks.h" #include "opt_ktrace.h" #include "opt_mac.h" #ifdef __i386__ @@ -179,13 +178,6 @@ ast(struct trapframe *framep) td->td_profil_ticks = 0; td->td_pflags &= ~TDP_OWEUPC; } -#if defined(HWPMC_HOOKS) - if (td->td_pflags & TDP_CALLCHAIN) { - PMC_CALL_HOOK_UNLOCKED(td, PMC_FN_USER_CALLCHAIN, - (void *) framep); - td->td_pflags &= ~TDP_CALLCHAIN; - } -#endif if (flags & TDF_ALRMPEND) { PROC_LOCK(p); psignal(p, SIGVTALRM); diff --git a/sys/kern/tty.c b/sys/kern/tty.c index e0045ce..d6735fa 100644 --- a/sys/kern/tty.c +++ b/sys/kern/tty.c @@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$"); #include <sys/cons.h> #include <sys/fcntl.h> #include <sys/file.h> +#include <sys/filedesc.h> #include <sys/filio.h> #ifdef COMPAT_43TTY #include <sys/ioctl_compat.h> @@ -870,10 +871,10 @@ tty_alloc(struct ttydevsw *tsw, void *sc, struct mtx *mutex) tty_init_termios(tp); - cv_init(&tp->t_inwait, "tty input"); - cv_init(&tp->t_outwait, "tty output"); - cv_init(&tp->t_bgwait, "tty background"); - cv_init(&tp->t_dcdwait, "tty dcd"); + cv_init(&tp->t_inwait, "ttyinp"); + cv_init(&tp->t_outwait, "ttyout"); + cv_init(&tp->t_bgwait, "ttybgw"); + cv_init(&tp->t_dcdwait, "ttydcd"); ttyinq_init(&tp->t_inq); ttyoutq_init(&tp->t_outq); @@ -883,7 +884,7 @@ tty_alloc(struct ttydevsw *tsw, void *sc, struct mtx *mutex) tp->t_mtx = mutex; } else { tp->t_mtx = &tp->t_mtxobj; - mtx_init(&tp->t_mtxobj, "tty lock", NULL, MTX_DEF); + mtx_init(&tp->t_mtxobj, "ttylck", NULL, MTX_DEF); } knlist_init(&tp->t_inpoll.si_note, tp->t_mtx, NULL, NULL, NULL); @@ -1673,18 +1674,24 @@ ttyhook_defrint(struct tty *tp, char c, int flags) } int -ttyhook_register(struct tty **rtp, struct thread *td, int fd, +ttyhook_register(struct tty **rtp, struct proc *p, int fd, struct ttyhook *th, void *softc) { struct tty *tp; struct file *fp; struct cdev *dev; struct cdevsw *cdp; + struct filedesc *fdp; int error; /* Validate the file descriptor. */ - if (fget(td, fd, &fp) != 0) - return (EINVAL); + if ((fdp = p->p_fd) == NULL) + return (EBADF); + FILEDESC_SLOCK(fdp); + if ((fp = fget_locked(fdp, fd)) == NULL || fp->f_ops == &badfileops) { + FILEDESC_SUNLOCK(fdp); + return (EBADF); + } /* Make sure the vnode is bound to a character device. */ error = EINVAL; @@ -1723,7 +1730,7 @@ ttyhook_register(struct tty **rtp, struct thread *td, int fd, done3: tty_unlock(tp); done2: dev_relthread(dev); -done1: fdrop(fp, td); +done1: FILEDESC_SUNLOCK(fdp); return (error); } diff --git a/sys/kern/tty_pts.c b/sys/kern/tty_pts.c index 9e81a6d..c767daa 100644 --- a/sys/kern/tty_pts.c +++ b/sys/kern/tty_pts.c @@ -273,6 +273,16 @@ ptsdev_ioctl(struct file *fp, u_long cmd, void *data, case FIONBIO: /* This device supports non-blocking operation. */ return (0); + case FIONREAD: + tty_lock(tp); + if (psc->pts_flags & PTS_FINISHED) { + /* Force read() to be called. */ + *(int *)data = 1; + } else { + *(int *)data = ttydisc_getc_poll(tp); + } + tty_unlock(tp); + return (0); case FIODGNAME: { struct fiodgname_arg *fgn; const char *p; diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c index 06682d5..c4840ce 100644 --- a/sys/kern/vfs_lookup.c +++ b/sys/kern/vfs_lookup.c @@ -814,6 +814,10 @@ success: if ((cnp->cn_flags & (ISLASTCN | LOCKSHARED | LOCKLEAF)) == (ISLASTCN | LOCKLEAF) && VOP_ISLOCKED(dp) != LK_EXCLUSIVE) { vn_lock(dp, LK_UPGRADE | LK_RETRY); + if (dp->v_iflag & VI_DOOMED) { + error = ENOENT; + goto bad2; + } } if (vfslocked && dvfslocked) VFS_UNLOCK_GIANT(dvfslocked); /* Only need one */ diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c index 12368c9..2b870f0 100644 --- a/sys/kern/vfs_mount.c +++ b/sys/kern/vfs_mount.c @@ -507,29 +507,20 @@ vfs_mount_destroy(struct mount *mp) { MNT_ILOCK(mp); + mp->mnt_kern_flag |= MNTK_REFEXPIRE; + if (mp->mnt_kern_flag & MNTK_MWAIT) { + mp->mnt_kern_flag &= ~MNTK_MWAIT; + wakeup(mp); + } while (mp->mnt_ref) msleep(mp, MNT_MTX(mp), PVFS, "mntref", 0); - if (mp->mnt_writeopcount > 0) { - printf("Waiting for mount point write ops\n"); - while (mp->mnt_writeopcount > 0) { - mp->mnt_kern_flag |= MNTK_SUSPEND; - msleep(&mp->mnt_writeopcount, - MNT_MTX(mp), - PZERO, "mntdestroy2", 0); - } - printf("mount point write ops completed\n"); - } - if (mp->mnt_secondary_writes > 0) { - printf("Waiting for mount point secondary write ops\n"); - while (mp->mnt_secondary_writes > 0) { - mp->mnt_kern_flag |= MNTK_SUSPEND; - msleep(&mp->mnt_secondary_writes, - MNT_MTX(mp), - PZERO, "mntdestroy3", 0); - } - printf("mount point secondary write ops completed\n"); - } - MNT_IUNLOCK(mp); + KASSERT(mp->mnt_ref == 0, + ("%s: invalid refcount in the drain path @ %s:%d", __func__, + __FILE__, __LINE__)); + if (mp->mnt_writeopcount != 0) + panic("vfs_mount_destroy: nonzero writeopcount"); + if (mp->mnt_secondary_writes != 0) + panic("vfs_mount_destroy: nonzero secondary_writes"); mp->mnt_vfc->vfc_refcount--; if (!TAILQ_EMPTY(&mp->mnt_nvnodelist)) { struct vnode *vp; @@ -538,18 +529,10 @@ vfs_mount_destroy(struct mount *mp) vprint("", vp); panic("unmount: dangling vnode"); } - MNT_ILOCK(mp); - if (mp->mnt_kern_flag & MNTK_MWAIT) - wakeup(mp); - if (mp->mnt_writeopcount != 0) - panic("vfs_mount_destroy: nonzero writeopcount"); - if (mp->mnt_secondary_writes != 0) - panic("vfs_mount_destroy: nonzero secondary_writes"); if (mp->mnt_nvnodelistsize != 0) panic("vfs_mount_destroy: nonzero nvnodelistsize"); - mp->mnt_writeopcount = -1000; - mp->mnt_nvnodelistsize = -1000; - mp->mnt_secondary_writes = -1000; + if (mp->mnt_lockref != 0) + panic("vfs_mount_destroy: nonzero lock refcount"); MNT_IUNLOCK(mp); #ifdef MAC mac_mount_destroy(mp); diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 16373b1..eb02693 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -345,7 +345,7 @@ vfs_busy(struct mount *mp, int flags) MNT_ILOCK(mp); MNT_REF(mp); if (mp->mnt_kern_flag & MNTK_UNMOUNT) { - if (flags & MBF_NOWAIT) { + if (flags & MBF_NOWAIT || mp->mnt_kern_flag & MNTK_REFEXPIRE) { MNT_REL(mp); MNT_IUNLOCK(mp); return (ENOENT); diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index e4f4f8b..198009d 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -200,19 +200,21 @@ quotactl(td, uap) AUDIT_ARG(uid, uap->uid); if (jailed(td->td_ucred) && !prison_quotas) return (EPERM); - NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE | AUDITVNODE1, + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1, UIO_USERSPACE, uap->path, td); if ((error = namei(&nd)) != 0) return (error); vfslocked = NDHASGIANT(&nd); NDFREE(&nd, NDF_ONLY_PNBUF); mp = nd.ni_vp->v_mount; - if ((error = vfs_busy(mp, 0))) { - vrele(nd.ni_vp); + vfs_ref(mp); + vput(nd.ni_vp); + error = vfs_busy(mp, 0); + vfs_rel(mp); + if (error) { VFS_UNLOCK_GIANT(vfslocked); return (error); } - vrele(nd.ni_vp); error = VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, td); vfs_unbusy(mp); VFS_UNLOCK_GIANT(vfslocked); @@ -306,6 +308,12 @@ kern_statfs(struct thread *td, char *path, enum uio_seg pathseg, vfs_ref(mp); NDFREE(&nd, NDF_ONLY_PNBUF); vput(nd.ni_vp); + error = vfs_busy(mp, 0); + vfs_rel(mp); + if (error) { + VFS_UNLOCK_GIANT(vfslocked); + return (error); + } #ifdef MAC error = mac_mount_check_stat(td->td_ucred, mp); if (error) @@ -329,7 +337,7 @@ kern_statfs(struct thread *td, char *path, enum uio_seg pathseg, } *buf = *sp; out: - vfs_rel(mp); + vfs_unbusy(mp); VFS_UNLOCK_GIANT(vfslocked); if (mtx_owned(&Giant)) printf("statfs(%d): %s: %d\n", vfslocked, path, error); @@ -391,6 +399,10 @@ kern_fstatfs(struct thread *td, int fd, struct statfs *buf) error = EBADF; goto out; } + error = vfs_busy(mp, 0); + vfs_rel(mp); + if (error) + goto out; #ifdef MAC error = mac_mount_check_stat(td->td_ucred, mp); if (error) @@ -415,7 +427,7 @@ kern_fstatfs(struct thread *td, int fd, struct statfs *buf) *buf = *sp; out: if (mp) - vfs_rel(mp); + vfs_unbusy(mp); VFS_UNLOCK_GIANT(vfslocked); return (error); } diff --git a/sys/mips/conf/DEFAULTS b/sys/mips/conf/DEFAULTS index 18a9a26..dc480ce 100644 --- a/sys/mips/conf/DEFAULTS +++ b/sys/mips/conf/DEFAULTS @@ -9,5 +9,5 @@ device mem device uart_ns8250 -options GEOM_BSD -options GEOM_MBR +options GEOM_PART_BSD +options GEOM_PART_MBR diff --git a/sys/mips/include/elf.h b/sys/mips/include/elf.h index fc1035e..6e48ec1 100644 --- a/sys/mips/include/elf.h +++ b/sys/mips/include/elf.h @@ -40,9 +40,11 @@ /* Information taken from MIPS ABI supplemental */ -#include <sys/elf32.h> /* Definitions common to all 32 bit architectures. */ - +#ifndef __ELF_WORD_SIZE #define __ELF_WORD_SIZE 32 /* Used by <sys/elf_generic.h> */ +#endif +#include <sys/elf32.h> /* Definitions common to all 32 bit architectures. */ +#include <sys/elf64.h> /* Definitions common to all 64 bit architectures. */ #include <sys/elf_generic.h> #define ELF_ARCH EM_MIPS @@ -114,6 +116,16 @@ typedef union { Elf32_Word gt_bytes; /* This many bytes would be used */ } gt_entry; /* Subsequent entries in section */ } Elf32_gptab; +typedef union { + struct { + Elf64_Word gt_current_g_value; /* -G val used in compilation */ + Elf64_Word gt_unused; /* Not used */ + } gt_header; /* First entry in section */ + struct { + Elf64_Word gt_g_value; /* If this val were used for -G */ + Elf64_Word gt_bytes; /* This many bytes would be used */ + } gt_entry; /* Subsequent entries in section */ +} Elf64_gptab; /* * Entry found in sections of type SHT_MIPS_REGINFO. @@ -123,6 +135,11 @@ typedef struct { Elf32_Word ri_cprmask[4]; /* Coprocessor registers used */ Elf32_Sword ri_gp_value; /* $gp register value */ } Elf32_RegInfo; +typedef struct { + Elf64_Word ri_gprmask; /* General registers used */ + Elf64_Word ri_cprmask[4]; /* Coprocessor registers used */ + Elf64_Sword ri_gp_value; /* $gp register value */ +} Elf64_RegInfo; /* @@ -147,10 +164,38 @@ typedef struct { #define R_MIPS_CALLHI16 30 /* upper 16 bit GOT entry for function */ #define R_MIPS_CALLLO16 31 /* lower 16 bit GOT entry for function */ -#define R_TYPE(name) __CONCAT(R_MIPS_,name) +/* + * These are from the 64-bit Irix ELF ABI + */ +#define R_MIPS_SHIFT5 16 +#define R_MIPS_SHIFT6 17 +#define R_MIPS_64 18 +#define R_MIPS_GOT_DISP 19 +#define R_MIPS_GOT_PAGE 20 +#define R_MIPS_GOT_OFST 21 +#define R_MIPS_GOT_HI16 22 +#define R_MIPS_GOT_LO16 23 +#define R_MIPS_SUB 24 +#define R_MIPS_INSERT_A 25 +#define R_MIPS_INSERT_B 26 +#define R_MIPS_DELETE 27 +#define R_MIPS_HIGHER 28 +#define R_MIPS_HIGHEST 29 +#define R_MIPS_SCN_DISP 32 +#define R_MIPS_REL16 33 +#define R_MIPS_ADD_IMMEDIATE 34 +#define R_MIPS_PJUMP 35 +#define R_MIPS_ERLGOT 36 + +#define R_MIPS_max 37 +#define R_TYPE(name) __CONCAT(R_MIPS_,name) /* Define "machine" characteristics */ +#if __ELF_WORD_SIZE == 32 #define ELF_TARG_CLASS ELFCLASS32 +#else +#define ELF_TARG_CLASS ELFCLASS64 +#endif #ifdef __MIPSEB__ #define ELF_TARG_DATA ELFDATA2MSB #else @@ -159,23 +204,30 @@ typedef struct { #define ELF_TARG_MACH EM_MIPS #define ELF_TARG_VER 1 - /* * Auxiliary vector entries for passing information to the interpreter. * * The i386 supplement to the SVR4 ABI specification names this "auxv_t", * but POSIX lays claim to all symbols ending with "_t". */ - typedef struct { /* Auxiliary vector entry on initial stack */ int a_type; /* Entry type. */ union { - long a_val; /* Integer value. */ + int a_val; /* Integer value. */ void *a_ptr; /* Address. */ void (*a_fcn)(void); /* Function pointer (not used). */ } a_un; } Elf32_Auxinfo; +typedef struct { /* Auxiliary vector entry on initial stack */ + long a_type; /* Entry type. */ + union { + long a_val; /* Integer value. */ + void *a_ptr; /* Address. */ + void (*a_fcn)(void); /* Function pointer (not used). */ + } a_un; +} Elf64_Auxinfo; + __ElfType(Auxinfo); /* Values for a_type. */ @@ -189,18 +241,6 @@ __ElfType(Auxinfo); #define AT_BASE 7 /* Interpreter's base address. */ #define AT_FLAGS 8 /* Flags (unused for i386). */ #define AT_ENTRY 9 /* Where interpreter should transfer control. */ - -/* - * The following non-standard values are used for passing information - * from John Polstra's testbed program to the dynamic linker. These - * are expected to go away soon. - * - * Unfortunately, these overlap the Linux non-standard values, so they - * must not be used in the same context. - */ -#define AT_BRK 10 /* Starting point for sbrk and brk. */ -#define AT_DEBUG 11 /* Debugging level. */ - /* * The following non-standard values are used in Linux ELF binaries. */ diff --git a/sys/mips/mips/elf_machdep.c b/sys/mips/mips/elf_machdep.c index dc08bc2..163d0ee 100644 --- a/sys/mips/mips/elf_machdep.c +++ b/sys/mips/mips/elf_machdep.c @@ -93,22 +93,6 @@ SYSINIT(elf32, SI_SUB_EXEC, SI_ORDER_ANY, (sysinit_cfunc_t) elf32_insert_brand_entry, &freebsd_brand_info); -static Elf32_Brandinfo freebsd_brand_oinfo = { - .brand = ELFOSABI_FREEBSD, - .machine = EM_MIPS, - .compat_3_brand = "FreeBSD", - .emul_path = NULL, - .interp_path = "/usr/libexec/ld-elf.so.1", - .sysvec = &elf32_freebsd_sysvec, - .interp_newpath = NULL, - .flags = 0 -}; - -SYSINIT(oelf32, SI_SUB_EXEC, SI_ORDER_ANY, - (sysinit_cfunc_t) elf32_insert_brand_entry, - &freebsd_brand_oinfo); - - void elf32_dump_thread(struct thread *td __unused, void *dst __unused, size_t *off __unused) diff --git a/sys/modules/Makefile b/sys/modules/Makefile index eee15c1..97d7cf2 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -30,9 +30,6 @@ SUBDIR= ${_3dfx} \ ${_asr} \ ata \ ath \ - ath_rate_amrr \ - ath_rate_onoe \ - ath_rate_sample \ aue \ ${_auxio} \ axe \ diff --git a/sys/modules/ath/Makefile b/sys/modules/ath/Makefile index 4f478f6..068d337 100644 --- a/sys/modules/ath/Makefile +++ b/sys/modules/ath/Makefile @@ -29,44 +29,80 @@ # $FreeBSD$ # -.PATH: ${.CURDIR}/../../dev/ath \ - ${.CURDIR}/../../dev/ath/ath_hal \ - ${.CURDIR}/../../dev/ath/ath_hal/ar5210 \ - ${.CURDIR}/../../dev/ath/ath_hal/ar5211 \ - ${.CURDIR}/../../dev/ath/ath_hal/ar5212 \ - ${.CURDIR}/../../dev/ath/ath_hal/ar5416 +ATH_RATE?= sample # tx rate control algorithm -AR5210_SRCS=ah_eeprom_v1.c \ +.PATH: ${.CURDIR}/../../dev/ath +.PATH: ${.CURDIR}/../../dev/ath/ath_hal + +KMOD= if_ath +SRCS= if_ath.c if_ath_pci.c +# NB: v3 eeprom support used by both AR5211 and AR5212; just include it +SRCS+= ah_osdep.c ah.c ah_regdomain.c ah_eeprom_v3.c +SRCS+= device_if.h bus_if.h pci_if.h opt_inet.h opt_ath.h opt_ah.h + +# +# AR5210 support; these are first generation 11a-only devices. +# +.PATH: ${.CURDIR}/../../dev/ath/ath_hal/ar5210 +SRCS+= ah_eeprom_v1.c \ ar5210_attach.c ar5210_beacon.c ar5210_interrupts.c \ ar5210_keycache.c ar5210_misc.c ar5210_phy.c ar5210_power.c \ ar5210_recv.c ar5210_reset.c ar5210_xmit.c -AR5211_SRCS=ar5211_attach.c ar5211_beacon.c ar5211_interrupts.c \ + +# +# AR5211 support; these are second generation 11b/g/a devices +# (but 11g was OFDM only and is not supported). +# +.PATH: ${.CURDIR}/../../dev/ath/ath_hal/ar5211 +SRCS+= ar5211_attach.c ar5211_beacon.c ar5211_interrupts.c \ ar5211_keycache.c ar5211_misc.c ar5211_phy.c ar5211_power.c \ ar5211_recv.c ar5211_reset.c ar5211_xmit.c -AR5212_SRCS=ar5212_ani.c ar5212_attach.c ar5212_beacon.c ar5212_eeprom.c \ + +# +# AR5212 support; this covers all other pci/cardbus legacy parts. +# +.PATH: ${.CURDIR}/../../dev/ath/ath_hal/ar5212 +SRCS+= ar5212_ani.c ar5212_attach.c ar5212_beacon.c ar5212_eeprom.c \ ar5212_gpio.c ar5212_interrupts.c ar5212_keycache.c ar5212_misc.c \ ar5212_phy.c ar5212_power.c ar5212_recv.c ar5212_reset.c \ - ar5212_rfgain.c ar5212_xmit.c \ - ar2413.c ar2425.c ar5111.c ar5112.c ar5413.c -AR5416_SRCS=ah_eeprom_v14.c \ + ar5212_rfgain.c ar5212_xmit.c +# RF backends +SRCS+= ar5111.c +SRCS+= ar5112.c +SRCS+= ar2413.c +SRCS+= ar2425.c +SRCS+= ar5413.c + +# +# AR5416, AR9160 support; these are 11n parts but only really +# supported (right now) operating in legacy mode. Note enabling +# this support requires defining AH_SUPPORT_AR5416 in opt_ah.h +# so the 11n tx/rx descriptor format is handled. +# +# NB: 9160 depends on 5416 but 5416 does not require 9160 +# +.PATH: ${.CURDIR}/../../dev/ath/ath_hal/ar5416 +SRCS+= ah_eeprom_v14.c \ ar5416_ani.c ar5416_attach.c ar5416_beacon.c ar5416_cal.c \ ar5416_cal_iq.c ar5416_cal_adcgain.c ar5416_cal_adcdc.c \ ar5416_eeprom.c ar5416_gpio.c ar5416_interrupts.c ar5416_keycache.c \ ar5416_misc.c ar5416_phy.c ar5416_power.c ar5416_recv.c \ - ar5416_reset.c ar5416_xmit.c \ - ar2133.c -AR9160_SRCS=ar9160_attach.c + ar5416_reset.c ar5416_xmit.c +SRCS+= ar9160_attach.c +# RF backend for 5416 and 9160 +SRCS+= ar2133.c -KMOD= if_ath -SRCS= if_ath.c if_ath_pci.c -# NB: v3 eeprom support used by both AR5211 and AR5212; just include it -SRCS+= ah_osdep.c ah.c ah_regdomain.c ah_eeprom_v3.c -SRCS+= ${AR5210_SRCS} -SRCS+= ${AR5211_SRCS} -SRCS+= ${AR5212_SRCS} -SRCS+= ${AR5416_SRCS} -SRCS+= ${AR9160_SRCS} -SRCS+= device_if.h bus_if.h pci_if.h opt_inet.h opt_ath.h opt_ah.h +# NB: rate control is bound to the driver by symbol names so only pick one +.if ${ATH_RATE} == "sample" +.PATH: ${.CURDIR}/../../dev/ath/ath_rate/sample +SRCS+= sample.c opt_wlan.h +.elif ${ATH_RATE} == "onoe" +.PATH: ${.CURDIR}/../../dev/ath/ath_rate/onoe +SRCS+= onoe.c +.elif ${ATH_RATE} == "amrr" +.PATH: ${.CURDIR}/../../dev/ath/ath_rate/amrr +SRCS+= amrr.c +.endif CFLAGS+= -I. -I${.CURDIR}/../../dev/ath -I${.CURDIR}/../../dev/ath/ath_hal diff --git a/sys/modules/ath_rate_amrr/Makefile b/sys/modules/ath_rate_amrr/Makefile deleted file mode 100644 index cbeea9c..0000000 --- a/sys/modules/ath_rate_amrr/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -# -# Copyright (c) 2004-2008 Sam Leffler, Errno Consulting -# 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, -# without modification. -# 2. Redistributions in binary form must reproduce at minimum a disclaimer -# similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any -# redistribution must be conditioned upon including a substantially -# similar Disclaimer requirement for further binary redistribution. -# -# NO WARRANTY -# 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 NONINFRINGEMENT, MERCHANTIBILITY -# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -# THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. -# -# $FreeBSD$ -# - -.PATH: ${.CURDIR}/../../dev/ath/ath_rate/amrr - -KMOD= ath_rate -SRCS= amrr.c -SRCS+= device_if.h bus_if.h pci_if.h opt_inet.h opt_ah.h opt_wlan.h - -CFLAGS+= -I. -I${.CURDIR}/../../dev/ath -I${.CURDIR}/../../dev/ath/ath_hal - -.include <bsd.kmod.mk> diff --git a/sys/modules/ath_rate_onoe/Makefile b/sys/modules/ath_rate_onoe/Makefile deleted file mode 100644 index fe725e4..0000000 --- a/sys/modules/ath_rate_onoe/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -# -# Copyright (c) 2004-2008 Sam Leffler, Errno Consulting -# 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, -# without modification. -# 2. Redistributions in binary form must reproduce at minimum a disclaimer -# similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any -# redistribution must be conditioned upon including a substantially -# similar Disclaimer requirement for further binary redistribution. -# -# NO WARRANTY -# 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 NONINFRINGEMENT, MERCHANTIBILITY -# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -# THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. -# -# $FreeBSD$ -# - -.PATH: ${.CURDIR}/../../dev/ath/ath_rate/onoe - -KMOD= ath_rate -SRCS= onoe.c -SRCS+= device_if.h bus_if.h pci_if.h opt_inet.h opt_ah.h opt_wlan.h - -CFLAGS+= -I. -I${.CURDIR}/../../dev/ath -I${.CURDIR}/../../dev/ath/ath_hal - -.include <bsd.kmod.mk> diff --git a/sys/modules/ath_rate_sample/Makefile b/sys/modules/ath_rate_sample/Makefile deleted file mode 100644 index c179d10..0000000 --- a/sys/modules/ath_rate_sample/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -# -# Copyright (c) 2004-2008 Sam Leffler, Errno Consulting -# 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, -# without modification. -# 2. Redistributions in binary form must reproduce at minimum a disclaimer -# similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any -# redistribution must be conditioned upon including a substantially -# similar Disclaimer requirement for further binary redistribution. -# -# NO WARRANTY -# 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 NONINFRINGEMENT, MERCHANTIBILITY -# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -# THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. -# -# $FreeBSD$ -# - -.PATH: ${.CURDIR}/../../dev/ath/ath_rate/sample - -KMOD= ath_rate -SRCS= sample.c -SRCS+= device_if.h bus_if.h pci_if.h opt_inet.h opt_ah.h opt_wlan.h - -CFLAGS+= -I. -I${.CURDIR}/../../dev/ath -I${.CURDIR}/../../dev/ath/ath_hal - -.include <bsd.kmod.mk> diff --git a/sys/modules/cxgb/Makefile b/sys/modules/cxgb/Makefile index 7d56988..71cbb7a 100644 --- a/sys/modules/cxgb/Makefile +++ b/sys/modules/cxgb/Makefile @@ -25,7 +25,7 @@ _toe_header = ${_sysdir}/netinet/toedev.h .if exists(${_toe_header}) _toecore = toecore -_tom = tom +#_tom = tom .endif .if ${MACHINE_ARCH} == "i386" && exists(${_toe_header}) diff --git a/sys/net/ieee8023ad_lacp.c b/sys/net/ieee8023ad_lacp.c index 27cf480..bd44e23 100644 --- a/sys/net/ieee8023ad_lacp.c +++ b/sys/net/ieee8023ad_lacp.c @@ -901,6 +901,7 @@ lacp_aggregator_bandwidth(struct lacp_aggregator *la) static void lacp_select_active_aggregator(struct lacp_softc *lsc) { + struct lagg_softc *sc = lsc->lsc_softc; struct lacp_aggregator *la; struct lacp_aggregator *best_la = NULL; uint64_t best_speed = 0; @@ -956,6 +957,7 @@ lacp_select_active_aggregator(struct lacp_softc *lsc) #endif /* defined(LACP_DEBUG) */ if (lsc->lsc_active_aggregator != best_la) { + sc->sc_ifp->if_baudrate = best_speed; lsc->lsc_active_aggregator = best_la; lacp_update_portmap(lsc); if (best_la) { diff --git a/sys/net/if.c b/sys/net/if.c index 5142a5c..070202c 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -60,6 +60,7 @@ #include <sys/jail.h> #include <sys/vimage.h> #include <machine/stdarg.h> +#include <vm/uma.h> #include <net/if.h> #include <net/if_arp.h> @@ -157,7 +158,7 @@ static struct knlist ifklist; #endif int ifqmaxlen = IFQ_MAXLEN; -struct mtx ifnet_lock; +struct rwlock ifnet_lock; static if_com_alloc_t *if_com_alloc[256]; static if_com_free_t *if_com_free[256]; @@ -190,14 +191,23 @@ MALLOC_DEFINE(M_IFNET, "ifnet", "interface internals"); MALLOC_DEFINE(M_IFADDR, "ifaddr", "interface address"); MALLOC_DEFINE(M_IFMADDR, "ether_multi", "link-level multicast address"); +static struct ifnet * +ifnet_byindex_locked(u_short idx) +{ + INIT_VNET_NET(curvnet); + struct ifnet *ifp; + + ifp = V_ifindex_table[idx].ife_ifnet; + return (ifp); +} + struct ifnet * ifnet_byindex(u_short idx) { - INIT_VNET_NET(curvnet); struct ifnet *ifp; IFNET_RLOCK(); - ifp = V_ifindex_table[idx].ife_ifnet; + ifp = ifnet_byindex_locked(idx); IFNET_RUNLOCK(); return (ifp); } @@ -218,7 +228,7 @@ ifaddr_byindex(u_short idx) struct ifaddr *ifa; IFNET_RLOCK(); - ifa = ifnet_byindex(idx)->if_addr; + ifa = ifnet_byindex_locked(idx)->if_addr; IFNET_RUNLOCK(); return (ifa); } @@ -498,7 +508,7 @@ if_free_type(struct ifnet *ifp, u_char type) ifnet_setbyindex(ifp->if_index, NULL); /* XXX: should be locked with if_findindex() */ - while (V_if_index > 0 && ifnet_byindex(V_if_index) == NULL) + while (V_if_index > 0 && ifnet_byindex_locked(V_if_index) == NULL) V_if_index--; IFNET_WUNLOCK(); @@ -1110,7 +1120,7 @@ if_rtdel(struct radix_node *rn, void *arg) return (0); err = rtrequest_fib(RTM_DELETE, rt_key(rt), rt->rt_gateway, - rt_mask(rt), rt->rt_flags, + rt_mask(rt), rt->rt_flags|RTF_RNH_LOCKED, (struct rtentry **) NULL, rt->rt_fibnum); if (err) { log(LOG_WARNING, "if_rtdel: error %d\n", err); @@ -1366,6 +1376,9 @@ done: return (ifa); } +#include <net/route.h> +#include <net/if_llatbl.h> + /* * Default action when installing a route with a Link Level gateway. * Lookup an appropriate real ifa to point to. diff --git a/sys/net/if_arcsubr.c b/sys/net/if_arcsubr.c index 0f5fef3..0089d13 100644 --- a/sys/net/if_arcsubr.c +++ b/sys/net/if_arcsubr.c @@ -64,6 +64,7 @@ #include <net/if_arc.h> #include <net/if_arp.h> #include <net/bpf.h> +#include <net/if_llatbl.h> #if defined(INET) || defined(INET6) #include <netinet/in.h> @@ -108,6 +109,7 @@ arc_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, u_int8_t atype, adst; int loop_copy = 0; int isphds; + struct llentry *lle; if (!((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING))) @@ -127,7 +129,7 @@ arc_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, else if (ifp->if_flags & IFF_NOARP) adst = ntohl(SIN(dst)->sin_addr.s_addr) & 0xFF; else { - error = arpresolve(ifp, rt0, m, dst, &adst); + error = arpresolve(ifp, rt0, m, dst, &adst, &lle); if (error) return (error == EWOULDBLOCK ? 0 : error); } @@ -165,7 +167,7 @@ arc_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, #endif #ifdef INET6 case AF_INET6: - error = nd6_storelladdr(ifp, rt0, m, dst, (u_char *)&adst); + error = nd6_storelladdr(ifp, m, dst, (u_char *)&adst, &lle); if (error) return (error); atype = ARCTYPE_INET6; diff --git a/sys/net/if_atmsubr.c b/sys/net/if_atmsubr.c index 9d1a7fa..7e36187 100644 --- a/sys/net/if_atmsubr.c +++ b/sys/net/if_atmsubr.c @@ -153,22 +153,11 @@ atm_output(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst, case AF_INET: case AF_INET6: { - struct rtentry *rt = NULL; - /* - * check route - */ - if (rt0 != NULL) { - error = rt_check(&rt, &rt0, dst); - if (error) - goto bad; - RT_UNLOCK(rt); - } - if (dst->sa_family == AF_INET6) etype = ETHERTYPE_IPV6; else etype = ETHERTYPE_IP; - if (!atmresolve(rt, m, dst, &atmdst)) { + if (!atmresolve(rt0, m, dst, &atmdst)) { m = NULL; /* XXX: atmresolve already free'd it */ senderr(EHOSTUNREACH); diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index 4524fdd..73a08dd 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -64,6 +64,7 @@ #include <net/ethernet.h> #include <net/if_bridgevar.h> #include <net/if_vlan_var.h> +#include <net/if_llatbl.h> #include <net/pf_mtag.h> #include <net/vnet.h> @@ -87,6 +88,7 @@ #include <netipx/ipx.h> #include <netipx/ipx_if.h> #endif + int (*ef_inputp)(struct ifnet*, struct ether_header *eh, struct mbuf *m); int (*ef_outputp)(struct ifnet *ifp, struct mbuf **mp, struct sockaddr *dst, short *tp, int *hlen); @@ -151,6 +153,7 @@ static int ether_ipfw; #endif #endif + /* * Ethernet output routine. * Encapsulate a packet of type family for the local net. @@ -164,6 +167,7 @@ ether_output(struct ifnet *ifp, struct mbuf *m, short type; int error, hdrcmplt = 0; u_char esrc[ETHER_ADDR_LEN], edst[ETHER_ADDR_LEN]; + struct llentry *lle = NULL; struct ether_header *eh; struct pf_mtag *t; int loop_copy = 1; @@ -186,7 +190,7 @@ ether_output(struct ifnet *ifp, struct mbuf *m, switch (dst->sa_family) { #ifdef INET case AF_INET: - error = arpresolve(ifp, rt0, m, dst, edst); + error = arpresolve(ifp, rt0, m, dst, edst, &lle); if (error) return (error == EWOULDBLOCK ? 0 : error); type = htons(ETHERTYPE_IP); @@ -221,7 +225,7 @@ ether_output(struct ifnet *ifp, struct mbuf *m, #endif #ifdef INET6 case AF_INET6: - error = nd6_storelladdr(ifp, rt0, m, dst, (u_char *)edst); + error = nd6_storelladdr(ifp, m, dst, (u_char *)edst, &lle); if (error) return error; type = htons(ETHERTYPE_IPV6); @@ -289,6 +293,17 @@ ether_output(struct ifnet *ifp, struct mbuf *m, senderr(EAFNOSUPPORT); } + if (lle != NULL && (lle->la_flags & LLE_IFADDR)) { + int csum_flags = 0; + if (m->m_pkthdr.csum_flags & CSUM_IP) + csum_flags |= (CSUM_IP_CHECKED|CSUM_IP_VALID); + if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) + csum_flags |= (CSUM_DATA_VALID|CSUM_PSEUDO_HDR); + m->m_pkthdr.csum_flags |= csum_flags; + m->m_pkthdr.csum_data = 0xffff; + return (if_simloop(ifp, m, dst->sa_family, 0)); + } + /* * Add local net header. If no space in first mbuf, * allocate another. diff --git a/sys/net/if_fddisubr.c b/sys/net/if_fddisubr.c index e37d7ae..438a6e8 100644 --- a/sys/net/if_fddisubr.c +++ b/sys/net/if_fddisubr.c @@ -55,6 +55,7 @@ #include <net/if_dl.h> #include <net/if_llc.h> #include <net/if_types.h> +#include <net/if_llatbl.h> #include <net/ethernet.h> #include <net/netisr.h> @@ -120,6 +121,7 @@ fddi_output(ifp, m, dst, rt0) int loop_copy = 0, error = 0, hdrcmplt = 0; u_char esrc[FDDI_ADDR_LEN], edst[FDDI_ADDR_LEN]; struct fddi_header *fh; + struct llentry *lle; #ifdef MAC error = mac_ifnet_check_transmit(ifp, m); @@ -137,7 +139,7 @@ fddi_output(ifp, m, dst, rt0) switch (dst->sa_family) { #ifdef INET case AF_INET: { - error = arpresolve(ifp, rt0, m, dst, edst); + error = arpresolve(ifp, rt0, m, dst, edst, &lle); if (error) return (error == EWOULDBLOCK ? 0 : error); type = htons(ETHERTYPE_IP); @@ -173,7 +175,7 @@ fddi_output(ifp, m, dst, rt0) #endif /* INET */ #ifdef INET6 case AF_INET6: - error = nd6_storelladdr(ifp, rt0, m, dst, (u_char *)edst); + error = nd6_storelladdr(ifp, m, dst, (u_char *)edst, &lle); if (error) return (error); /* Something bad happened */ type = htons(ETHERTYPE_IPV6); diff --git a/sys/net/if_fwsubr.c b/sys/net/if_fwsubr.c index 77e7b70..9d7b95b 100644 --- a/sys/net/if_fwsubr.c +++ b/sys/net/if_fwsubr.c @@ -51,6 +51,7 @@ #include <net/if_types.h> #include <net/bpf.h> #include <net/firewire.h> +#include <net/if_llatbl.h> #if defined(INET) || defined(INET6) #include <netinet/in.h> @@ -80,7 +81,6 @@ firewire_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, { struct fw_com *fc = IFP2FWC(ifp); int error, type; - struct rtentry *rt = NULL; struct m_tag *mtag; union fw_encap *enc; struct fw_hwaddr *destfw; @@ -89,6 +89,7 @@ firewire_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct mbuf *mtail; int unicast, dgl, foff; static int next_dgl; + struct llentry *lle; #ifdef MAC error = mac_ifnet_check_transmit(ifp, m); @@ -102,13 +103,6 @@ firewire_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, goto bad; } - if (rt0 != NULL) { - error = rt_check(&rt, &rt0, dst); - if (error) - goto bad; - RT_UNLOCK(rt); - } - /* * For unicast, we make a tag to store the lladdr of the * destination. This might not be the first time we have seen @@ -144,7 +138,7 @@ firewire_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, * doesn't fit into the arp model. */ if (unicast) { - error = arpresolve(ifp, rt, m, dst, (u_char *) destfw); + error = arpresolve(ifp, rt0, m, dst, (u_char *) destfw, &lle); if (error) return (error == EWOULDBLOCK ? 0 : error); } @@ -173,8 +167,8 @@ firewire_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, #ifdef INET6 case AF_INET6: if (unicast) { - error = nd6_storelladdr(fc->fc_ifp, rt, m, dst, - (u_char *) destfw); + error = nd6_storelladdr(fc->fc_ifp, m, dst, + (u_char *) destfw, &lle); if (error) return (error); } diff --git a/sys/net/if_iso88025subr.c b/sys/net/if_iso88025subr.c index 00e323a..ff82e10 100644 --- a/sys/net/if_iso88025subr.c +++ b/sys/net/if_iso88025subr.c @@ -59,6 +59,7 @@ #include <net/if_dl.h> #include <net/if_llc.h> #include <net/if_types.h> +#include <net/if_llatbl.h> #include <net/ethernet.h> #include <net/netisr.h> @@ -243,7 +244,7 @@ iso88025_output(ifp, m, dst, rt0) struct iso88025_header *th; struct iso88025_header gen_th; struct sockaddr_dl *sdl = NULL; - struct rtentry *rt = NULL; + struct llentry *lle; #ifdef MAC error = mac_ifnet_check_transmit(ifp, m); @@ -260,14 +261,8 @@ iso88025_output(ifp, m, dst, rt0) /* Calculate routing info length based on arp table entry */ /* XXX any better way to do this ? */ - if (rt0 != NULL) { - error = rt_check(&rt, &rt0, dst); - if (error) - goto bad; - RT_UNLOCK(rt); - } - if (rt && (sdl = (struct sockaddr_dl *)rt->rt_gateway)) + if (rt0 && (sdl = (struct sockaddr_dl *)rt0->rt_gateway)) if (SDL_ISO88025(sdl)->trld_rcf != 0) rif_len = TR_RCF_RIFLEN(SDL_ISO88025(sdl)->trld_rcf); @@ -289,7 +284,7 @@ iso88025_output(ifp, m, dst, rt0) switch (dst->sa_family) { #ifdef INET case AF_INET: - error = arpresolve(ifp, rt0, m, dst, edst); + error = arpresolve(ifp, rt0, m, dst, edst, &lle); if (error) return (error == EWOULDBLOCK ? 0 : error); snap_type = ETHERTYPE_IP; @@ -324,7 +319,7 @@ iso88025_output(ifp, m, dst, rt0) #endif /* INET */ #ifdef INET6 case AF_INET6: - error = nd6_storelladdr(ifp, rt0, m, dst, (u_char *)edst); + error = nd6_storelladdr(ifp, m, dst, (u_char *)edst, &lle); if (error) return (error); snap_type = ETHERTYPE_IPV6; diff --git a/sys/net/if_lagg.c b/sys/net/if_lagg.c index be6e0b8..0ab96b3 100644 --- a/sys/net/if_lagg.c +++ b/sys/net/if_lagg.c @@ -310,6 +310,7 @@ lagg_capabilities(struct lagg_softc *sc) { struct lagg_port *lp; int cap = ~0, ena = ~0; + u_long hwa = ~0UL; LAGG_WLOCK_ASSERT(sc); @@ -317,14 +318,18 @@ lagg_capabilities(struct lagg_softc *sc) SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { cap &= lp->lp_ifp->if_capabilities; ena &= lp->lp_ifp->if_capenable; + hwa &= lp->lp_ifp->if_hwassist; } cap = (cap == ~0 ? 0 : cap); ena = (ena == ~0 ? 0 : ena); + hwa = (hwa == ~0 ? 0 : hwa); if (sc->sc_ifp->if_capabilities != cap || - sc->sc_ifp->if_capenable != ena) { + sc->sc_ifp->if_capenable != ena || + sc->sc_ifp->if_hwassist != hwa) { sc->sc_ifp->if_capabilities = cap; sc->sc_ifp->if_capenable = ena; + sc->sc_ifp->if_hwassist = hwa; getmicrotime(&sc->sc_ifp->if_lastchange); if (sc->sc_ifflags & IFF_DEBUG) @@ -1206,6 +1211,7 @@ lagg_linkstate(struct lagg_softc *sc) { struct lagg_port *lp; int new_link = LINK_STATE_DOWN; + uint64_t speed; /* Our link is considered up if at least one of our ports is active */ SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { @@ -1215,6 +1221,25 @@ lagg_linkstate(struct lagg_softc *sc) } } if_link_state_change(sc->sc_ifp, new_link); + + /* Update if_baudrate to reflect the max possible speed */ + switch (sc->sc_proto) { + case LAGG_PROTO_FAILOVER: + sc->sc_ifp->if_baudrate = sc->sc_primary != NULL ? + sc->sc_primary->lp_ifp->if_baudrate : 0; + break; + case LAGG_PROTO_ROUNDROBIN: + case LAGG_PROTO_LOADBALANCE: + case LAGG_PROTO_ETHERCHANNEL: + speed = 0; + SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) + speed += lp->lp_ifp->if_baudrate; + sc->sc_ifp->if_baudrate = speed; + break; + case LAGG_PROTO_LACP: + /* LACP updates if_baudrate itself */ + break; + } } static void diff --git a/sys/net/if_llatbl.c b/sys/net/if_llatbl.c new file mode 100644 index 0000000..a3d1b05 --- /dev/null +++ b/sys/net/if_llatbl.c @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2004 Luigi Rizzo, Alessandro Cerri. All rights reserved. + * Copyright (c) 2004-2008 Qing Li. All rights reserved. + * Copyright (c) 2008 Kip Macy. 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "opt_inet.h" +#include "opt_inet6.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/syslog.h> +#include <sys/sysctl.h> +#include <sys/socket.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/rwlock.h> +#include <sys/vimage.h> + +#include <vm/uma.h> + +#include <netinet/in.h> +#include <net/if_llatbl.h> +#include <net/if.h> +#include <net/if_dl.h> +#include <net/if_var.h> +#include <net/route.h> +#include <netinet/if_ether.h> +#include <netinet6/in6_var.h> +#include <netinet6/nd6.h> + +MALLOC_DEFINE(M_LLTABLE, "lltable", "link level address tables"); + +static SLIST_HEAD(, lltable) lltables = SLIST_HEAD_INITIALIZER(lltables); + +extern void arprequest(struct ifnet *, struct in_addr *, struct in_addr *, + u_char *); + +/* + * Dump arp state for a specific address family. + */ +int +lltable_sysctl_dumparp(int af, struct sysctl_req *wr) +{ + struct lltable *llt; + int error = 0; + + IFNET_RLOCK(); + SLIST_FOREACH(llt, &lltables, llt_link) { + if (llt->llt_af == af) { + error = llt->llt_dump(llt, wr); + if (error != 0) + goto done; + } + } +done: + IFNET_RUNLOCK(); + return (error); +} + +/* + * Deletes an address from the address table. + * This function is called by the timer functions + * such as arptimer() and nd6_llinfo_timer(), and + * the caller does the locking. + */ +void +llentry_free(struct llentry *lle) +{ + + LLE_WLOCK_ASSERT(lle); + LIST_REMOVE(lle, lle_next); + + if (lle->la_hold != NULL) + m_freem(lle->la_hold); + + LLE_FREE_LOCKED(lle); +} + +/* + * Free all entries from given table and free itself. + * Since lltables collects from all of the intefaces, + * the caller of this function must acquire IFNET_WLOCK(). + */ +void +lltable_free(struct lltable *llt) +{ + struct llentry *lle, *next; + int i; + + KASSERT(llt != NULL, ("%s: llt is NULL", __func__)); + + IFNET_WLOCK(); + SLIST_REMOVE(&lltables, llt, lltable, llt_link); + IFNET_WUNLOCK(); + + for (i=0; i < LLTBL_HASHTBL_SIZE; i++) { + LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) { + + callout_drain(&lle->la_timer); + LLE_WLOCK(lle); + llentry_free(lle); + } + } + + free(llt, M_LLTABLE); +} + +void +lltable_drain(int af) +{ + struct lltable *llt; + struct llentry *lle; + register int i; + + IFNET_RLOCK(); + SLIST_FOREACH(llt, &lltables, llt_link) { + if (llt->llt_af != af) + continue; + + for (i=0; i < LLTBL_HASHTBL_SIZE; i++) { + LIST_FOREACH(lle, &llt->lle_head[i], lle_next) { + if (lle->la_hold) { + m_freem(lle->la_hold); + lle->la_hold = NULL; + } + } + } + } + IFNET_RUNLOCK(); +} + +/* + * Create a new lltable. + */ +struct lltable * +lltable_init(struct ifnet *ifp, int af) +{ + struct lltable *llt; + register int i; + + llt = malloc(sizeof(struct lltable), M_LLTABLE, M_WAITOK); + if (llt == NULL) + return (NULL); + + llt->llt_af = af; + llt->llt_ifp = ifp; + for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) + LIST_INIT(&llt->lle_head[i]); + + IFNET_WLOCK(); + SLIST_INSERT_HEAD(&lltables, llt, llt_link); + IFNET_WUNLOCK(); + + return (llt); +} + +/* + * Called in route_output when adding/deleting a route to an interface. + */ +int +lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info) +{ + struct sockaddr_dl *dl = + (struct sockaddr_dl *)info->rti_info[RTAX_GATEWAY]; + struct sockaddr *dst = (struct sockaddr *)info->rti_info[RTAX_DST]; + struct ifnet *ifp; + struct lltable *llt; + struct llentry *lle; + u_int laflags = 0, flags = 0; + int error = 0; + + if (dl == NULL || dl->sdl_family != AF_LINK) { + log(LOG_INFO, "%s: invalid dl\n", __func__); + return EINVAL; + } + ifp = ifnet_byindex(dl->sdl_index); + if (ifp == NULL) { + log(LOG_INFO, "%s: invalid ifp (sdl_index %d)\n", + __func__, dl->sdl_index); + return EINVAL; + } + + switch (rtm->rtm_type) { + case RTM_ADD: + if (rtm->rtm_flags & RTF_ANNOUNCE) { + flags |= LLE_PUB; +#ifdef INET + if (dst->sa_family == AF_INET && + ((struct sockaddr_inarp *)dst)->sin_other != 0) { + struct rtentry *rt = rtalloc1(dst, 0, 0); + if (rt == NULL || !(rt->rt_flags & RTF_HOST)) { + log(LOG_INFO, "%s: RTM_ADD publish " + "(proxy only) is invalid\n", + __func__); + RTFREE(rt); + return EINVAL; + } + RTFREE(rt); + + flags |= LLE_PROXY; + } +#endif + } + flags |= LLE_CREATE; + break; + + case RTM_DELETE: + flags |= LLE_DELETE; + break; + + case RTM_CHANGE: + break; + + default: + return EINVAL; /* XXX not implemented yet */ + } + + /* XXX linked list may be too expensive */ + IFNET_RLOCK(); + SLIST_FOREACH(llt, &lltables, llt_link) { + if (llt->llt_af == dst->sa_family && + llt->llt_ifp == ifp) + break; + } + IFNET_RUNLOCK(); + KASSERT(llt != NULL, ("Yep, ugly hacks are bad\n")); + + if (flags && LLE_CREATE) + flags |= LLE_EXCLUSIVE; + + IF_AFDATA_LOCK(ifp); + lle = lla_lookup(llt, flags, dst); + IF_AFDATA_UNLOCK(ifp); + if (LLE_IS_VALID(lle)) { + if (flags & LLE_CREATE) { + /* + * If we delay the delete, then a subsequent + * "arp add" should look up this entry, reset the + * LLE_DELETED flag, and reset the expiration timer + */ + bcopy(LLADDR(dl), &lle->ll_addr, ifp->if_addrlen); + lle->la_flags |= LLE_VALID; + lle->la_flags &= ~LLE_DELETED; +#ifdef INET6 + /* + * ND6 + */ + if (dst->sa_family == AF_INET6) + lle->ln_state = ND6_LLINFO_REACHABLE; +#endif + /* + * NB: arp and ndp always set (RTF_STATIC | RTF_HOST) + */ + + if (rtm->rtm_rmx.rmx_expire == 0) { + lle->la_flags |= LLE_STATIC; + lle->la_expire = 0; + } else + lle->la_expire = rtm->rtm_rmx.rmx_expire; + laflags = lle->la_flags; + LLE_WUNLOCK(lle); +#ifdef INET + /* gratuitous ARP */ + if ((laflags & LLE_PUB) && dst->sa_family == AF_INET) { + arprequest(ifp, + &((struct sockaddr_in *)dst)->sin_addr, + &((struct sockaddr_in *)dst)->sin_addr, + ((laflags & LLE_PROXY) ? + (u_char *)IF_LLADDR(ifp) : + (u_char *)LLADDR(dl))); + } +#endif + } else { + if (flags & LLE_EXCLUSIVE) + LLE_WUNLOCK(lle); + else + LLE_RUNLOCK(lle); + } + } else if ((lle == NULL) && (flags & LLE_DELETE)) + error = EINVAL; + + + return (error); +} diff --git a/sys/net/if_llatbl.h b/sys/net/if_llatbl.h new file mode 100644 index 0000000..50e617d --- /dev/null +++ b/sys/net/if_llatbl.h @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2004 Luigi Rizzo, Alessandro Cerri. All rights reserved. + * Copyright (c) 2004-2008 Qing Li. All rights reserved. + * Copyright (c) 2008 Kip Macy. 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#ifndef _NET_IF_LLATBL_H_ +#define _NET_IF_LLATBL_H_ + +#include <sys/_rwlock.h> +#include <netinet/in.h> + +struct ifnet; +struct sysctl_req; +struct rt_msghdr; +struct rt_addrinfo; + +struct llentry; +LIST_HEAD(llentries, llentry); + +/* + * Code referencing llentry must at least hold + * a shared lock + */ +struct llentry { + LIST_ENTRY(llentry) lle_next; + struct rwlock lle_lock; + struct lltable *lle_tbl; + struct llentries *lle_head; + struct mbuf *la_hold; + time_t la_expire; + uint16_t la_flags; + uint16_t la_asked; + uint16_t la_preempt; + uint16_t ln_byhint; + int16_t ln_state; /* IPv6 has ND6_LLINFO_NOSTATE == -2 */ + uint16_t ln_router; + time_t ln_ntick; + int lle_refcnt; + + union { + uint64_t mac_aligned; + uint16_t mac16[3]; + } ll_addr; + + /* XXX af-private? */ + union { + struct callout ln_timer_ch; + struct callout la_timer; + } lle_timer; + /* NB: struct sockaddr must immediately follow */ +}; + +#define LLE_WLOCK(lle) rw_wlock(&(lle)->lle_lock) +#define LLE_RLOCK(lle) rw_rlock(&(lle)->lle_lock) +#define LLE_WUNLOCK(lle) rw_wunlock(&(lle)->lle_lock) +#define LLE_RUNLOCK(lle) rw_runlock(&(lle)->lle_lock) +#define LLE_DOWNGRADE(lle) rw_downgrade(&(lle)->lle_lock) +#define LLE_TRY_UPGRADE(lle) rw_try_upgrade(&(lle)->lle_lock) +#define LLE_LOCK_INIT(lle) rw_init_flags(&(lle)->lle_lock, "lle", RW_DUPOK) +#define LLE_LOCK_DESTROY(lle) rw_destroy(&(lle)->lle_lock) +#define LLE_WLOCK_ASSERT(lle) rw_assert(&(lle)->lle_lock, RA_WLOCKED) + +#define LLE_IS_VALID(lle) (((lle) != NULL) && ((lle) != (void *)-1)) + +#define LLE_ADDREF(lle) do { \ + LLE_WLOCK_ASSERT(lle); \ + KASSERT((lle)->lle_refcnt >= 0, \ + ("negative refcnt %d", (lle)->lle_refcnt)); \ + (lle)->lle_refcnt++; \ +} while (0) + +#define LLE_REMREF(lle) do { \ + LLE_WLOCK_ASSERT(lle); \ + KASSERT((lle)->lle_refcnt > 1, \ + ("bogus refcnt %d", (lle)->lle_refcnt)); \ + (lle)->lle_refcnt--; \ +} while (0) + +#define LLE_FREE_LOCKED(lle) do { \ + if ((lle)->lle_refcnt <= 1) \ + (lle)->lle_tbl->llt_free((lle)->lle_tbl, (lle));\ + else { \ + (lle)->lle_refcnt--; \ + LLE_WUNLOCK(lle); \ + } \ + /* guard against invalid refs */ \ + lle = 0; \ +} while (0) + +#define LLE_FREE(lle) do { \ + LLE_WLOCK(lle); \ + if ((lle)->lle_refcnt <= 1) \ + (lle)->lle_tbl->llt_free((lle)->lle_tbl, (lle));\ + else { \ + (lle)->lle_refcnt--; \ + LLE_WUNLOCK(lle); \ + } \ + /* guard against invalid refs */ \ + lle = NULL; \ +} while (0) + + +#define ln_timer_ch lle_timer.ln_timer_ch +#define la_timer lle_timer.la_timer + +/* XXX bad name */ +#define L3_ADDR(lle) ((struct sockaddr *)(&lle[1])) +#define L3_ADDR_LEN(lle) (((struct sockaddr *)(&lle[1]))->sa_len) + +#ifndef LLTBL_HASHTBL_SIZE +#define LLTBL_HASHTBL_SIZE 32 /* default 32 ? */ +#endif + +#ifndef LLTBL_HASHMASK +#define LLTBL_HASHMASK (LLTBL_HASHTBL_SIZE - 1) +#endif + +struct lltable { + SLIST_ENTRY(lltable) llt_link; + struct llentries lle_head[LLTBL_HASHTBL_SIZE]; + int llt_af; + struct ifnet *llt_ifp; + + struct llentry * (*llt_new)(const struct sockaddr *, u_int); + void (*llt_free)(struct lltable *, struct llentry *); + struct llentry * (*llt_lookup)(struct lltable *, u_int flags, + const struct sockaddr *l3addr); + int (*llt_rtcheck)(struct ifnet *, + const struct sockaddr *); + int (*llt_dump)(struct lltable *, + struct sysctl_req *); +}; +MALLOC_DECLARE(M_LLTABLE); + +/* + * flags to be passed to arplookup. + */ +#define LLE_DELETED 0x0001 /* entry must be deleted */ +#define LLE_STATIC 0x0002 /* entry is static */ +#define LLE_IFADDR 0x0004 /* entry is interface addr */ +#define LLE_VALID 0x0008 /* ll_addr is valid */ +#define LLE_PROXY 0x0010 /* proxy entry ??? */ +#define LLE_PUB 0x0020 /* publish entry ??? */ +#define LLE_DELETE 0x4000 /* delete on a lookup - match LLE_IFADDR */ +#define LLE_CREATE 0x8000 /* create on a lookup miss */ +#define LLE_EXCLUSIVE 0x2000 /* return lle xlocked */ + +#define LLATBL_HASH(key, mask) \ + (((((((key >> 8) ^ key) >> 8) ^ key) >> 8) ^ key) & mask) + +struct lltable *lltable_init(struct ifnet *, int); +void lltable_free(struct lltable *); +void lltable_drain(int); +int lltable_sysctl_dumparp(int, struct sysctl_req *); + +void llentry_free(struct llentry *); + +/* + * Generic link layer address lookup function. + */ +static __inline struct llentry * +lla_lookup(struct lltable *llt, u_int flags, const struct sockaddr *l3addr) +{ + return llt->llt_lookup(llt, flags, l3addr); +} + +int lla_rt_output(struct rt_msghdr *, struct rt_addrinfo *); +#endif /* _NET_IF_LLATBL_H_ */ diff --git a/sys/net/if_media.h b/sys/net/if_media.h index 18726da..f4b3d81 100644 --- a/sys/net/if_media.h +++ b/sys/net/if_media.h @@ -145,6 +145,11 @@ uint64_t ifmedia_baudrate(int); #define IFM_10G_SR 19 /* 10GBase-SR 850nm Multi-mode */ #define IFM_10G_CX4 20 /* 10GBase CX4 copper */ #define IFM_2500_SX 21 /* 2500BaseSX - multi-mode fiber */ +#define IFM_10G_TWINAX 22 /* 10GBase Twinax copper */ +#define IFM_10G_TWINAX_LONG 23 /* 10GBase Twinax Long copper */ +#define IFM_10G_LRM 24 /* 10GBase-LRM 850nm Multi-mode */ +#define IFM_UNKNOWN 25 /* New media types that have not been defined yet */ + /* note 31 is the max! */ @@ -349,6 +354,10 @@ struct ifmedia_description { { IFM_10G_SR, "10Gbase-SR" }, \ { IFM_10G_CX4, "10Gbase-CX4" }, \ { IFM_2500_SX, "2500BaseSX" }, \ + { IFM_10G_LRM, "10Gbase-LRM" }, \ + { IFM_10G_TWINAX, "10Gbase-Twinax" }, \ + { IFM_10G_TWINAX_LONG, "10Gbase-Twinax-Long" }, \ + { IFM_UNKNOWN, "Unknown" }, \ { 0, NULL }, \ } @@ -603,6 +612,9 @@ struct ifmedia_baudrate { { IFM_ETHER | IFM_10G_SR, IF_Gbps(10ULL) }, \ { IFM_ETHER | IFM_10G_CX4, IF_Gbps(10ULL) }, \ { IFM_ETHER | IFM_2500_SX, IF_Mbps(2500ULL) }, \ + { IFM_ETHER | IFM_10G_TWINAX, IF_Gbps(10ULL) }, \ + { IFM_ETHER | IFM_10G_TWINAX_LONG, IF_Gbps(10ULL) }, \ + { IFM_ETHER | IFM_10G_LRM, IF_Gbps(10ULL) }, \ \ { IFM_TOKEN | IFM_TOK_STP4, IF_Mbps(4) }, \ { IFM_TOKEN | IFM_TOK_STP16, IF_Mbps(16) }, \ diff --git a/sys/net/if_var.h b/sys/net/if_var.h index 0724488..250bed9 100644 --- a/sys/net/if_var.h +++ b/sys/net/if_var.h @@ -77,9 +77,11 @@ struct ifvlantrunk; #ifdef _KERNEL #include <sys/mbuf.h> #include <sys/eventhandler.h> +#include <sys/buf_ring.h> #endif /* _KERNEL */ #include <sys/lock.h> /* XXX */ #include <sys/mutex.h> /* XXX */ +#include <sys/rwlock.h> /* XXX */ #include <sys/event.h> /* XXX */ #include <sys/_task.h> @@ -169,25 +171,24 @@ struct ifnet { void *if_bridge; /* bridge glue */ - struct lltable *lltables; /* list of L3-L2 resolution tables */ - struct label *if_label; /* interface MAC label */ /* these are only used by IPv6 */ struct ifprefixhead if_prefixhead; /* list of prefixes per if */ void *if_afdata[AF_MAX]; int if_afdata_initialized; - struct mtx if_afdata_mtx; + struct rwlock if_afdata_lock; struct task if_starttask; /* task for IFF_NEEDSGIANT */ struct task if_linktask; /* task for link change events */ struct mtx if_addr_mtx; /* mutex to protect address lists */ + LIST_ENTRY(ifnet) if_clones; /* interfaces of a cloner */ TAILQ_HEAD(, ifg_list) if_groups; /* linked list of groups per if */ /* protected by if_addr_mtx */ void *if_pf_kif; void *if_lagg; /* lagg glue */ - void *if_pspare[8]; /* multiq/TOE 3; vimage 3; general use 4 */ - void (*if_qflush) /* flush any queues */ + void *if_pspare[8]; /* TOE 3; vimage 3; general use 4 */ + void (*if_qflush) /* flush any queues */ (struct ifnet *); int (*if_transmit) /* initiate output routine */ (struct ifnet *, struct mbuf *); @@ -359,11 +360,19 @@ typedef void (*group_change_event_handler_t)(void *, const char *); EVENTHANDLER_DECLARE(group_change_event, group_change_event_handler_t); #define IF_AFDATA_LOCK_INIT(ifp) \ - mtx_init(&(ifp)->if_afdata_mtx, "if_afdata", NULL, MTX_DEF) -#define IF_AFDATA_LOCK(ifp) mtx_lock(&(ifp)->if_afdata_mtx) -#define IF_AFDATA_TRYLOCK(ifp) mtx_trylock(&(ifp)->if_afdata_mtx) -#define IF_AFDATA_UNLOCK(ifp) mtx_unlock(&(ifp)->if_afdata_mtx) -#define IF_AFDATA_DESTROY(ifp) mtx_destroy(&(ifp)->if_afdata_mtx) + rw_init(&(ifp)->if_afdata_lock, "if_afdata") + +#define IF_AFDATA_WLOCK(ifp) rw_wlock(&(ifp)->if_afdata_lock) +#define IF_AFDATA_RLOCK(ifp) rw_rlock(&(ifp)->if_afdata_lock) +#define IF_AFDATA_WUNLOCK(ifp) rw_wunlock(&(ifp)->if_afdata_lock) +#define IF_AFDATA_RUNLOCK(ifp) rw_runlock(&(ifp)->if_afdata_lock) +#define IF_AFDATA_LOCK(ifp) IF_AFDATA_WLOCK(ifp) +#define IF_AFDATA_UNLOCK(ifp) IF_AFDATA_WUNLOCK(ifp) +#define IF_AFDATA_TRYLOCK(ifp) rw_try_wlock(&(ifp)->if_afdata_lock) +#define IF_AFDATA_DESTROY(ifp) rw_destroy(&(ifp)->if_afdata_lock) + +#define IF_AFDATA_LOCK_ASSERT(ifp) rw_assert(&(ifp)->if_afdata_lock, RA_LOCKED) +#define IF_AFDATA_UNLOCK_ASSERT(ifp) rw_assert(&(ifp)->if_afdata_lock, RA_UNLOCKED) #define IFF_LOCKGIANT(ifp) do { \ if ((ifp)->if_flags & IFF_NEEDSGIANT) \ @@ -540,6 +549,45 @@ do { \ IFQ_PURGE(ifq); \ } while (0) +#ifdef _KERNEL +static __inline void +drbr_stats_update(struct ifnet *ifp, int len, int mflags) +{ + + ifp->if_obytes += len; + if (mflags & M_MCAST) + ifp->if_omcasts++; +} + +static __inline int +drbr_enqueue(struct ifnet *ifp, struct buf_ring *br, struct mbuf *m) +{ + int error = 0; + int len = m->m_pkthdr.len; + int mflags = m->m_flags; + + if ((error = buf_ring_enqueue(br, m)) == ENOBUFS) { + br->br_drops++; + _IF_DROP(&ifp->if_snd); + m_freem(m); + } else + drbr_stats_update(ifp, len, mflags); + + return (error); +} + +static __inline void +drbr_free(struct buf_ring *br, struct malloc_type *type) +{ + struct mbuf *m; + + while ((m = buf_ring_dequeue_sc(br)) != NULL) + m_freem(m); + + buf_ring_free(br, type); +} +#endif + /* * 72 was chosen below because it is the size of a TCP/IP * header (40) + the minimum mss (32). @@ -635,14 +683,14 @@ struct ifmultiaddr { IFA_UNLOCK(ifa); \ } while (0) -extern struct mtx ifnet_lock; +extern struct rwlock ifnet_lock; #define IFNET_LOCK_INIT() \ - mtx_init(&ifnet_lock, "ifnet", NULL, MTX_DEF | MTX_RECURSE) -#define IFNET_WLOCK() mtx_lock(&ifnet_lock) -#define IFNET_WUNLOCK() mtx_unlock(&ifnet_lock) -#define IFNET_WLOCK_ASSERT() mtx_assert(&ifnet_lock, MA_OWNED) -#define IFNET_RLOCK() IFNET_WLOCK() -#define IFNET_RUNLOCK() IFNET_WUNLOCK() + rw_init_flags(&ifnet_lock, "ifnet", RW_RECURSE) +#define IFNET_WLOCK() rw_wlock(&ifnet_lock) +#define IFNET_WUNLOCK() rw_wunlock(&ifnet_lock) +#define IFNET_WLOCK_ASSERT() rw_assert(&ifnet_lock, RA_LOCKED) +#define IFNET_RLOCK() rw_rlock(&ifnet_lock) +#define IFNET_RUNLOCK() rw_runlock(&ifnet_lock) struct ifindex_entry { struct ifnet *ife_ifnet; @@ -659,10 +707,12 @@ struct ifnet *ifnet_byindex(u_short idx); struct ifaddr *ifaddr_byindex(u_short idx); struct cdev *ifdev_byindex(u_short idx); +#ifdef VIMAGE_GLOBALS extern struct ifnethead ifnet; -extern int ifqmaxlen; extern struct ifnet *loif; /* first loopback interface */ extern int if_index; +#endif +extern int ifqmaxlen; int if_addgroup(struct ifnet *, const char *); int if_delgroup(struct ifnet *, const char *); diff --git a/sys/net/pfil.c b/sys/net/pfil.c index bb82bb3..3018eb9 100644 --- a/sys/net/pfil.c +++ b/sys/net/pfil.c @@ -97,33 +97,26 @@ pfil_head_register(struct pfil_head *ph) struct pfil_head *lph; PFIL_LIST_LOCK(); - LIST_FOREACH(lph, &pfil_head_list, ph_list) + LIST_FOREACH(lph, &pfil_head_list, ph_list) { if (ph->ph_type == lph->ph_type && ph->ph_un.phu_val == lph->ph_un.phu_val) { PFIL_LIST_UNLOCK(); return EEXIST; } - PFIL_LIST_UNLOCK(); - + } PFIL_LOCK_INIT(ph); - PFIL_WLOCK(ph); ph->ph_nhooks = 0; - TAILQ_INIT(&ph->ph_in); TAILQ_INIT(&ph->ph_out); - - PFIL_LIST_LOCK(); LIST_INSERT_HEAD(&pfil_head_list, ph, ph_list); PFIL_LIST_UNLOCK(); - - PFIL_WUNLOCK(ph); - return (0); } /* - * pfil_head_unregister() removes a pfil_head from the packet filter - * hook mechanism. + * pfil_head_unregister() removes a pfil_head from the packet filter hook + * mechanism. The producer of the hook promises that all outstanding + * invocations of the hook have completed before it unregisters the hook. */ int pfil_head_unregister(struct pfil_head *ph) @@ -131,21 +124,13 @@ pfil_head_unregister(struct pfil_head *ph) struct packet_filter_hook *pfh, *pfnext; PFIL_LIST_LOCK(); - /* - * LIST_REMOVE is safe for unlocked pfil_heads in ph_list. - * No need to WLOCK all of them. - */ LIST_REMOVE(ph, ph_list); PFIL_LIST_UNLOCK(); - - PFIL_WLOCK(ph); - TAILQ_FOREACH_SAFE(pfh, &ph->ph_in, pfil_link, pfnext) free(pfh, M_IFADDR); TAILQ_FOREACH_SAFE(pfh, &ph->ph_out, pfil_link, pfnext) free(pfh, M_IFADDR); PFIL_LOCK_DESTROY(ph); - return (0); } @@ -175,14 +160,13 @@ pfil_head_get(int type, u_long val) * PFIL_WAITOK OK to call malloc with M_WAITOK. */ int -pfil_add_hook(int (*func)(void *, struct mbuf **, struct ifnet *, int, struct inpcb *), - void *arg, int flags, struct pfil_head *ph) +pfil_add_hook(int (*func)(void *, struct mbuf **, struct ifnet *, int, + struct inpcb *), void *arg, int flags, struct pfil_head *ph) { struct packet_filter_hook *pfh1 = NULL; struct packet_filter_hook *pfh2 = NULL; int err; - /* Get memory */ if (flags & PFIL_IN) { pfh1 = (struct packet_filter_hook *)malloc(sizeof(*pfh1), M_IFADDR, (flags & PFIL_WAITOK) ? M_WAITOK : M_NOWAIT); @@ -199,17 +183,13 @@ pfil_add_hook(int (*func)(void *, struct mbuf **, struct ifnet *, int, struct in goto error; } } - - /* Lock */ PFIL_WLOCK(ph); - - /* Add */ if (flags & PFIL_IN) { pfh1->pfil_func = func; pfh1->pfil_arg = arg; err = pfil_list_add(&ph->ph_in, pfh1, flags & ~PFIL_OUT); if (err) - goto done; + goto locked_error; ph->ph_nhooks++; } if (flags & PFIL_OUT) { @@ -219,15 +199,13 @@ pfil_add_hook(int (*func)(void *, struct mbuf **, struct ifnet *, int, struct in if (err) { if (flags & PFIL_IN) pfil_list_remove(&ph->ph_in, func, arg); - goto done; + goto locked_error; } ph->ph_nhooks++; } - PFIL_WUNLOCK(ph); - return 0; -done: +locked_error: PFIL_WUNLOCK(ph); error: if (pfh1 != NULL) diff --git a/sys/net/pfil.h b/sys/net/pfil.h index 22d3d16..5db9e55 100644 --- a/sys/net/pfil.h +++ b/sys/net/pfil.h @@ -49,7 +49,8 @@ struct inpcb; */ struct packet_filter_hook { TAILQ_ENTRY(packet_filter_hook) pfil_link; - int (*pfil_func)(void *, struct mbuf **, struct ifnet *, int, struct inpcb *); + int (*pfil_func)(void *, struct mbuf **, struct ifnet *, int, + struct inpcb *); void *pfil_arg; int pfil_flags; }; diff --git a/sys/net/radix.c b/sys/net/radix.c index e70d17d..39b198e 100644 --- a/sys/net/radix.c +++ b/sys/net/radix.c @@ -1087,6 +1087,7 @@ rn_walktree(h, f, w) * while applying the function f to it, so we need to calculate * the successor node in advance. */ + /* First time through node, go left */ while (rn->rn_bit >= 0) rn = rn->rn_left; diff --git a/sys/net/radix_mpath.c b/sys/net/radix_mpath.c index 68233fe..8d94d01 100644 --- a/sys/net/radix_mpath.c +++ b/sys/net/radix_mpath.c @@ -266,8 +266,8 @@ rtalloc_mpath_fib(struct route *ro, u_int32_t hash, u_int fibnum) * be done for sendto(3) case? */ if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP)) - return; /* XXX */ - ro->ro_rt = rtalloc1_fib(&ro->ro_dst, 1, RTF_CLONING, fibnum); + return; + ro->ro_rt = rtalloc1_fib(&ro->ro_dst, 1, 0, fibnum); /* if the route does not exist or it is not multipath, don't care */ if (ro->ro_rt == NULL) diff --git a/sys/net/route.c b/sys/net/route.c index be71e13..1f3e096 100644 --- a/sys/net/route.c +++ b/sys/net/route.c @@ -41,6 +41,7 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/syslog.h> #include <sys/malloc.h> #include <sys/mbuf.h> #include <sys/socket.h> @@ -53,6 +54,7 @@ #include <sys/vimage.h> #include <net/if.h> +#include <net/if_dl.h> #include <net/route.h> #ifdef RADIX_MPATH @@ -269,8 +271,7 @@ rtalloc1_fib(struct sockaddr *dst, int report, u_long ignflags, struct radix_node *rn; struct rtentry *newrt; struct rt_addrinfo info; - u_long nflags; - int needresolve = 0, err = 0, msgtype = RTM_MISS; + int err = 0, msgtype = RTM_MISS; int needlock; KASSERT((fibnum < rt_numfibs), ("rtalloc1_fib: bad fibnum")); @@ -283,10 +284,9 @@ rtalloc1_fib(struct sockaddr *dst, int report, u_long ignflags, */ if (rnh == NULL) { V_rtstat.rts_unreach++; - goto miss2; + goto miss; } needlock = !(ignflags & RTF_RNH_LOCKED); -retry: if (needlock) RADIX_NODE_HEAD_RLOCK(rnh); #ifdef INVARIANTS @@ -295,103 +295,33 @@ retry: #endif rn = rnh->rnh_matchaddr(dst, rnh); if (rn && ((rn->rn_flags & RNF_ROOT) == 0)) { - newrt = rt = RNTORT(rn); - nflags = rt->rt_flags & ~ignflags; - if (report && (nflags & RTF_CLONING)) { - if (needlock && !RADIX_NODE_HEAD_LOCK_TRY_UPGRADE(rnh)) { - RADIX_NODE_HEAD_RUNLOCK(rnh); - RADIX_NODE_HEAD_LOCK(rnh); - /* - * lookup again to make sure it wasn't changed - */ - rn = rnh->rnh_matchaddr(dst, rnh); - if (!(rn && ((rn->rn_flags & RNF_ROOT) == 0))) { - RADIX_NODE_HEAD_UNLOCK(rnh); - needresolve = 0; - log(LOG_INFO, "retrying route lookup ...\n"); - goto retry; - } - } - needresolve = 1; - } else { - RT_LOCK(newrt); - RT_ADDREF(newrt); - if (needlock) - RADIX_NODE_HEAD_RUNLOCK(rnh); - goto done; - } - } - /* - * if needresolve is set then we have the exclusive lock - * and we need to keep it held for the benefit of rtrequest_fib - */ - if (!needresolve && needlock) + RT_LOCK(newrt); + RT_ADDREF(newrt); + if (needlock) + RADIX_NODE_HEAD_RUNLOCK(rnh); + goto done; + + } else if (needlock) RADIX_NODE_HEAD_RUNLOCK(rnh); - if (needresolve) { - RADIX_NODE_HEAD_WLOCK_ASSERT(rnh); + /* + * Either we hit the root or couldn't find any match, + * Which basically means + * "caint get there frm here" + */ + V_rtstat.rts_unreach++; +miss: + if (report) { /* - * We are apparently adding (report = 0 in delete). - * If it requires that it be cloned, do so. - * (This implies it wasn't a HOST route.) + * If required, report the failure to the supervising + * Authorities. + * For a delete, this is not an error. (report == 0) */ - err = rtrequest_fib(RTM_RESOLVE, dst, NULL, - NULL, RTF_RNH_LOCKED, &newrt, fibnum); - if (err) { - /* - * If the cloning didn't succeed, maybe - * what we have will do. Return that. - */ - newrt = rt; /* existing route */ - RT_LOCK(newrt); - RT_ADDREF(newrt); - goto miss; - } - KASSERT(newrt, ("no route and no error")); - RT_LOCK(newrt); - if (newrt->rt_flags & RTF_XRESOLVE) { - /* - * If the new route specifies it be - * externally resolved, then go do that. - */ - msgtype = RTM_RESOLVE; - goto miss; - } - /* Inform listeners of the new route. */ bzero(&info, sizeof(info)); - info.rti_info[RTAX_DST] = rt_key(newrt); - info.rti_info[RTAX_NETMASK] = rt_mask(newrt); - info.rti_info[RTAX_GATEWAY] = newrt->rt_gateway; - if (newrt->rt_ifp != NULL) { - info.rti_info[RTAX_IFP] = - newrt->rt_ifp->if_addr->ifa_addr; - info.rti_info[RTAX_IFA] = newrt->rt_ifa->ifa_addr; - } - rt_missmsg(RTM_ADD, &info, newrt->rt_flags, 0); - if (needlock) - RADIX_NODE_HEAD_UNLOCK(rnh); - } else { - /* - * Either we hit the root or couldn't find any match, - * Which basically means - * "caint get there frm here" - */ - V_rtstat.rts_unreach++; - miss: - if (needlock && needresolve) - RADIX_NODE_HEAD_UNLOCK(rnh); - miss2: if (report) { - /* - * If required, report the failure to the supervising - * Authorities. - * For a delete, this is not an error. (report == 0) - */ - bzero(&info, sizeof(info)); - info.rti_info[RTAX_DST] = dst; - rt_missmsg(msgtype, &info, 0, err); - } - } + info.rti_info[RTAX_DST] = dst; + rt_missmsg(msgtype, &info, 0, err); + } done: if (newrt) RT_LOCK_ASSERT(newrt); @@ -420,7 +350,7 @@ rtfree(struct rtentry *rt) */ RT_REMREF(rt); if (rt->rt_refcnt > 0) { - printf("%s: %p has %lu refs\n", __func__, rt, rt->rt_refcnt); + log(LOG_DEBUG, "%s: %p has %d refs\t", __func__, rt, rt->rt_refcnt); goto done; } @@ -461,8 +391,6 @@ rtfree(struct rtentry *rt) */ if (rt->rt_ifa) IFAFREE(rt->rt_ifa); - rt->rt_parent = NULL; /* NB: no refcnt on parent */ - /* * The key is separatly alloc'd so free it (see rt_setgate()). * This also frees the gateway, as they are always malloc'd @@ -715,14 +643,6 @@ ifa_ifwithroute_fib(int flags, struct sockaddr *dst, struct sockaddr *gateway, return (ifa); } -static walktree_f_t rt_fixdelete; -static walktree_f_t rt_fixchange; - -struct rtfc_arg { - struct rtentry *rt0; - struct radix_node_head *rnh; -}; - /* * Do appropriate manipulations of a routing tree given * all the bits of info needed @@ -828,8 +748,13 @@ rtexpunge(struct rtentry *rt) struct ifaddr *ifa; int error = 0; + /* + * Find the correct routing tree to use for this Address Family + */ rnh = V_rt_tables[rt->rt_fibnum][rt_key(rt)->sa_family]; RT_LOCK_ASSERT(rt); + if (rnh == NULL) + return (EAFNOSUPPORT); RADIX_NODE_HEAD_LOCK_ASSERT(rnh); #if 0 /* @@ -840,13 +765,6 @@ rtexpunge(struct rtentry *rt) KASSERT(rt->rt_refcnt <= 1, ("bogus refcnt %ld", rt->rt_refcnt)); #endif /* - * Find the correct routing tree to use for this Address Family - */ - rnh = V_rt_tables[rt->rt_fibnum][rt_key(rt)->sa_family]; - if (rnh == NULL) - return (EAFNOSUPPORT); - - /* * Remove the item from the tree; it should be there, * but when callers invoke us blindly it may not (sigh). */ @@ -863,24 +781,6 @@ rtexpunge(struct rtentry *rt) rt->rt_flags &= ~RTF_UP; /* - * Now search what's left of the subtree for any cloned - * routes which might have been formed from this node. - */ - if ((rt->rt_flags & RTF_CLONING) && rt_mask(rt)) - rnh->rnh_walktree_from(rnh, rt_key(rt), rt_mask(rt), - rt_fixdelete, rt); - - /* - * Remove any external references we may have. - * This might result in another rtentry being freed if - * we held its last reference. - */ - if (rt->rt_gwroute) { - RTFREE(rt->rt_gwroute); - rt->rt_gwroute = NULL; - } - - /* * Give the protocol a chance to keep things in sync. */ if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest) { @@ -904,12 +804,6 @@ bad: } int -rtrequest1(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt) -{ - return (rtrequest1_fib(req, info, ret_nrt, 0)); -} - -int rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt, u_int fibnum) { @@ -941,10 +835,9 @@ rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt, * If we are adding a host route then we don't want to put * a netmask in the tree, nor do we want to clone it. */ - if (flags & RTF_HOST) { + if (flags & RTF_HOST) netmask = NULL; - flags &= ~RTF_CLONING; - } + switch (req) { case RTM_DELETE: #ifdef RADIX_MPATH @@ -1023,26 +916,6 @@ normal_rtdel: rt->rt_flags &= ~RTF_UP; /* - * Now search what's left of the subtree for any cloned - * routes which might have been formed from this node. - */ - if ((rt->rt_flags & RTF_CLONING) && - rt_mask(rt)) { - rnh->rnh_walktree_from(rnh, dst, rt_mask(rt), - rt_fixdelete, rt); - } - - /* - * Remove any external references we may have. - * This might result in another rtentry being freed if - * we held its last reference. - */ - if (rt->rt_gwroute) { - RTFREE(rt->rt_gwroute); - rt->rt_gwroute = NULL; - } - - /* * give the protocol a chance to keep things in sync. */ if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest) @@ -1069,20 +942,12 @@ deldone: } else RTFREE_LOCKED(rt); break; - case RTM_RESOLVE: - if (ret_nrt == NULL || (rt = *ret_nrt) == NULL) - senderr(EINVAL); - ifa = rt->rt_ifa; - /* XXX locking? */ - flags = rt->rt_flags & - ~(RTF_CLONING | RTF_STATIC); - flags |= RTF_WASCLONED; - gateway = rt->rt_gateway; - if ((netmask = rt->rt_genmask) == NULL) - flags |= RTF_HOST; - goto makeroute; - + /* + * resolve was only used for route cloning + * here for compat + */ + break; case RTM_ADD: if ((flags & RTF_GATEWAY) && !gateway) senderr(EINVAL); @@ -1093,8 +958,6 @@ deldone: if (info->rti_ifa == NULL && (error = rt_getifa_fib(info, fibnum))) senderr(error); ifa = info->rti_ifa; - - makeroute: rt = uma_zalloc(rtzone, M_NOWAIT | M_ZERO); if (rt == NULL) senderr(ENOBUFS); @@ -1103,7 +966,7 @@ deldone: rt->rt_fibnum = fibnum; /* * Add the gateway. Possibly re-malloc-ing the storage for it - * also add the rt_gwroute if possible. + * */ RT_LOCK(rt); if ((error = rt_setgate(rt, dst, gateway)) != 0) { @@ -1138,8 +1001,6 @@ deldone: /* do not permit exactly the same dst/mask/gw pair */ if (rn_mpath_capable(rnh) && rt_mpath_conflict(rnh, rt, netmask)) { - if (rt->rt_gwroute) - RTFREE(rt->rt_gwroute); if (rt->rt_ifa) { IFAFREE(rt->rt_ifa); } @@ -1152,34 +1013,11 @@ deldone: /* XXX mtu manipulation will be done in rnh_addaddr -- itojun */ rn = rnh->rnh_addaddr(ndst, netmask, rnh, rt->rt_nodes); - if (rn == NULL) { - struct rtentry *rt2; - /* - * Uh-oh, we already have one of these in the tree. - * We do a special hack: if the route that's already - * there was generated by the cloning mechanism - * then we just blow it away and retry the insertion - * of the new one. - */ - rt2 = rtalloc1_fib(dst, 0, RTF_RNH_LOCKED, fibnum); - if (rt2 && rt2->rt_parent) { - rtexpunge(rt2); - RT_UNLOCK(rt2); - rn = rnh->rnh_addaddr(ndst, netmask, - rnh, rt->rt_nodes); - } else if (rt2) { - /* undo the extra ref we got */ - RTFREE_LOCKED(rt2); - } - } - /* * If it still failed to go into the tree, * then un-make it (this should be a function) */ if (rn == NULL) { - if (rt->rt_gwroute) - RTFREE(rt->rt_gwroute); if (rt->rt_ifa) IFAFREE(rt->rt_ifa); Free(rt_key(rt)); @@ -1188,33 +1026,6 @@ deldone: senderr(EEXIST); } - rt->rt_parent = NULL; - - /* - * If we got here from RESOLVE, then we are cloning - * so clone the rest, and note that we - * are a clone (and increment the parent's references) - */ - if (req == RTM_RESOLVE) { - KASSERT(ret_nrt && *ret_nrt, - ("no route to clone from")); - rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */ - rt->rt_rmx.rmx_pksent = 0; /* reset packet counter */ - if ((*ret_nrt)->rt_flags & RTF_CLONING) { - /* - * NB: We do not bump the refcnt on the parent - * entry under the assumption that it will - * remain so long as we do. This is - * important when deleting the parent route - * as this operation requires traversing - * the tree to delete all clones and futzing - * with refcnts requires us to double-lock - * parent through this back reference. - */ - rt->rt_parent = *ret_nrt; - } - } - /* * If this protocol has something to add to this then * allow it to do that as well. @@ -1223,20 +1034,6 @@ deldone: ifa->ifa_rtrequest(req, rt, info); /* - * We repeat the same procedure from rt_setgate() here because - * it doesn't fire when we call it there because the node - * hasn't been added to the tree yet. - */ - if (req == RTM_ADD && - !(rt->rt_flags & RTF_HOST) && rt_mask(rt) != NULL) { - struct rtfc_arg arg; - arg.rnh = rnh; - arg.rt0 = rt; - rnh->rnh_walktree_from(rnh, rt_key(rt), rt_mask(rt), - rt_fixchange, &arg); - } - - /* * actually return a resultant rtentry and * give the caller a single reference. */ @@ -1263,159 +1060,21 @@ bad: #undef ifpaddr #undef flags -/* - * Called from rtrequest(RTM_DELETE, ...) to fix up the route's ``family'' - * (i.e., the routes related to it by the operation of cloning). This - * routine is iterated over all potential former-child-routes by way of - * rnh->rnh_walktree_from() above, and those that actually are children of - * the late parent (passed in as VP here) are themselves deleted. - */ -static int -rt_fixdelete(struct radix_node *rn, void *vp) -{ - struct rtentry *rt = RNTORT(rn); - struct rtentry *rt0 = vp; - - if (rt->rt_parent == rt0 && - !(rt->rt_flags & (RTF_PINNED | RTF_CLONING))) { - return rtrequest_fib(RTM_DELETE, rt_key(rt), NULL, rt_mask(rt), - rt->rt_flags|RTF_RNH_LOCKED, NULL, rt->rt_fibnum); - } - return 0; -} - -/* - * This routine is called from rt_setgate() to do the analogous thing for - * adds and changes. There is the added complication in this case of a - * middle insert; i.e., insertion of a new network route between an older - * network route and (cloned) host routes. For this reason, a simple check - * of rt->rt_parent is insufficient; each candidate route must be tested - * against the (mask, value) of the new route (passed as before in vp) - * to see if the new route matches it. - * - * XXX - it may be possible to do fixdelete() for changes and reserve this - * routine just for adds. I'm not sure why I thought it was necessary to do - * changes this way. - */ - -static int -rt_fixchange(struct radix_node *rn, void *vp) -{ - struct rtentry *rt = RNTORT(rn); - struct rtfc_arg *ap = vp; - struct rtentry *rt0 = ap->rt0; - struct radix_node_head *rnh = ap->rnh; - u_char *xk1, *xm1, *xk2, *xmp; - int i, len, mlen; - - /* make sure we have a parent, and route is not pinned or cloning */ - if (!rt->rt_parent || - (rt->rt_flags & (RTF_PINNED | RTF_CLONING))) - return 0; - - if (rt->rt_parent == rt0) /* parent match */ - goto delete_rt; - /* - * There probably is a function somewhere which does this... - * if not, there should be. - */ - len = imin(rt_key(rt0)->sa_len, rt_key(rt)->sa_len); - - xk1 = (u_char *)rt_key(rt0); - xm1 = (u_char *)rt_mask(rt0); - xk2 = (u_char *)rt_key(rt); - - /* avoid applying a less specific route */ - xmp = (u_char *)rt_mask(rt->rt_parent); - mlen = rt_key(rt->rt_parent)->sa_len; - if (mlen > rt_key(rt0)->sa_len) /* less specific route */ - return 0; - for (i = rnh->rnh_treetop->rn_offset; i < mlen; i++) - if ((xmp[i] & ~(xmp[i] ^ xm1[i])) != xmp[i]) - return 0; /* less specific route */ - - for (i = rnh->rnh_treetop->rn_offset; i < len; i++) - if ((xk2[i] & xm1[i]) != xk1[i]) - return 0; /* no match */ - - /* - * OK, this node is a clone, and matches the node currently being - * changed/added under the node's mask. So, get rid of it. - */ -delete_rt: - return rtrequest_fib(RTM_DELETE, rt_key(rt), NULL, - rt_mask(rt), rt->rt_flags, NULL, rt->rt_fibnum); -} - int rt_setgate(struct rtentry *rt, struct sockaddr *dst, struct sockaddr *gate) { INIT_VNET_NET(curvnet); /* XXX dst may be overwritten, can we move this to below */ + int dlen = SA_SIZE(dst), glen = SA_SIZE(gate); +#ifdef INVARIANTS struct radix_node_head *rnh = V_rt_tables[rt->rt_fibnum][dst->sa_family]; - int dlen = SA_SIZE(dst), glen = SA_SIZE(gate); +#endif -again: RT_LOCK_ASSERT(rt); RADIX_NODE_HEAD_LOCK_ASSERT(rnh); /* - * A host route with the destination equal to the gateway - * will interfere with keeping LLINFO in the routing - * table, so disallow it. - */ - if (((rt->rt_flags & (RTF_HOST|RTF_GATEWAY|RTF_LLINFO)) == - (RTF_HOST|RTF_GATEWAY)) && - dst->sa_len == gate->sa_len && - bcmp(dst, gate, dst->sa_len) == 0) { - /* - * The route might already exist if this is an RTM_CHANGE - * or a routing redirect, so try to delete it. - */ - if (rt_key(rt)) - rtexpunge(rt); - return EADDRNOTAVAIL; - } - - /* - * Cloning loop avoidance in case of bad configuration. - */ - if (rt->rt_flags & RTF_GATEWAY) { - struct rtentry *gwrt; - - RT_UNLOCK(rt); /* XXX workaround LOR */ - gwrt = rtalloc1_fib(gate, 1, RTF_RNH_LOCKED, rt->rt_fibnum); - if (gwrt == rt) { - RT_REMREF(rt); - return (EADDRINUSE); /* failure */ - } - /* - * Try to reacquire the lock on rt, and if it fails, - * clean state and restart from scratch. - */ - if (!RT_TRYLOCK(rt)) { - RTFREE_LOCKED(gwrt); - RT_LOCK(rt); - goto again; - } - /* - * If there is already a gwroute, then drop it. If we - * are asked to replace route with itself, then do - * not leak its refcounter. - */ - if (rt->rt_gwroute != NULL) { - if (rt->rt_gwroute == gwrt) { - RT_REMREF(rt->rt_gwroute); - } else - RTFREE(rt->rt_gwroute); - } - - if ((rt->rt_gwroute = gwrt) != NULL) - RT_UNLOCK(rt->rt_gwroute); - } - - /* * Prepare to store the gateway in rt->rt_gateway. * Both dst and gateway are stored one after the other in the same * malloc'd chunk. If we have room, we can reuse the old buffer, @@ -1446,21 +1105,7 @@ again: */ bcopy(gate, rt->rt_gateway, glen); - /* - * This isn't going to do anything useful for host routes, so - * don't bother. Also make sure we have a reasonable mask - * (we don't yet have one during adds). - */ - if (!(rt->rt_flags & RTF_HOST) && rt_mask(rt) != 0) { - struct rtfc_arg arg; - - arg.rnh = rnh; - arg.rt0 = rt; - rnh->rnh_walktree_from(rnh, rt_key(rt), rt_mask(rt), - rt_fixchange, &arg); - } - - return 0; + return (0); } static void @@ -1500,6 +1145,7 @@ rtinit1(struct ifaddr *ifa, int cmd, int flags, int fibnum) char tempbuf[_SOCKADDR_TMPSIZE]; int didwork = 0; int a_failure = 0; + static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; if (flags & RTF_HOST) { dst = ifa->ifa_dstaddr; @@ -1604,7 +1250,14 @@ rtinit1(struct ifaddr *ifa, int cmd, int flags, int fibnum) info.rti_ifa = ifa; info.rti_flags = flags | ifa->ifa_flags; info.rti_info[RTAX_DST] = dst; - info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr; + /* + * doing this for compatibility reasons + */ + if (cmd == RTM_ADD) + info.rti_info[RTAX_GATEWAY] = + (struct sockaddr *)&null_sdl; + else + info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr; info.rti_info[RTAX_NETMASK] = netmask; error = rtrequest1_fib(cmd, &info, &rt, fibnum); if (error == 0 && rt != NULL) { @@ -1628,6 +1281,15 @@ rtinit1(struct ifaddr *ifa, int cmd, int flags, int fibnum) rt->rt_ifa = ifa; } #endif + /* + * doing this for compatibility reasons + */ + if (cmd == RTM_ADD) { + ((struct sockaddr_dl *)rt->rt_gateway)->sdl_type = + rt->rt_ifp->if_type; + ((struct sockaddr_dl *)rt->rt_gateway)->sdl_index = + rt->rt_ifp->if_index; + } rt_newaddrmsg(cmd, ifa, error, rt); if (cmd == RTM_DELETE) { /* @@ -1696,147 +1358,5 @@ rtinit(struct ifaddr *ifa, int cmd, int flags) return (rtinit1(ifa, cmd, flags, fib)); } -/* - * rt_check() is invoked on each layer 2 output path, prior to - * encapsulating outbound packets. - * - * The function is mostly used to find a routing entry for the gateway, - * which in some protocol families could also point to the link-level - * address for the gateway itself (the side effect of revalidating the - * route to the destination is rather pointless at this stage, we did it - * already a moment before in the pr_output() routine to locate the ifp - * and gateway to use). - * - * When we remove the layer-3 to layer-2 mapping tables from the - * routing table, this function can be removed. - * - * === On input === - * *dst is the address of the NEXT HOP (which coincides with the - * final destination if directly reachable); - * *lrt0 points to the cached route to the final destination; - * *lrt is not meaningful; - * (*lrt0 has no ref held on it by us so REMREF is not needed. - * Refs only account for major structural references and not usages, - * which is actually a bit of a problem.) - * - * === Operation === - * If the route is marked down try to find a new route. If the route - * to the gateway is gone, try to setup a new route. Otherwise, - * if the route is marked for packets to be rejected, enforce that. - * Note that rtalloc returns an rtentry with an extra REF that we may - * need to lose. - * - * === On return === - * *dst is unchanged; - * *lrt0 points to the (possibly new) route to the final destination - * *lrt points to the route to the next hop [LOCKED] - * - * Their values are meaningful ONLY if no error is returned. - * - * To follow this you have to remember that: - * RT_REMREF reduces the reference count by 1 but doesn't check it for 0 (!) - * RTFREE_LOCKED includes an RT_REMREF (or an rtfree if refs == 1) - * and an RT_UNLOCK - * RTFREE does an RT_LOCK and an RTFREE_LOCKED - * The gwroute pointer counts as a reference on the rtentry to which it points. - * so when we add it we use the ref that rtalloc gives us and when we lose it - * we need to remove the reference. - * RT_TEMP_UNLOCK does an RT_ADDREF before freeing the lock, and - * RT_RELOCK locks it (it can't have gone away due to the ref) and - * drops the ref, possibly freeing it and zeroing the pointer if - * the ref goes to 0 (unlocking in the process). - */ -int -rt_check(struct rtentry **lrt, struct rtentry **lrt0, struct sockaddr *dst) -{ - struct rtentry *rt; - struct rtentry *rt0; - u_int fibnum; - - KASSERT(*lrt0 != NULL, ("rt_check")); - rt0 = *lrt0; - rt = NULL; - fibnum = rt0->rt_fibnum; - - /* NB: the locking here is tortuous... */ - RT_LOCK(rt0); -retry: - if (rt0 && (rt0->rt_flags & RTF_UP) == 0) { - /* Current rt0 is useless, try get a replacement. */ - RT_UNLOCK(rt0); - rt0 = NULL; - } - if (rt0 == NULL) { - rt0 = rtalloc1_fib(dst, 1, 0UL, fibnum); - if (rt0 == NULL) { - return (EHOSTUNREACH); - } - RT_REMREF(rt0); /* don't need the reference. */ - } - - if (rt0->rt_flags & RTF_GATEWAY) { - if ((rt = rt0->rt_gwroute) != NULL) { - RT_LOCK(rt); /* NB: gwroute */ - if ((rt->rt_flags & RTF_UP) == 0) { - /* gw route is dud. ignore/lose it */ - RTFREE_LOCKED(rt); /* unref (&unlock) gwroute */ - rt = rt0->rt_gwroute = NULL; - } - } - - if (rt == NULL) { /* NOT AN ELSE CLAUSE */ - RT_TEMP_UNLOCK(rt0); /* MUST return to undo this */ - rt = rtalloc1_fib(rt0->rt_gateway, 1, 0UL, fibnum); - if ((rt == rt0) || (rt == NULL)) { - /* the best we can do is not good enough */ - if (rt) { - RT_REMREF(rt); /* assumes ref > 0 */ - RT_UNLOCK(rt); - } - RTFREE(rt0); /* lock, unref, (unlock) */ - return (ENETUNREACH); - } - /* - * Relock it and lose the added reference. - * All sorts of things could have happenned while we - * had no lock on it, so check for them. - */ - RT_RELOCK(rt0); - if (rt0 == NULL || ((rt0->rt_flags & RTF_UP) == 0)) - /* Ru-roh.. what we had is no longer any good */ - goto retry; - /* - * While we were away, someone replaced the gateway. - * Since a reference count is involved we can't just - * overwrite it. - */ - if (rt0->rt_gwroute) { - if (rt0->rt_gwroute != rt) { - RTFREE_LOCKED(rt); - goto retry; - } - } else { - rt0->rt_gwroute = rt; - } - } - RT_LOCK_ASSERT(rt); - RT_UNLOCK(rt0); - } else { - /* think of rt as having the lock from now on.. */ - rt = rt0; - } - /* XXX why are we inspecting rmx_expire? */ - if ((rt->rt_flags & RTF_REJECT) && - (rt->rt_rmx.rmx_expire == 0 || - time_uptime < rt->rt_rmx.rmx_expire)) { - RT_UNLOCK(rt); - return (rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); - } - - *lrt = rt; - *lrt0 = rt0; - return (0); -} - /* This must be before ip6_init2(), which is now SI_ORDER_MIDDLE */ SYSINIT(route, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, route_init, 0); diff --git a/sys/net/route.h b/sys/net/route.h index fb8df39..5062198 100644 --- a/sys/net/route.h +++ b/sys/net/route.h @@ -135,15 +135,11 @@ struct rtentry { #define rt_key(r) (*((struct sockaddr **)(&(r)->rt_nodes->rn_key))) #define rt_mask(r) (*((struct sockaddr **)(&(r)->rt_nodes->rn_mask))) struct sockaddr *rt_gateway; /* value */ - u_long rt_flags; /* up/down?, host/net */ + int rt_flags; /* up/down?, host/net */ + int rt_refcnt; /* # held references */ struct ifnet *rt_ifp; /* the answer: interface to use */ struct ifaddr *rt_ifa; /* the answer: interface address to use */ struct rt_metrics_lite rt_rmx; /* metrics used by rx'ing protocols */ - long rt_refcnt; /* # held references */ - struct sockaddr *rt_genmask; /* for generation of cloned routes */ - caddr_t rt_llinfo; /* pointer to link level info cache */ - struct rtentry *rt_gwroute; /* implied entry for gatewayed routes */ - struct rtentry *rt_parent; /* cloning parent of this route */ u_int rt_fibnum; /* which FIB */ #ifdef _KERNEL /* XXX ugly, user apps use this definition but don't have a mtx def */ @@ -175,9 +171,9 @@ struct ortentry { #define RTF_MODIFIED 0x20 /* modified dynamically (by redirect) */ #define RTF_DONE 0x40 /* message confirmed */ /* 0x80 unused, was RTF_DELCLONE */ -#define RTF_CLONING 0x100 /* generate new routes on use */ +/* 0x100 unused, was RTF_CLONING */ #define RTF_XRESOLVE 0x200 /* external daemon resolves name */ -#define RTF_LLINFO 0x400 /* generated by link layer (e.g. ARP) */ +/* 0x400 unused, was RTF_LLINFO */ #define RTF_STATIC 0x800 /* manually added */ #define RTF_BLACKHOLE 0x1000 /* just discard pkts (during updates) */ #define RTF_PROTO2 0x4000 /* protocol specific routing flag */ @@ -188,7 +184,7 @@ struct ortentry { #define RTF_PRCLONING 0x10000 /* unused, for compatibility */ #endif -#define RTF_WASCLONED 0x20000 /* route generated through cloning */ +/* 0x20000 unused, was RTF_WASCLONED */ #define RTF_PROTO3 0x40000 /* protocol specific routing flag */ /* 0x80000 unused */ #define RTF_PINNED 0x100000 /* future use */ @@ -326,14 +322,14 @@ struct rt_addrinfo { #define RT_ADDREF(_rt) do { \ RT_LOCK_ASSERT(_rt); \ KASSERT((_rt)->rt_refcnt >= 0, \ - ("negative refcnt %ld", (_rt)->rt_refcnt)); \ + ("negative refcnt %d", (_rt)->rt_refcnt)); \ (_rt)->rt_refcnt++; \ } while (0) #define RT_REMREF(_rt) do { \ RT_LOCK_ASSERT(_rt); \ KASSERT((_rt)->rt_refcnt > 0, \ - ("bogus refcnt %ld", (_rt)->rt_refcnt)); \ + ("bogus refcnt %d", (_rt)->rt_refcnt)); \ (_rt)->rt_refcnt--; \ } while (0) @@ -409,7 +405,6 @@ void rtredirect(struct sockaddr *, struct sockaddr *, struct sockaddr *, int, struct sockaddr *); int rtrequest(int, struct sockaddr *, struct sockaddr *, struct sockaddr *, int, struct rtentry **); -int rtrequest1(int, struct rt_addrinfo *, struct rtentry **); /* defaults to "all" FIBs */ int rtinit_fib(struct ifaddr *, int, int); diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c index e8cc021..30591c7 100644 --- a/sys/net/rtsock.c +++ b/sys/net/rtsock.c @@ -53,6 +53,7 @@ #include <sys/vimage.h> #include <net/if.h> +#include <net/if_llatbl.h> #include <net/netisr.h> #include <net/raw_cb.h> #include <net/route.h> @@ -496,19 +497,6 @@ route_output(struct mbuf *m, struct socket *so) (info.rti_info[RTAX_GATEWAY] != NULL && info.rti_info[RTAX_GATEWAY]->sa_family >= AF_MAX)) senderr(EINVAL); - if (info.rti_info[RTAX_GENMASK]) { - struct radix_node *t; - t = rn_addmask((caddr_t) info.rti_info[RTAX_GENMASK], 0, 1); - if (t != NULL && - bcmp((char *)(void *)info.rti_info[RTAX_GENMASK] + 1, - (char *)(void *)t->rn_key + 1, - ((struct sockaddr *)t->rn_key)->sa_len - 1) == 0) - info.rti_info[RTAX_GENMASK] = - (struct sockaddr *)t->rn_key; - else - senderr(ENOBUFS); - } - /* * Verify that the caller has the appropriate privilege; RTM_GET * is the only operation the non-superuser is allowed. @@ -526,6 +514,11 @@ route_output(struct mbuf *m, struct socket *so) if (info.rti_info[RTAX_GATEWAY] == NULL) senderr(EINVAL); saved_nrt = NULL; + /* support for new ARP code */ + if (info.rti_info[RTAX_GATEWAY]->sa_family == AF_LINK) { + error = lla_rt_output(rtm, &info); + break; + } error = rtrequest1_fib(RTM_ADD, &info, &saved_nrt, so->so_fibnum); if (error == 0 && saved_nrt) { @@ -534,13 +527,18 @@ route_output(struct mbuf *m, struct socket *so) &rtm->rtm_rmx, &saved_nrt->rt_rmx); rtm->rtm_index = saved_nrt->rt_ifp->if_index; RT_REMREF(saved_nrt); - saved_nrt->rt_genmask = info.rti_info[RTAX_GENMASK]; RT_UNLOCK(saved_nrt); } break; case RTM_DELETE: saved_nrt = NULL; + /* support for new ARP code */ + if (info.rti_info[RTAX_GATEWAY] && + (info.rti_info[RTAX_GATEWAY]->sa_family == AF_LINK)) { + error = lla_rt_output(rtm, &info); + break; + } error = rtrequest1_fib(RTM_DELETE, &info, &saved_nrt, so->so_fibnum); if (error == 0) { @@ -612,7 +610,7 @@ route_output(struct mbuf *m, struct socket *so) info.rti_info[RTAX_DST] = rt_key(rt); info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; info.rti_info[RTAX_NETMASK] = rt_mask(rt); - info.rti_info[RTAX_GENMASK] = rt->rt_genmask; + info.rti_info[RTAX_GENMASK] = 0; if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) { ifp = rt->rt_ifp; if (ifp) { @@ -673,10 +671,10 @@ route_output(struct mbuf *m, struct socket *so) rt->rt_ifa->ifa_addr))) { RT_UNLOCK(rt); RADIX_NODE_HEAD_LOCK(rnh); - if ((error = rt_getifa_fib(&info, - rt->rt_fibnum)) != 0) - senderr(error); + error = rt_getifa_fib(&info, rt->rt_fibnum); RADIX_NODE_HEAD_UNLOCK(rnh); + if (error != 0) + senderr(error); RT_LOCK(rt); } if (info.rti_ifa != NULL && @@ -699,8 +697,7 @@ route_output(struct mbuf *m, struct socket *so) RT_UNLOCK(rt); senderr(error); } - if (!(rt->rt_flags & RTF_LLINFO)) - rt->rt_flags |= RTF_GATEWAY; + rt->rt_flags |= RTF_GATEWAY; } if (info.rti_ifa != NULL && info.rti_ifa != rt->rt_ifa) { @@ -718,8 +715,6 @@ route_output(struct mbuf *m, struct socket *so) rtm->rtm_index = rt->rt_ifp->if_index; if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest) rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, &info); - if (info.rti_info[RTAX_GENMASK]) - rt->rt_genmask = info.rti_info[RTAX_GENMASK]; /* FALLTHROUGH */ case RTM_LOCK: /* We don't support locks anymore */ @@ -1261,7 +1256,7 @@ sysctl_dumpentry(struct radix_node *rn, void *vw) info.rti_info[RTAX_DST] = rt_key(rt); info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; info.rti_info[RTAX_NETMASK] = rt_mask(rt); - info.rti_info[RTAX_GENMASK] = rt->rt_genmask; + info.rti_info[RTAX_GENMASK] = 0; if (rt->rt_ifp) { info.rti_info[RTAX_IFP] = rt->rt_ifp->if_addr->ifa_addr; info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; @@ -1440,6 +1435,11 @@ sysctl_rtsock(SYSCTL_HANDLER_ARGS) RADIX_NODE_HEAD_UNLOCK(rnh); } else if (af != 0) error = EAFNOSUPPORT; + /* + * take care of llinfo entries + */ + if (w.w_op == NET_RT_FLAGS) + error = lltable_sysctl_dumparp(af, w.w_req); break; case NET_RT_IFLIST: diff --git a/sys/net80211/_ieee80211.h b/sys/net80211/_ieee80211.h index b735b5c..f5858fe 100644 --- a/sys/net80211/_ieee80211.h +++ b/sys/net80211/_ieee80211.h @@ -137,7 +137,7 @@ struct ieee80211_channel { uint8_t ic_extieee; /* HT40 extension channel number */ }; -#define IEEE80211_CHAN_MAX 255 +#define IEEE80211_CHAN_MAX 256 #define IEEE80211_CHAN_BYTES 32 /* howmany(IEEE80211_CHAN_MAX, NBBY) */ #define IEEE80211_CHAN_ANY 0xffff /* token for ``any channel'' */ #define IEEE80211_CHAN_ANYC \ diff --git a/sys/net80211/ieee80211.c b/sys/net80211/ieee80211.c index cce1312..e0a9432 100644 --- a/sys/net80211/ieee80211.c +++ b/sys/net80211/ieee80211.c @@ -118,7 +118,7 @@ ieee80211_chan_init(struct ieee80211com *ic) struct ieee80211_channel *c; int i; - KASSERT(0 < ic->ic_nchans && ic->ic_nchans < IEEE80211_CHAN_MAX, + KASSERT(0 < ic->ic_nchans && ic->ic_nchans <= IEEE80211_CHAN_MAX, ("invalid number of channels specified: %u", ic->ic_nchans)); memset(ic->ic_chan_avail, 0, sizeof(ic->ic_chan_avail)); memset(ic->ic_modecaps, 0, sizeof(ic->ic_modecaps)); @@ -126,8 +126,6 @@ ieee80211_chan_init(struct ieee80211com *ic) for (i = 0; i < ic->ic_nchans; i++) { c = &ic->ic_channels[i]; KASSERT(c->ic_flags != 0, ("channel with no flags")); - KASSERT(c->ic_ieee < IEEE80211_CHAN_MAX, - ("channel with bogus ieee number %u", c->ic_ieee)); setbit(ic->ic_chan_avail, c->ic_ieee); /* * Identify mode capabilities. diff --git a/sys/net80211/ieee80211_acl.c b/sys/net80211/ieee80211_acl.c index 13407a4..cb20b87 100644 --- a/sys/net80211/ieee80211_acl.c +++ b/sys/net80211/ieee80211_acl.c @@ -99,7 +99,7 @@ acl_attach(struct ieee80211vap *vap) { struct aclstate *as; - MALLOC(as, struct aclstate *, sizeof(struct aclstate), + as = (struct aclstate *) malloc(sizeof(struct aclstate), M_80211_ACL, M_NOWAIT | M_ZERO); if (as == NULL) return 0; @@ -123,7 +123,7 @@ acl_detach(struct ieee80211vap *vap) acl_free_all(vap); vap->iv_as = NULL; ACL_LOCK_DESTROY(as); - FREE(as, M_80211_ACL); + free(as, M_80211_ACL); } static __inline struct acl * @@ -147,7 +147,7 @@ _acl_free(struct aclstate *as, struct acl *acl) TAILQ_REMOVE(&as->as_list, acl, acl_list); LIST_REMOVE(acl, acl_hash); - FREE(acl, M_80211_ACL); + free(acl, M_80211_ACL); as->as_nacls--; } @@ -175,7 +175,7 @@ acl_add(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN]) struct acl *acl, *new; int hash; - MALLOC(new, struct acl *, sizeof(struct acl), M_80211_ACL, M_NOWAIT | M_ZERO); + new = (struct acl *) malloc(sizeof(struct acl), M_80211_ACL, M_NOWAIT | M_ZERO); if (new == NULL) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL, "ACL: add %s failed, no memory\n", ether_sprintf(mac)); @@ -188,7 +188,7 @@ acl_add(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN]) LIST_FOREACH(acl, &as->as_hash[hash], acl_hash) { if (IEEE80211_ADDR_EQ(acl->acl_macaddr, mac)) { ACL_UNLOCK(as); - FREE(new, M_80211_ACL); + free(new, M_80211_ACL); IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL, "ACL: add %s failed, already present\n", ether_sprintf(mac)); @@ -301,7 +301,7 @@ acl_getioctl(struct ieee80211vap *vap, struct ieee80211req *ireq) ireq->i_len = space; /* return required space */ return 0; /* NB: must not error */ } - MALLOC(ap, struct ieee80211req_maclist *, space, + ap = (struct ieee80211req_maclist *) malloc(space, M_TEMP, M_NOWAIT); if (ap == NULL) return ENOMEM; @@ -317,7 +317,7 @@ acl_getioctl(struct ieee80211vap *vap, struct ieee80211req *ireq) ireq->i_len = space; } else error = copyout(ap, ireq->i_data, ireq->i_len); - FREE(ap, M_TEMP); + free(ap, M_TEMP); return error; } return EINVAL; diff --git a/sys/net80211/ieee80211_crypto.h b/sys/net80211/ieee80211_crypto.h index 63a9583..40a6b03 100644 --- a/sys/net80211/ieee80211_crypto.h +++ b/sys/net80211/ieee80211_crypto.h @@ -218,7 +218,7 @@ static __inline void ieee80211_crypto_resetkey(struct ieee80211vap *vap, struct ieee80211_key *k, ieee80211_keyix ix) { - k->wk_cipher = &ieee80211_cipher_none;; + k->wk_cipher = &ieee80211_cipher_none; k->wk_private = k->wk_cipher->ic_attach(vap, k); k->wk_keyix = k->wk_rxkeyix = ix; k->wk_flags = IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV; diff --git a/sys/net80211/ieee80211_crypto_ccmp.c b/sys/net80211/ieee80211_crypto_ccmp.c index bdaf7e3..c2e9486 100644 --- a/sys/net80211/ieee80211_crypto_ccmp.c +++ b/sys/net80211/ieee80211_crypto_ccmp.c @@ -96,7 +96,7 @@ ccmp_attach(struct ieee80211vap *vap, struct ieee80211_key *k) { struct ccmp_ctx *ctx; - MALLOC(ctx, struct ccmp_ctx *, sizeof(struct ccmp_ctx), + ctx = (struct ccmp_ctx *) malloc(sizeof(struct ccmp_ctx), M_80211_CRYPTO, M_NOWAIT | M_ZERO); if (ctx == NULL) { vap->iv_stats.is_crypto_nomem++; @@ -113,7 +113,7 @@ ccmp_detach(struct ieee80211_key *k) { struct ccmp_ctx *ctx = k->wk_private; - FREE(ctx, M_80211_CRYPTO); + free(ctx, M_80211_CRYPTO); KASSERT(nrefs > 0, ("imbalanced attach/detach")); nrefs--; /* NB: we assume caller locking */ } diff --git a/sys/net80211/ieee80211_crypto_tkip.c b/sys/net80211/ieee80211_crypto_tkip.c index f509856..b20946a 100644 --- a/sys/net80211/ieee80211_crypto_tkip.c +++ b/sys/net80211/ieee80211_crypto_tkip.c @@ -109,7 +109,7 @@ tkip_attach(struct ieee80211vap *vap, struct ieee80211_key *k) { struct tkip_ctx *ctx; - MALLOC(ctx, struct tkip_ctx *, sizeof(struct tkip_ctx), + ctx = (struct tkip_ctx *) malloc(sizeof(struct tkip_ctx), M_80211_CRYPTO, M_NOWAIT | M_ZERO); if (ctx == NULL) { vap->iv_stats.is_crypto_nomem++; @@ -126,7 +126,7 @@ tkip_detach(struct ieee80211_key *k) { struct tkip_ctx *ctx = k->wk_private; - FREE(ctx, M_80211_CRYPTO); + free(ctx, M_80211_CRYPTO); KASSERT(nrefs > 0, ("imbalanced attach/detach")); nrefs--; /* NB: we assume caller locking */ } diff --git a/sys/net80211/ieee80211_crypto_wep.c b/sys/net80211/ieee80211_crypto_wep.c index 7eade59..07c1797 100644 --- a/sys/net80211/ieee80211_crypto_wep.c +++ b/sys/net80211/ieee80211_crypto_wep.c @@ -87,7 +87,7 @@ wep_attach(struct ieee80211vap *vap, struct ieee80211_key *k) { struct wep_ctx *ctx; - MALLOC(ctx, struct wep_ctx *, sizeof(struct wep_ctx), + ctx = (struct wep_ctx *) malloc(sizeof(struct wep_ctx), M_80211_CRYPTO, M_NOWAIT | M_ZERO); if (ctx == NULL) { vap->iv_stats.is_crypto_nomem++; @@ -106,7 +106,7 @@ wep_detach(struct ieee80211_key *k) { struct wep_ctx *ctx = k->wk_private; - FREE(ctx, M_80211_CRYPTO); + free(ctx, M_80211_CRYPTO); KASSERT(nrefs > 0, ("imbalanced attach/detach")); nrefs--; /* NB: we assume caller locking */ } diff --git a/sys/net80211/ieee80211_ddb.c b/sys/net80211/ieee80211_ddb.c index b3dd4d4..59c6a46 100644 --- a/sys/net80211/ieee80211_ddb.c +++ b/sys/net80211/ieee80211_ddb.c @@ -92,7 +92,8 @@ __FBSDID("$FreeBSD$"); #define IEEE80211_NODE_BITS \ "\20\1AUTH\2QOS\3ERP\5PWR_MGT\6AREF\7HT\10HTCOMPAT\11WPS\12TSN" \ - "\13AMPDU_RX\14AMPDU_TX\15MIMO_PS\16MIMO_RTS\17RIFS\20SGI20\21SGI40" + "\13AMPDU_RX\14AMPDU_TX\15MIMO_PS\16MIMO_RTS\17RIFS\20SGI20\21SGI40" \ + "\22ASSOCID" #define IEEE80211_ERP_BITS \ "\20\1NON_ERP_PRESENT\2USE_PROTECTION\3LONG_PREAMBLE" @@ -541,7 +542,7 @@ _db_show_com(const struct ieee80211com *ic, int showvaps, int showsta, int showp */ db_printf("\tnchans %d", ic->ic_nchans); #if 0 - struct ieee80211_channel ic_channels[IEEE80211_CHAN_MAX+1]; + struct ieee80211_channel ic_channels[IEEE80211_CHAN_MAX]; uint8_t ic_chan_avail[IEEE80211_CHAN_BYTES]; uint8_t ic_chan_active[IEEE80211_CHAN_BYTES]; uint8_t ic_chan_scan[IEEE80211_CHAN_BYTES]; diff --git a/sys/net80211/ieee80211_dfs.h b/sys/net80211/ieee80211_dfs.h index 36d14aa..9076077 100644 --- a/sys/net80211/ieee80211_dfs.h +++ b/sys/net80211/ieee80211_dfs.h @@ -32,7 +32,7 @@ */ struct ieee80211_dfs_state { - int nol_event[IEEE80211_CHAN_MAX+1]; + int nol_event[IEEE80211_CHAN_MAX]; struct callout nol_timer; /* NOL list processing */ struct callout cac_timer; /* CAC timer */ struct timeval lastevent; /* time of last radar event */ diff --git a/sys/net80211/ieee80211_freebsd.c b/sys/net80211/ieee80211_freebsd.c index 71174b7..60de0f4 100644 --- a/sys/net80211/ieee80211_freebsd.c +++ b/sys/net80211/ieee80211_freebsd.c @@ -234,7 +234,7 @@ ieee80211_sysctl_vattach(struct ieee80211vap *vap) struct sysctl_oid *oid; char num[14]; /* sufficient for 32 bits */ - MALLOC(ctx, struct sysctl_ctx_list *, sizeof(struct sysctl_ctx_list), + ctx = (struct sysctl_ctx_list *) malloc(sizeof(struct sysctl_ctx_list), M_DEVBUF, M_NOWAIT | M_ZERO); if (ctx == NULL) { if_printf(ifp, "%s: cannot allocate sysctl context!\n", @@ -310,7 +310,7 @@ ieee80211_sysctl_vdetach(struct ieee80211vap *vap) if (vap->iv_sysctl != NULL) { sysctl_ctx_free(vap->iv_sysctl); - FREE(vap->iv_sysctl, M_DEVBUF); + free(vap->iv_sysctl, M_DEVBUF); vap->iv_sysctl = NULL; } } diff --git a/sys/net80211/ieee80211_hostap.c b/sys/net80211/ieee80211_hostap.c index 60cbe4b..c333954 100644 --- a/sys/net80211/ieee80211_hostap.c +++ b/sys/net80211/ieee80211_hostap.c @@ -902,7 +902,7 @@ hostap_auth_open(struct ieee80211_node *ni, struct ieee80211_frame *wh, * open auth is attempted. */ if (ni->ni_challenge != NULL) { - FREE(ni->ni_challenge, M_80211_NODE); + free(ni->ni_challenge, M_80211_NODE); ni->ni_challenge = NULL; } /* XXX hack to workaround calling convention */ @@ -928,6 +928,11 @@ hostap_auth_open(struct ieee80211_node *ni, struct ieee80211_frame *wh, * after the transaction completes. */ ni->ni_flags |= IEEE80211_NODE_AREF; + /* + * Mark the node as requiring a valid association id + * before outbound traffic is permitted. + */ + ni->ni_flags |= IEEE80211_NODE_ASSOCID; if (vap->iv_acl != NULL && vap->iv_acl->iac_getpolicy(vap) == IEEE80211_MACCMD_POLICY_RADIUS) { @@ -1054,6 +1059,11 @@ hostap_auth_shared(struct ieee80211_node *ni, struct ieee80211_frame *wh, * after the transaction completes. */ ni->ni_flags |= IEEE80211_NODE_AREF; + /* + * Mark the node as requiring a valid associatio id + * before outbound traffic is permitted. + */ + ni->ni_flags |= IEEE80211_NODE_ASSOCID; IEEE80211_RSSI_LPF(ni->ni_avgrssi, rssi); ni->ni_noise = noise; ni->ni_rstamp = rstamp; @@ -1986,7 +1996,7 @@ hostap_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, return; /* discard challenge after association */ if (ni->ni_challenge != NULL) { - FREE(ni->ni_challenge, M_80211_NODE); + free(ni->ni_challenge, M_80211_NODE); ni->ni_challenge = NULL; } /* NB: 802.11 spec says to ignore station's privacy bit */ diff --git a/sys/net80211/ieee80211_input.c b/sys/net80211/ieee80211_input.c index e72a2a2..e68bb6c 100644 --- a/sys/net80211/ieee80211_input.c +++ b/sys/net80211/ieee80211_input.c @@ -499,7 +499,7 @@ int ieee80211_alloc_challenge(struct ieee80211_node *ni) { if (ni->ni_challenge == NULL) - MALLOC(ni->ni_challenge, uint32_t*, IEEE80211_CHALLENGE_LEN, + ni->ni_challenge = (uint32_t *) malloc(IEEE80211_CHALLENGE_LEN, M_80211_NODE, M_NOWAIT); if (ni->ni_challenge == NULL) { IEEE80211_NOTE(ni->ni_vap, @@ -673,14 +673,6 @@ ieee80211_parse_beacon(struct ieee80211_node *ni, struct mbuf *m, } IEEE80211_VERIFY_ELEMENT(scan->ssid, IEEE80211_NWID_LEN, scan->status |= IEEE80211_BPARSE_SSID_INVALID); -#if IEEE80211_CHAN_MAX < 255 - if (scan->chan > IEEE80211_CHAN_MAX) { - IEEE80211_DISCARD(vap, IEEE80211_MSG_ELEMID, - wh, NULL, "invalid channel %u", scan->chan); - vap->iv_stats.is_rx_badchan++; - scan->status |= IEEE80211_BPARSE_CHAN_INVALID; - } -#endif if (scan->chan != scan->bchan && ic->ic_phytype != IEEE80211_T_FH) { /* * Frame was received on a channel different from the diff --git a/sys/net80211/ieee80211_ioctl.c b/sys/net80211/ieee80211_ioctl.c index ae39fd6..b967e47 100644 --- a/sys/net80211/ieee80211_ioctl.c +++ b/sys/net80211/ieee80211_ioctl.c @@ -320,14 +320,14 @@ ieee80211_ioctl_getscanresults(struct ieee80211vap *vap, space = req.space; /* XXX M_WAITOK after driver lock released */ - MALLOC(p, void *, space, M_TEMP, M_NOWAIT | M_ZERO); + p = malloc(space, M_TEMP, M_NOWAIT | M_ZERO); if (p == NULL) return ENOMEM; req.sr = p; ieee80211_scan_iterate(vap, get_scan_result, &req); ireq->i_len = space - req.space; error = copyout(p, ireq->i_data, ireq->i_len); - FREE(p, M_TEMP); + free(p, M_TEMP); } else ireq->i_len = 0; @@ -467,7 +467,7 @@ getstainfo_common(struct ieee80211vap *vap, struct ieee80211req *ireq, if (req.space > 0) { space = req.space; /* XXX M_WAITOK after driver lock released */ - MALLOC(p, void *, space, M_TEMP, M_NOWAIT | M_ZERO); + p = malloc(space, M_TEMP, M_NOWAIT | M_ZERO); if (p == NULL) { error = ENOMEM; goto bad; @@ -479,7 +479,7 @@ getstainfo_common(struct ieee80211vap *vap, struct ieee80211req *ireq, get_sta_info(&req, ni); ireq->i_len = space - req.space; error = copyout(p, (uint8_t *) ireq->i_data+off, ireq->i_len); - FREE(p, M_TEMP); + free(p, M_TEMP); } else ireq->i_len = 0; bad: @@ -696,7 +696,7 @@ ieee80211_ioctl_getdevcaps(struct ieee80211com *ic, if (ireq->i_len != sizeof(struct ieee80211_devcaps_req)) return EINVAL; - MALLOC(dc, struct ieee80211_devcaps_req *, + dc = (struct ieee80211_devcaps_req *) malloc( sizeof(struct ieee80211_devcaps_req), M_TEMP, M_NOWAIT | M_ZERO); if (dc == NULL) return ENOMEM; @@ -707,7 +707,7 @@ ieee80211_ioctl_getdevcaps(struct ieee80211com *ic, ic->ic_getradiocaps(ic, &ci->ic_nchans, ci->ic_chans); ieee80211_sort_channels(ci->ic_chans, ci->ic_nchans); error = copyout(dc, ireq->i_data, sizeof(*dc)); - FREE(dc, M_TEMP); + free(dc, M_TEMP); return error; } @@ -1556,7 +1556,7 @@ ieee80211_ioctl_setchanlist(struct ieee80211vap *vap, struct ieee80211req *ireq) struct ieee80211com *ic = vap->iv_ic; struct ieee80211req_chanlist list; u_char chanlist[IEEE80211_CHAN_BYTES]; - int i, j, nchan, error; + int i, nchan, error; if (ireq->i_len != sizeof(list)) return EINVAL; @@ -1564,22 +1564,16 @@ ieee80211_ioctl_setchanlist(struct ieee80211vap *vap, struct ieee80211req *ireq) if (error) return error; memset(chanlist, 0, sizeof(chanlist)); - /* - * Since channel 0 is not available for DS, channel 1 - * is assigned to LSB on WaveLAN. - */ - if (ic->ic_phytype == IEEE80211_T_DS) - i = 1; - else - i = 0; nchan = 0; - for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++) { + for (i = 0; i < ic->ic_nchans; i++) { + const struct ieee80211_channel *c = &ic->ic_channels[i]; /* - * NB: silently discard unavailable channels so users - * can specify 1-255 to get all available channels. + * Calculate the intersection of the user list and the + * available channels so users can do things like specify + * 1-255 to get all available channels. */ - if (isset(list.ic_channels, j) && isset(ic->ic_chan_avail, i)) { - setbit(chanlist, i); + if (isset(list.ic_channels, c->ic_ieee)) { + setbit(chanlist, c->ic_ieee); nchan++; } } @@ -1890,8 +1884,6 @@ ieee80211_ioctl_setchannel(struct ieee80211vap *vap, if (ireq->i_val == 0 || ireq->i_val == (int16_t) IEEE80211_CHAN_ANY) { c = IEEE80211_CHAN_ANYC; - } else if ((u_int) ireq->i_val > IEEE80211_CHAN_MAX) { - return EINVAL; } else { struct ieee80211_channel *c2; @@ -1993,14 +1985,14 @@ ieee80211_ioctl_setregdomain(struct ieee80211vap *vap, if (ireq->i_len != sizeof(struct ieee80211_regdomain_req)) return EINVAL; - MALLOC(reg, struct ieee80211_regdomain_req *, + reg = (struct ieee80211_regdomain_req *) malloc( sizeof(struct ieee80211_regdomain_req), M_TEMP, M_NOWAIT); if (reg == NULL) return ENOMEM; error = copyin(ireq->i_data, reg, sizeof(*reg)); if (error == 0) error = ieee80211_setregdomain(vap, reg); - FREE(reg, M_TEMP); + free(reg, M_TEMP); return (error == 0 ? ENETRESET : error); } @@ -2139,7 +2131,7 @@ setappie(struct ieee80211_appie **aie, const struct ieee80211req *ireq) if (ireq->i_len == 0) { /* delete any existing ie */ if (app != NULL) { *aie = NULL; /* XXX racey */ - FREE(app, M_80211_NODE_IE); + free(app, M_80211_NODE_IE); } return 0; } @@ -2153,20 +2145,20 @@ setappie(struct ieee80211_appie **aie, const struct ieee80211req *ireq) * * XXX bad bad bad */ - MALLOC(napp, struct ieee80211_appie *, + napp = (struct ieee80211_appie *) malloc( sizeof(struct ieee80211_appie) + ireq->i_len, M_80211_NODE_IE, M_NOWAIT); if (napp == NULL) return ENOMEM; /* XXX holding ic lock */ error = copyin(ireq->i_data, napp->ie_data, ireq->i_len); if (error) { - FREE(napp, M_80211_NODE_IE); + free(napp, M_80211_NODE_IE); return error; } napp->ie_len = ireq->i_len; *aie = napp; if (app != NULL) - FREE(app, M_80211_NODE_IE); + free(app, M_80211_NODE_IE); return 0; } diff --git a/sys/net80211/ieee80211_node.c b/sys/net80211/ieee80211_node.c index 8e9d91f..e3028d9 100644 --- a/sys/net80211/ieee80211_node.c +++ b/sys/net80211/ieee80211_node.c @@ -153,7 +153,7 @@ ieee80211_node_latevattach(struct ieee80211vap *vap) "WARNING: max aid too small, changed to %d\n", vap->iv_max_aid); } - MALLOC(vap->iv_aid_bitmap, uint32_t *, + vap->iv_aid_bitmap = (uint32_t *) malloc( howmany(vap->iv_max_aid, 32) * sizeof(uint32_t), M_80211_NODE, M_NOWAIT | M_ZERO); if (vap->iv_aid_bitmap == NULL) { @@ -180,7 +180,7 @@ ieee80211_node_vdetach(struct ieee80211vap *vap) vap->iv_bss = NULL; } if (vap->iv_aid_bitmap != NULL) { - FREE(vap->iv_aid_bitmap, M_80211_NODE); + free(vap->iv_aid_bitmap, M_80211_NODE); vap->iv_aid_bitmap = NULL; } } @@ -732,6 +732,7 @@ ieee80211_sta_join(struct ieee80211vap *vap, struct ieee80211_channel *chan, ni->ni_erp = se->se_erp; IEEE80211_RSSI_LPF(ni->ni_avgrssi, se->se_rssi); ni->ni_noise = se->se_noise; + ni->ni_flags |= IEEE80211_NODE_ASSOCID; if (ieee80211_ies_init(&ni->ni_ies, se->se_ies.data, se->se_ies.len)) { ieee80211_ies_expand(&ni->ni_ies); @@ -788,7 +789,7 @@ node_alloc(struct ieee80211vap *vap, const uint8_t macaddr[IEEE80211_ADDR_LEN]) { struct ieee80211_node *ni; - MALLOC(ni, struct ieee80211_node *, sizeof(struct ieee80211_node), + ni = (struct ieee80211_node *) malloc(sizeof(struct ieee80211_node), M_80211_NODE, M_NOWAIT | M_ZERO); return ni; } @@ -806,11 +807,11 @@ ieee80211_ies_init(struct ieee80211_ies *ies, const uint8_t *data, int len) memset(ies, 0, offsetof(struct ieee80211_ies, data)); if (ies->data != NULL && ies->len != len) { /* data size changed */ - FREE(ies->data, M_80211_NODE_IE); + free(ies->data, M_80211_NODE_IE); ies->data = NULL; } if (ies->data == NULL) { - MALLOC(ies->data, uint8_t *, len, M_80211_NODE_IE, M_NOWAIT); + ies->data = (uint8_t *) malloc(len, M_80211_NODE_IE, M_NOWAIT); if (ies->data == NULL) { ies->len = 0; /* NB: pointers have already been zero'd above */ @@ -829,7 +830,7 @@ void ieee80211_ies_cleanup(struct ieee80211_ies *ies) { if (ies->data != NULL) - FREE(ies->data, M_80211_NODE_IE); + free(ies->data, M_80211_NODE_IE); } /* @@ -898,8 +899,10 @@ node_cleanup(struct ieee80211_node *ni) * has happened. This is probably not needed as the node * should always be removed from the table so not found but * do it just in case. + * Likewise clear the ASSOCID flag as these flags are intended + * to be managed in tandem. */ - ni->ni_flags &= ~IEEE80211_NODE_AREF; + ni->ni_flags &= ~(IEEE80211_NODE_AREF | IEEE80211_NODE_ASSOCID); /* * Drain power save queue and, if needed, clear TIM. @@ -909,7 +912,7 @@ node_cleanup(struct ieee80211_node *ni) ni->ni_associd = 0; if (ni->ni_challenge != NULL) { - FREE(ni->ni_challenge, M_80211_NODE); + free(ni->ni_challenge, M_80211_NODE); ni->ni_challenge = NULL; } /* @@ -945,7 +948,7 @@ node_free(struct ieee80211_node *ni) ieee80211_ies_cleanup(&ni->ni_ies); ieee80211_psq_cleanup(&ni->ni_psq); IEEE80211_NODE_WDSQ_DESTROY(ni); - FREE(ni, M_80211_NODE); + free(ni, M_80211_NODE); } static void @@ -1511,19 +1514,8 @@ ieee80211_find_txnode(struct ieee80211vap *vap, vap->iv_opmode == IEEE80211_M_WDS || IEEE80211_IS_MULTICAST(macaddr)) ni = ieee80211_ref_node(vap->iv_bss); - else { + else ni = ieee80211_find_node_locked(nt, macaddr); - if (vap->iv_opmode == IEEE80211_M_HOSTAP && - (ni != NULL && ni->ni_associd == 0)) { - /* - * Station is not associated; don't permit the - * data frame to be sent by returning NULL. This - * is kinda a kludge but the least intrusive way - * to add this check into all drivers. - */ - ieee80211_unref_node(&ni); /* NB: null's ni */ - } - } IEEE80211_NODE_UNLOCK(nt); if (ni == NULL) { @@ -1651,7 +1643,7 @@ ieee80211_node_delucastkey(struct ieee80211_node *ni) IEEE80211_NODE_LOCK(nt); nikey = NULL; status = 1; /* NB: success */ - if (!IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey)) { + if (ni->ni_ucastkey.wk_keyix != IEEE80211_KEYIX_NONE) { keyix = ni->ni_ucastkey.wk_rxkeyix; status = ieee80211_crypto_delkey(ni->ni_vap, &ni->ni_ucastkey); if (nt->nt_keyixmap != NULL && keyix < nt->nt_keyixmax) { @@ -1799,7 +1791,7 @@ ieee80211_node_table_init(struct ieee80211com *ic, nt->nt_inact_init = inact; nt->nt_keyixmax = keyixmax; if (nt->nt_keyixmax > 0) { - MALLOC(nt->nt_keyixmap, struct ieee80211_node **, + nt->nt_keyixmap = (struct ieee80211_node **) malloc( keyixmax * sizeof(struct ieee80211_node *), M_80211_NODE, M_NOWAIT | M_ZERO); if (nt->nt_keyixmap == NULL) @@ -1860,7 +1852,7 @@ ieee80211_node_table_cleanup(struct ieee80211_node_table *nt) printf("%s: %s[%u] still active\n", __func__, nt->nt_name, i); #endif - FREE(nt->nt_keyixmap, M_80211_NODE); + free(nt->nt_keyixmap, M_80211_NODE); nt->nt_keyixmap = NULL; } IEEE80211_NODE_ITERATE_LOCK_DESTROY(nt); diff --git a/sys/net80211/ieee80211_node.h b/sys/net80211/ieee80211_node.h index b8a30ad..bd304d5 100644 --- a/sys/net80211/ieee80211_node.h +++ b/sys/net80211/ieee80211_node.h @@ -117,6 +117,7 @@ struct ieee80211_node { #define IEEE80211_NODE_RIFS 0x004000 /* RIFS enabled */ #define IEEE80211_NODE_SGI20 0x008000 /* Short GI in HT20 enabled */ #define IEEE80211_NODE_SGI40 0x010000 /* Short GI in HT40 enabled */ +#define IEEE80211_NODE_ASSOCID 0x020000 /* xmit requires associd */ uint16_t ni_associd; /* association ID */ uint16_t ni_vlan; /* vlan tag */ uint16_t ni_txpower; /* current transmit power */ diff --git a/sys/net80211/ieee80211_output.c b/sys/net80211/ieee80211_output.c index e5c6889..050d892 100644 --- a/sys/net80211/ieee80211_output.c +++ b/sys/net80211/ieee80211_output.c @@ -203,10 +203,8 @@ ieee80211_start(struct ifnet *ifp) continue; } /* XXX AUTH'd */ - /* XXX mark vap to identify if associd is required */ if (ni->ni_associd == 0 && - (vap->iv_opmode == IEEE80211_M_STA || - vap->iv_opmode == IEEE80211_M_HOSTAP || IS_DWDS(vap))) { + (ni->ni_flags & IEEE80211_NODE_ASSOCID)) { IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT, eh->ether_dhost, NULL, "sta not associated (type 0x%04x)", diff --git a/sys/net80211/ieee80211_power.c b/sys/net80211/ieee80211_power.c index b2ace4a..aad82ba 100644 --- a/sys/net80211/ieee80211_power.c +++ b/sys/net80211/ieee80211_power.c @@ -80,7 +80,7 @@ ieee80211_power_latevattach(struct ieee80211vap *vap) */ if (vap->iv_opmode == IEEE80211_M_HOSTAP) { vap->iv_tim_len = howmany(vap->iv_max_aid,8) * sizeof(uint8_t); - MALLOC(vap->iv_tim_bitmap, uint8_t *, vap->iv_tim_len, + vap->iv_tim_bitmap = (uint8_t *) malloc(vap->iv_tim_len, M_80211_POWER, M_NOWAIT | M_ZERO); if (vap->iv_tim_bitmap == NULL) { printf("%s: no memory for TIM bitmap!\n", __func__); @@ -94,7 +94,7 @@ void ieee80211_power_vdetach(struct ieee80211vap *vap) { if (vap->iv_tim_bitmap != NULL) { - FREE(vap->iv_tim_bitmap, M_80211_POWER); + free(vap->iv_tim_bitmap, M_80211_POWER); vap->iv_tim_bitmap = NULL; } } diff --git a/sys/net80211/ieee80211_proto.c b/sys/net80211/ieee80211_proto.c index 452bd3f..31b68fd 100644 --- a/sys/net80211/ieee80211_proto.c +++ b/sys/net80211/ieee80211_proto.c @@ -214,7 +214,7 @@ ieee80211_proto_vdetach(struct ieee80211vap *vap) { #define FREEAPPIE(ie) do { \ if (ie != NULL) \ - FREE(ie, M_80211_NODE_IE); \ + free(ie, M_80211_NODE_IE); \ } while (0) /* * Detach operating mode module. diff --git a/sys/net80211/ieee80211_regdomain.c b/sys/net80211/ieee80211_regdomain.c index 0e41355..724d00b 100644 --- a/sys/net80211/ieee80211_regdomain.c +++ b/sys/net80211/ieee80211_regdomain.c @@ -338,7 +338,7 @@ ieee80211_setregdomain(struct ieee80211vap *vap, reg->rd.isocc[0], reg->rd.isocc[1]); return EINVAL; } - if (reg->chaninfo.ic_nchans >= IEEE80211_CHAN_MAX) { + if (reg->chaninfo.ic_nchans > IEEE80211_CHAN_MAX) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_IOCTL, "%s: too many channels %u, max %u\n", __func__, reg->chaninfo.ic_nchans, IEEE80211_CHAN_MAX); diff --git a/sys/net80211/ieee80211_scan.c b/sys/net80211/ieee80211_scan.c index dabb404..f56617a0 100644 --- a/sys/net80211/ieee80211_scan.c +++ b/sys/net80211/ieee80211_scan.c @@ -96,7 +96,7 @@ ieee80211_scan_attach(struct ieee80211com *ic) { struct scan_state *ss; - MALLOC(ss, struct scan_state *, sizeof(struct scan_state), + ss = (struct scan_state *) malloc(sizeof(struct scan_state), M_80211_SCAN, M_NOWAIT | M_ZERO); if (ss == NULL) { ic->ic_scan = NULL; @@ -122,7 +122,7 @@ ieee80211_scan_detach(struct ieee80211com *ic) } ic->ic_flags &= ~IEEE80211_F_SCAN; ic->ic_scan = NULL; - FREE(SCAN_PRIVATE(ss), M_80211_SCAN); + free(SCAN_PRIVATE(ss), M_80211_SCAN); } } diff --git a/sys/net80211/ieee80211_scan_sta.c b/sys/net80211/ieee80211_scan_sta.c index e3a4bda..15e4ff6 100644 --- a/sys/net80211/ieee80211_scan_sta.c +++ b/sys/net80211/ieee80211_scan_sta.c @@ -87,6 +87,9 @@ struct sta_entry { #define STA_HASH(addr) \ (((const uint8_t *)(addr))[IEEE80211_ADDR_LEN - 1] % STA_HASHSIZE) +#define MAX_IEEE_CHAN 256 /* max acceptable IEEE chan # */ +CTASSERT(MAX_IEEE_CHAN >= 256); + struct sta_table { struct mtx st_lock; /* on scan table */ TAILQ_HEAD(, sta_entry) st_entry; /* all entries */ @@ -96,7 +99,7 @@ struct sta_table { u_int st_scangen; /* scan generation # */ int st_newscan; /* ap-related state */ - int st_maxrssi[IEEE80211_CHAN_MAX]; + int st_maxrssi[MAX_IEEE_CHAN]; }; static void sta_flush_table(struct sta_table *); @@ -137,7 +140,7 @@ sta_attach(struct ieee80211_scan_state *ss) { struct sta_table *st; - MALLOC(st, struct sta_table *, sizeof(struct sta_table), + st = (struct sta_table *) malloc(sizeof(struct sta_table), M_80211_SCAN, M_NOWAIT | M_ZERO); if (st == NULL) return 0; @@ -161,7 +164,7 @@ sta_detach(struct ieee80211_scan_state *ss) sta_flush_table(st); mtx_destroy(&st->st_lock); mtx_destroy(&st->st_scanlock); - FREE(st, M_80211_SCAN); + free(st, M_80211_SCAN); KASSERT(nrefs > 0, ("imbalanced attach/detach")); nrefs--; /* NB: we assume caller locking */ } @@ -195,7 +198,7 @@ sta_flush_table(struct sta_table *st) TAILQ_REMOVE(&st->st_entry, se, se_list); LIST_REMOVE(se, se_hash); ieee80211_ies_cleanup(&se->base.se_ies); - FREE(se, M_80211_SCAN); + free(se, M_80211_SCAN); } memset(st->st_maxrssi, 0, sizeof(st->st_maxrssi)); } @@ -228,7 +231,7 @@ sta_add(struct ieee80211_scan_state *ss, LIST_FOREACH(se, &st->st_hash[hash], se_hash) if (IEEE80211_ADDR_EQ(se->base.se_macaddr, macaddr)) goto found; - MALLOC(se, struct sta_entry *, sizeof(struct sta_entry), + se = (struct sta_entry *) malloc(sizeof(struct sta_entry), M_80211_SCAN, M_NOWAIT | M_ZERO); if (se == NULL) { mtx_unlock(&st->st_lock); @@ -343,6 +346,7 @@ found: se->se_seen = 1; se->se_notseen = 0; + KASSERT(sizeof(sp->bchan) == 1, ("bchan size")); if (rssi > st->st_maxrssi[sp->bchan]) st->st_maxrssi[sp->bchan] = rssi; @@ -1505,7 +1509,7 @@ adhoc_age(struct ieee80211_scan_state *ss) TAILQ_REMOVE(&st->st_entry, se, se_list); LIST_REMOVE(se, se_hash); ieee80211_ies_cleanup(&se->base.se_ies); - FREE(se, M_80211_SCAN); + free(se, M_80211_SCAN); } } mtx_unlock(&st->st_lock); @@ -1604,6 +1608,7 @@ ap_pick_channel(struct ieee80211_scan_state *ss, int flags) /* check channel attributes for band compatibility */ if (flags != 0 && (chan->ic_flags & flags) != flags) continue; + KASSERT(sizeof(chan->ic_ieee) == 1, ("ic_chan size")); /* XXX channel have interference */ if (st->st_maxrssi[chan->ic_ieee] == 0) { /* XXX use other considerations */ diff --git a/sys/net80211/ieee80211_sta.c b/sys/net80211/ieee80211_sta.c index 35fcead..54733c9 100644 --- a/sys/net80211/ieee80211_sta.c +++ b/sys/net80211/ieee80211_sta.c @@ -1018,7 +1018,7 @@ sta_auth_shared(struct ieee80211_node *ni, struct ieee80211_frame *wh, switch (seq) { case IEEE80211_AUTH_SHARED_PASS: if (ni->ni_challenge != NULL) { - FREE(ni->ni_challenge, M_80211_NODE); + free(ni->ni_challenge, M_80211_NODE); ni->ni_challenge = NULL; } if (status != 0) { diff --git a/sys/net80211/ieee80211_var.h b/sys/net80211/ieee80211_var.h index 3e90201..ccd95d0 100644 --- a/sys/net80211/ieee80211_var.h +++ b/sys/net80211/ieee80211_var.h @@ -156,7 +156,7 @@ struct ieee80211com { * (e.g. for dynamic turbo) */ int ic_nchans; /* # entries in ic_channels */ - struct ieee80211_channel ic_channels[IEEE80211_CHAN_MAX+1]; + struct ieee80211_channel ic_channels[IEEE80211_CHAN_MAX]; uint8_t ic_chan_avail[IEEE80211_CHAN_BYTES]; uint8_t ic_chan_active[IEEE80211_CHAN_BYTES]; uint8_t ic_chan_scan[IEEE80211_CHAN_BYTES]; diff --git a/sys/netgraph/netflow/netflow.c b/sys/netgraph/netflow/netflow.c index 5443629..411730a 100644 --- a/sys/netgraph/netflow/netflow.c +++ b/sys/netgraph/netflow/netflow.c @@ -270,7 +270,7 @@ hash_insert(priv_p priv, struct flow_hash_entry *hsh, struct flow_rec *r, sin.sin_family = AF_INET; sin.sin_addr = fle->f.r.r_dst; /* XXX MRT 0 as a default.. need the m here to get fib */ - rt = rtalloc1_fib((struct sockaddr *)&sin, 0, RTF_CLONING, 0); + rt = rtalloc1_fib((struct sockaddr *)&sin, 0, 0, 0); if (rt != NULL) { fle->f.fle_o_ifx = rt->rt_ifp->if_index; @@ -295,7 +295,7 @@ hash_insert(priv_p priv, struct flow_hash_entry *hsh, struct flow_rec *r, sin.sin_family = AF_INET; sin.sin_addr = fle->f.r.r_src; /* XXX MRT 0 as a default revisit. need the mbuf for fib*/ - rt = rtalloc1_fib((struct sockaddr *)&sin, 0, RTF_CLONING, 0); + rt = rtalloc1_fib((struct sockaddr *)&sin, 0, 0, 0); if (rt != NULL) { if (rt_mask(rt)) fle->f.src_mask = bitcount32(((struct sockaddr_in *) diff --git a/sys/netgraph/netgraph.h b/sys/netgraph/netgraph.h index 4072f76..859af71 100644 --- a/sys/netgraph/netgraph.h +++ b/sys/netgraph/netgraph.h @@ -1130,7 +1130,6 @@ item_p ng_package_msg(struct ng_mesg *msg, int flags); item_p ng_package_msg_self(node_p here, hook_p hook, struct ng_mesg *msg); void ng_replace_retaddr(node_p here, item_p item, ng_ID_t retaddr); int ng_rmhook_self(hook_p hook); /* if a node wants to kill a hook */ -int ng_rmnode_flags(node_p here, int flags); int ng_rmnode_self(node_p here); /* if a node wants to suicide */ int ng_rmtype(struct ng_type *tp); int ng_snd_item(item_p item, int queue); diff --git a/sys/netgraph/ng_base.c b/sys/netgraph/ng_base.c index 0406da1..0e9f96c 100644 --- a/sys/netgraph/ng_base.c +++ b/sys/netgraph/ng_base.c @@ -62,6 +62,9 @@ #include <sys/refcount.h> #include <sys/proc.h> #include <sys/vimage.h> +#include <sys/unistd.h> +#include <sys/kthread.h> +#include <sys/smp.h> #include <machine/cpu.h> #include <net/netisr.h> @@ -211,7 +214,7 @@ static int ng_generic_msg(node_p here, item_p item, hook_p lasthook); static ng_ID_t ng_decodeidname(const char *name); static int ngb_mod_event(module_t mod, int event, void *data); static void ng_worklist_add(node_p node); -static void ngintr(void); +static void ngthread(void *); static int ng_apply_item(node_p node, item_p item, int rw); static void ng_flush_input_queue(node_p node); static node_p ng_ID2noderef(ng_ID_t ID); @@ -259,6 +262,10 @@ MALLOC_DEFINE(M_NETGRAPH_MSG, "netgraph_msg", "netgraph name storage"); mtx_lock(&ng_worklist_mtx) #define NG_WORKLIST_UNLOCK() \ mtx_unlock(&ng_worklist_mtx) +#define NG_WORKLIST_SLEEP() \ + mtx_sleep(&ng_worklist, &ng_worklist_mtx, PI_NET, "sleep", 0) +#define NG_WORKLIST_WAKEUP() \ + wakeup_one(&ng_worklist) #ifdef NETGRAPH_DEBUG /*----------------------------------------------*/ /* @@ -1521,7 +1528,7 @@ ng_mkpeer(node_p node, const char *name, const char *name2, char *type) /* Shut this node down as soon as everyone is clear of it */ /* Should add arg "immediately" to jump the queue */ int -ng_rmnode_flags(node_p node, int flags) +ng_rmnode_self(node_p node) { int error; @@ -1531,16 +1538,10 @@ ng_rmnode_flags(node_p node, int flags) if (node->nd_flags & NGF_CLOSING) return (0); - error = ng_send_fn1(node, NULL, &ng_rmnode, NULL, 0, flags); + error = ng_send_fn(node, NULL, &ng_rmnode, NULL, 0); return (error); } -int -ng_rmnode_self(node_p node) -{ - return (ng_rmnode_flags(node, NG_NOFLAGS)); -} - static void ng_rmhook_part2(node_p node, hook_p hook, void *arg1, int arg2) { @@ -2874,9 +2875,13 @@ out: uma_zone_t ng_qzone; uma_zone_t ng_qdzone; +static int numthreads = 0; /* number of queue threads */ static int maxalloc = 4096;/* limit the damage of a leak */ static int maxdata = 512; /* limit the damage of a DoS */ +TUNABLE_INT("net.graph.threads", &numthreads); +SYSCTL_INT(_net_graph, OID_AUTO, threads, CTLFLAG_RDTUN, &numthreads, + 0, "Number of queue processing threads"); TUNABLE_INT("net.graph.maxalloc", &maxalloc); SYSCTL_INT(_net_graph, OID_AUTO, maxalloc, CTLFLAG_RDTUN, &maxalloc, 0, "Maximum number of non-data queue items to allocate"); @@ -3070,7 +3075,9 @@ ng_mod_event(module_t mod, int event, void *data) static int ngb_mod_event(module_t mod, int event, void *data) { - int error = 0; + struct proc *p; + struct thread *td; + int i, error = 0; switch (event) { case MOD_LOAD: @@ -3097,7 +3104,18 @@ ngb_mod_event(module_t mod, int event, void *data) ng_qdzone = uma_zcreate("NetGraph data items", sizeof(struct ng_item), NULL, NULL, NULL, NULL, UMA_ALIGN_CACHE, 0); uma_zone_set_max(ng_qdzone, maxdata); - netisr_register(NETISR_NETGRAPH, (netisr_t *)ngintr, NULL, 0); + /* Autoconfigure number of threads. */ + if (numthreads <= 0) + numthreads = mp_ncpus; + /* Create threads. */ + p = NULL; /* start with no process */ + for (i = 0; i < numthreads; i++) { + if (kproc_kthread_add(ngthread, NULL, &p, &td, + RFHIGHPID, 0, "ng_queue", "ng_queue%d", i)) { + numthreads = i; + break; + } + } break; case MOD_UNLOAD: /* You can't unload it because an interface may be using it. */ @@ -3252,25 +3270,20 @@ SYSCTL_PROC(_debug, OID_AUTO, ng_dump_items, CTLTYPE_INT | CTLFLAG_RW, /*********************************************************************** * Worklist routines **********************************************************************/ -/* NETISR thread enters here */ /* * Pick a node off the list of nodes with work, - * try get an item to process off it. - * If there are no more, remove the node from the list. + * try get an item to process off it. Remove the node from the list. */ static void -ngintr(void) +ngthread(void *arg) { for (;;) { node_p node; /* Get node from the worklist. */ NG_WORKLIST_LOCK(); - node = STAILQ_FIRST(&ng_worklist); - if (!node) { - NG_WORKLIST_UNLOCK(); - break; - } + while ((node = STAILQ_FIRST(&ng_worklist)) == NULL) + NG_WORKLIST_SLEEP(); STAILQ_REMOVE_HEAD(&ng_worklist, nd_input_queue.q_work); NG_WORKLIST_UNLOCK(); CTR3(KTR_NET, "%20s: node [%x] (%p) taken off worklist", @@ -3326,9 +3339,9 @@ ng_worklist_add(node_p node) NG_WORKLIST_LOCK(); STAILQ_INSERT_TAIL(&ng_worklist, node, nd_input_queue.q_work); NG_WORKLIST_UNLOCK(); - schednetisr(NETISR_NETGRAPH); CTR3(KTR_NET, "%20s: node [%x] (%p) put on worklist", __func__, node->nd_ID, node); + NG_WORKLIST_WAKEUP(); } else { CTR3(KTR_NET, "%20s: node [%x] (%p) already on worklist", __func__, node->nd_ID, node); diff --git a/sys/netgraph/ng_mppc.c b/sys/netgraph/ng_mppc.c index 472968f..5a6c302 100644 --- a/sys/netgraph/ng_mppc.c +++ b/sys/netgraph/ng_mppc.c @@ -824,21 +824,24 @@ ng_mppc_reset_req(node_p node) static void ng_mppc_getkey(const u_char *h, u_char *h2, int len) { - static const u_char pad1[10] = - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; - static const u_char pad2[10] = - { 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, }; + static const u_char pad1[40] = + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + static const u_char pad2[40] = + { 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, + 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, + 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, + 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2 }; u_char hash[20]; SHA1_CTX c; - int k; SHA1Init(&c); SHA1Update(&c, h, len); - for (k = 0; k < 4; k++) - SHA1Update(&c, pad1, sizeof(pad1)); + SHA1Update(&c, pad1, sizeof(pad1)); SHA1Update(&c, h2, len); - for (k = 0; k < 4; k++) - SHA1Update(&c, pad2, sizeof(pad2)); + SHA1Update(&c, pad2, sizeof(pad2)); SHA1Final(hash, &c); bcopy(hash, h2, len); } diff --git a/sys/netgraph/ng_tty.c b/sys/netgraph/ng_tty.c index c504b84..2fa33fc 100644 --- a/sys/netgraph/ng_tty.c +++ b/sys/netgraph/ng_tty.c @@ -114,7 +114,6 @@ static th_getc_poll_t ngt_getc_poll; static th_rint_t ngt_rint; static th_rint_bypass_t ngt_rint_bypass; static th_rint_poll_t ngt_rint_poll; -static th_close_t ngt_close; static struct ttyhook ngt_hook = { .th_getc_inject = ngt_getc_inject, @@ -122,7 +121,6 @@ static struct ttyhook ngt_hook = { .th_rint = ngt_rint, .th_rint_bypass = ngt_rint_bypass, .th_rint_poll = ngt_rint_poll, - .th_close = ngt_close, }; /* Netgraph node type descriptor */ @@ -252,7 +250,6 @@ static int ngt_rcvmsg(node_p node, item_p item, hook_p lasthook) { struct proc *p; - struct thread *td; const sc_p sc = NG_NODE_PRIVATE(node); struct ng_mesg *msg, *resp = NULL; int error = 0; @@ -266,12 +263,13 @@ ngt_rcvmsg(node_p node, item_p item, hook_p lasthook) return (EBUSY); p = pfind(((int *)msg->data)[0]); - if (p == NULL) + if (p == NULL || (p->p_flag & P_WEXIT)) return (ESRCH); - td = FIRST_THREAD_IN_PROC(p); - error = ttyhook_register(&sc->tp, td, ((int *)msg->data)[1], - &ngt_hook, sc); + _PHOLD(p); PROC_UNLOCK(p); + error = ttyhook_register(&sc->tp, p, ((int *)msg->data)[1], + &ngt_hook, sc); + PRELE(p); if (error != 0) return (error); break; @@ -515,12 +513,3 @@ ngt_rint_poll(struct tty *tp) return (1); } -static void -ngt_close(struct tty *tp) -{ - sc_p sc = ttyhook_softc(tp); - - /* Must be queued to drop the tty lock */ - ng_rmnode_flags(sc->node, NG_QUEUE); -} - diff --git a/sys/netinet/icmp6.h b/sys/netinet/icmp6.h index 91b1658..fcdc9ce 100644 --- a/sys/netinet/icmp6.h +++ b/sys/netinet/icmp6.h @@ -707,8 +707,10 @@ do { \ } \ } while (/*CONSTCOND*/ 0) +#ifdef VIMAGE_GLOBALS extern int icmp6_rediraccept; /* accept/process redirects */ extern int icmp6_redirtimeout; /* cache time for redirect routes */ +#endif #define ICMP6_NODEINFO_FQDNOK 0x1 #define ICMP6_NODEINFO_NODEADDROK 0x2 diff --git a/sys/netinet/icmp_var.h b/sys/netinet/icmp_var.h index dda84f2..cd9ee00 100644 --- a/sys/netinet/icmp_var.h +++ b/sys/netinet/icmp_var.h @@ -74,7 +74,9 @@ struct icmpstat { #ifdef _KERNEL SYSCTL_DECL(_net_inet_icmp); +#ifdef VIMAGE_GLOBALS extern struct icmpstat icmpstat; /* icmp statistics */ +#endif extern int badport_bandlim(int); #define BANDLIM_UNLIMITED -1 #define BANDLIM_ICMP_UNREACH 0 diff --git a/sys/netinet/if_atm.c b/sys/netinet/if_atm.c index 065f0c4..d534a18 100644 --- a/sys/netinet/if_atm.c +++ b/sys/netinet/if_atm.c @@ -127,10 +127,6 @@ atm_rtrequest(int req, struct rtentry *rt, struct rt_addrinfo *info) break; } - if ((rt->rt_flags & RTF_CLONING) != 0) { - printf("atm_rtrequest: cloning route detected?\n"); - break; - } if (gate->sa_family != AF_LINK || gate->sa_len < sizeof(null_sdl)) { log(LOG_DEBUG, "atm_rtrequest: bad gateway value"); @@ -332,8 +328,6 @@ atmresolve(struct rtentry *rt, struct mbuf *m, struct sockaddr *dst, goto bad; /* failed */ RT_REMREF(rt); /* don't keep LL references */ if ((rt->rt_flags & RTF_GATEWAY) != 0 || - (rt->rt_flags & RTF_LLINFO) == 0 || - /* XXX: are we using LLINFO? */ rt->rt_gateway->sa_family != AF_LINK) { RT_UNLOCK(rt); goto bad; diff --git a/sys/netinet/if_ether.c b/sys/netinet/if_ether.c index da7946d..1b03fb3 100644 --- a/sys/netinet/if_ether.c +++ b/sys/netinet/if_ether.c @@ -65,6 +65,7 @@ __FBSDID("$FreeBSD$"); #include <netinet/in.h> #include <netinet/in_var.h> +#include <net/if_llatbl.h> #include <netinet/if_ether.h> #include <netinet/vinet.h> @@ -79,6 +80,7 @@ __FBSDID("$FreeBSD$"); #define SIN(s) ((struct sockaddr_in *)s) #define SDL(s) ((struct sockaddr_dl *)s) +#define LLTABLE(ifp) ((struct lltable *)(ifp)->if_afdata[AF_INET]) SYSCTL_DECL(_net_link_ether); SYSCTL_NODE(_net_link_ether, PF_INET, inet, CTLFLAG_RW, 0, ""); @@ -87,23 +89,13 @@ SYSCTL_NODE(_net_link_ether, PF_INET, inet, CTLFLAG_RW, 0, ""); #ifdef VIMAGE_GLOBALS static int arpt_keep; /* once resolved, good for 20 more minutes */ static int arp_maxtries; -static int useloopback; /* use loopback interface for local traffic */ +int useloopback; /* use loopback interface for local traffic */ static int arp_proxyall; #endif SYSCTL_V_INT(V_NET, vnet_inet, _net_link_ether_inet, OID_AUTO, max_age, CTLFLAG_RW, arpt_keep, 0, "ARP entry lifetime in seconds"); -#define rt_expire rt_rmx.rmx_expire - -struct llinfo_arp { - struct callout la_timer; - struct rtentry *la_rt; - struct mbuf *la_hold; /* last packet until resolved/timeout */ - u_short la_preempt; /* countdown for pre-expiry arps */ - u_short la_asked; /* # requests sent */ -}; - static struct ifqueue arpintrq; SYSCTL_V_INT(V_NET, vnet_inet, _net_link_ether_inet, OID_AUTO, maxtries, @@ -117,196 +109,65 @@ SYSCTL_V_INT(V_NET, vnet_inet, _net_link_ether_inet, OID_AUTO, proxyall, "Enable proxy ARP for all suitable requests"); static void arp_init(void); -static void arp_rtrequest(int, struct rtentry *, struct rt_addrinfo *); -static void arprequest(struct ifnet *, +void arprequest(struct ifnet *, struct in_addr *, struct in_addr *, u_char *); static void arpintr(struct mbuf *); static void arptimer(void *); -static struct rtentry - *arplookup(u_long, int, int, int); #ifdef INET static void in_arpinput(struct mbuf *); #endif +#ifdef AF_INET +void arp_ifscrub(struct ifnet *ifp, uint32_t addr); + /* - * Timeout routine. + * called by in_ifscrub to remove entry from the table when + * the interface goes away */ -static void -arptimer(void *arg) +void +arp_ifscrub(struct ifnet *ifp, uint32_t addr) { - struct rtentry *rt = (struct rtentry *)arg; - - RT_LOCK_ASSERT(rt); - /* - * The lock is needed to close a theoretical race - * between spontaneous expiry and intentional removal. - * We still got an extra reference on rtentry, so can - * safely pass pointers to its contents. - */ - RT_UNLOCK(rt); - - in_rtrequest(RTM_DELETE, rt_key(rt), NULL, rt_mask(rt), 0, NULL, - rt->rt_fibnum); + struct sockaddr_in addr4; + + bzero((void *)&addr4, sizeof(addr4)); + addr4.sin_len = sizeof(addr4); + addr4.sin_family = AF_INET; + addr4.sin_addr.s_addr = addr; + IF_AFDATA_LOCK(ifp); + lla_lookup(LLTABLE(ifp), (LLE_DELETE | LLE_IFADDR), + (struct sockaddr *)&addr4); + IF_AFDATA_UNLOCK(ifp); } +#endif /* - * Parallel to llc_rtrequest. + * Timeout routine. Age arp_tab entries periodically. */ static void -arp_rtrequest(int req, struct rtentry *rt, struct rt_addrinfo *info) +arptimer(void *arg) { - INIT_VNET_NET(curvnet); - INIT_VNET_INET(curvnet); - struct sockaddr *gate; - struct llinfo_arp *la; - static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; - struct in_ifaddr *ia; - struct ifaddr *ifa; + struct ifnet *ifp; + struct llentry *lle = (struct llentry *)arg; - RT_LOCK_ASSERT(rt); - - if (rt->rt_flags & RTF_GATEWAY) + if (lle == NULL) { + panic("%s: NULL entry!\n", __func__); return; - gate = rt->rt_gateway; - la = (struct llinfo_arp *)rt->rt_llinfo; - switch (req) { - - case RTM_ADD: - /* - * XXX: If this is a manually added route to interface - * such as older version of routed or gated might provide, - * restore cloning bit. - */ - if ((rt->rt_flags & RTF_HOST) == 0 && - rt_mask(rt) != NULL && - SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff) - rt->rt_flags |= RTF_CLONING; - if (rt->rt_flags & RTF_CLONING) { - /* - * Case 1: This route should come from a route to iface. - */ - rt_setgate(rt, rt_key(rt), - (struct sockaddr *)&null_sdl); - gate = rt->rt_gateway; - SDL(gate)->sdl_type = rt->rt_ifp->if_type; - SDL(gate)->sdl_index = rt->rt_ifp->if_index; - rt->rt_expire = time_uptime; - break; - } - /* Announce a new entry if requested. */ - if (rt->rt_flags & RTF_ANNOUNCE) - arprequest(rt->rt_ifp, - &SIN(rt_key(rt))->sin_addr, - &SIN(rt_key(rt))->sin_addr, - (u_char *)LLADDR(SDL(gate))); - /*FALLTHROUGH*/ - case RTM_RESOLVE: - if (gate->sa_family != AF_LINK || - gate->sa_len < sizeof(null_sdl)) { - log(LOG_DEBUG, "%s: bad gateway %s%s\n", __func__, - inet_ntoa(SIN(rt_key(rt))->sin_addr), - (gate->sa_family != AF_LINK) ? - " (!AF_LINK)": ""); - break; - } - SDL(gate)->sdl_type = rt->rt_ifp->if_type; - SDL(gate)->sdl_index = rt->rt_ifp->if_index; - if (la != 0) - break; /* This happens on a route change */ - /* - * Case 2: This route may come from cloning, or a manual route - * add with a LL address. - */ - R_Zalloc(la, struct llinfo_arp *, sizeof(*la)); - rt->rt_llinfo = (caddr_t)la; - if (la == 0) { - log(LOG_DEBUG, "%s: malloc failed\n", __func__); - break; - } - /* - * We are storing a route entry outside of radix tree. So, - * it can be found and accessed by other means than radix - * lookup. The routing code assumes that any rtentry detached - * from radix can be destroyed safely. To prevent this, we - * add an additional reference. - */ - RT_ADDREF(rt); - la->la_rt = rt; - rt->rt_flags |= RTF_LLINFO; - callout_init_mtx(&la->la_timer, &rt->rt_mtx, - CALLOUT_RETURNUNLOCKED); - -#ifdef INET + } + ifp = lle->lle_tbl->llt_ifp; + IF_AFDATA_LOCK(ifp); + LLE_WLOCK(lle); + if ((lle->la_flags & LLE_DELETED) || + (time_second >= lle->la_expire)) { + if (!callout_pending(&lle->la_timer) && + callout_active(&lle->la_timer)) + (void) llentry_free(lle); + } else { /* - * This keeps the multicast addresses from showing up - * in `arp -a' listings as unresolved. It's not actually - * functional. Then the same for broadcast. + * Still valid, just drop our reference */ - if (IN_MULTICAST(ntohl(SIN(rt_key(rt))->sin_addr.s_addr)) && - rt->rt_ifp->if_type != IFT_ARCNET) { - ETHER_MAP_IP_MULTICAST(&SIN(rt_key(rt))->sin_addr, - LLADDR(SDL(gate))); - SDL(gate)->sdl_alen = 6; - rt->rt_expire = 0; - } - if (in_broadcast(SIN(rt_key(rt))->sin_addr, rt->rt_ifp)) { - memcpy(LLADDR(SDL(gate)), rt->rt_ifp->if_broadcastaddr, - rt->rt_ifp->if_addrlen); - SDL(gate)->sdl_alen = rt->rt_ifp->if_addrlen; - rt->rt_expire = 0; - } -#endif - - TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { - if (ia->ia_ifp == rt->rt_ifp && - SIN(rt_key(rt))->sin_addr.s_addr == - (IA_SIN(ia))->sin_addr.s_addr) - break; - } - if (ia) { - /* - * This test used to be - * if (loif.if_flags & IFF_UP) - * It allowed local traffic to be forced - * through the hardware by configuring the loopback down. - * However, it causes problems during network configuration - * for boards that can't receive packets they send. - * It is now necessary to clear "useloopback" and remove - * the route to force traffic out to the hardware. - */ - rt->rt_expire = 0; - bcopy(IF_LLADDR(rt->rt_ifp), LLADDR(SDL(gate)), - SDL(gate)->sdl_alen = rt->rt_ifp->if_addrlen); - if (V_useloopback) { - rt->rt_ifp = V_loif; - rt->rt_rmx.rmx_mtu = V_loif->if_mtu; - } - - /* - * make sure to set rt->rt_ifa to the interface - * address we are using, otherwise we will have trouble - * with source address selection. - */ - ifa = &ia->ia_ifa; - if (ifa != rt->rt_ifa) { - IFAFREE(rt->rt_ifa); - IFAREF(ifa); - rt->rt_ifa = ifa; - } - } - break; - - case RTM_DELETE: - if (la == NULL) /* XXX: at least CARP does this. */ - break; - callout_stop(&la->la_timer); - rt->rt_llinfo = NULL; - rt->rt_flags &= ~RTF_LLINFO; - RT_REMREF(rt); - if (la->la_hold) - m_freem(la->la_hold); - Free((caddr_t)la); + LLE_FREE_LOCKED(lle); } + IF_AFDATA_UNLOCK(ifp); } /* @@ -315,14 +176,37 @@ arp_rtrequest(int req, struct rtentry *rt, struct rt_addrinfo *info) * - arp header target ip address * - arp header source ethernet address */ -static void -arprequest(struct ifnet *ifp, struct in_addr *sip, struct in_addr *tip, +void +arprequest(struct ifnet *ifp, struct in_addr *sip, struct in_addr *tip, u_char *enaddr) { struct mbuf *m; struct arphdr *ah; struct sockaddr sa; + if (sip == NULL) { + /* XXX don't believe this can happen (or explain why) */ + /* + * The caller did not supply a source address, try to find + * a compatible one among those assigned to this interface. + */ + struct ifaddr *ifa; + + TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + if (!ifa->ifa_addr || + ifa->ifa_addr->sa_family != AF_INET) + continue; + sip = &SIN(ifa->ifa_addr)->sin_addr; + if (0 == ((sip->s_addr ^ tip->s_addr) & + SIN(ifa->ifa_netmask)->sin_addr.s_addr) ) + break; /* found it. */ + } + if (sip == NULL) { + printf("%s: cannot find matching address\n", __func__); + return; + } + } + if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL) return; m->m_len = sizeof(*ah) + 2*sizeof(struct in_addr) + @@ -345,8 +229,6 @@ arprequest(struct ifnet *ifp, struct in_addr *sip, struct in_addr *tip, sa.sa_len = 2; m->m_flags |= M_BCAST; (*ifp->if_output)(ifp, m, &sa, (struct rtentry *)0); - - return; } /* @@ -365,16 +247,15 @@ arprequest(struct ifnet *ifp, struct in_addr *sip, struct in_addr *tip, */ int arpresolve(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m, - struct sockaddr *dst, u_char *desten) + struct sockaddr *dst, u_char *desten, struct llentry **lle) { INIT_VNET_INET(ifp->if_vnet); - struct llinfo_arp *la = NULL; - struct rtentry *rt = NULL; - struct sockaddr_dl *sdl; - int error; - int fibnum = -1; + struct llentry *la = 0; + u_int flags = 0; + int error, renew; - if (m) { + *lle = NULL; + if (m != NULL) { if (m->m_flags & M_BCAST) { /* broadcast */ (void)memcpy(desten, @@ -386,110 +267,79 @@ arpresolve(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m, ETHER_MAP_IP_MULTICAST(&SIN(dst)->sin_addr, desten); return (0); } - fibnum = M_GETFIB(m); } - - if (rt0 != NULL) { - /* Look for a cached arp (ll) entry. */ - if (m == NULL) - fibnum = rt0->rt_fibnum; - error = rt_check(&rt, &rt0, dst); - if (error) { - m_freem(m); - return error; - } - la = (struct llinfo_arp *)rt->rt_llinfo; - if (la == NULL) - RT_UNLOCK(rt); - } - - /* - * If we had no mbuf and no route, then hope the caller - * has a fib in mind because we are running out of ideas. - * I think this should not happen in current code. - * (kmacy would know). + /* XXXXX */ - if (fibnum == -1) - fibnum = curthread->td_proc->p_fibnum; /* last gasp */ - +retry: + IF_AFDATA_RLOCK(ifp); + la = lla_lookup(LLTABLE(ifp), flags, dst); + IF_AFDATA_RUNLOCK(ifp); + if ((la == NULL) && ((flags & LLE_EXCLUSIVE) == 0) + && ((ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) == 0)) { + flags |= (LLE_CREATE | LLE_EXCLUSIVE); + IF_AFDATA_WLOCK(ifp); + la = lla_lookup(LLTABLE(ifp), flags, dst); + IF_AFDATA_WUNLOCK(ifp); + } if (la == NULL) { - /* - * We enter this block if rt0 was NULL, - * or if rt found by rt_check() didn't have llinfo. - * we should get a cloned route, which since it should - * come from the local interface should have a ll entry. - * It may be incomplete but that's ok. - */ - rt = arplookup(SIN(dst)->sin_addr.s_addr, 1, 0, fibnum); - if (rt == NULL) { - log(LOG_DEBUG, - "arpresolve: can't allocate route for %s\n", - inet_ntoa(SIN(dst)->sin_addr)); - m_freem(m); - return (EINVAL); /* XXX */ - } - la = (struct llinfo_arp *)rt->rt_llinfo; - if (la == NULL) { - RT_UNLOCK(rt); + if (flags & LLE_CREATE) log(LOG_DEBUG, "arpresolve: can't allocate llinfo for %s\n", inet_ntoa(SIN(dst)->sin_addr)); - m_freem(m); - return (EINVAL); /* XXX */ - } - } - sdl = SDL(rt->rt_gateway); - /* - * Check the address family and length is valid, the address - * is resolved; otherwise, try to resolve. - */ - if ((rt->rt_expire == 0 || rt->rt_expire > time_uptime) && - sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) { - - bcopy(LLADDR(sdl), desten, sdl->sdl_alen); + m_freem(m); + return (EINVAL); + } + 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 entry has an expiry time and it is approaching, - * send an ARP request. + * see if we need to send an ARP request within this + * arpt_down interval. */ - if ((rt->rt_expire != 0) && - (time_uptime + la->la_preempt > rt->rt_expire)) { - struct in_addr sin = - SIN(rt->rt_ifa->ifa_addr)->sin_addr; + if (!(la->la_flags & LLE_STATIC) && + time_uptime + la->la_preempt > la->la_expire) { + arprequest(ifp, NULL, + &SIN(dst)->sin_addr, IF_LLADDR(ifp)); la->la_preempt--; - RT_UNLOCK(rt); - arprequest(ifp, &sin, &SIN(dst)->sin_addr, - IF_LLADDR(ifp)); - return (0); - } - - RT_UNLOCK(rt); - return (0); - } - /* - * If ARP is disabled or static on this interface, stop. - * XXX - * Probably should not allocate empty llinfo struct if we are - * not going to be sending out an arp request. - */ - if (ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) { - RT_UNLOCK(rt); + } + + *lle = la; + error = 0; + goto done; + } + + if (la->la_flags & LLE_STATIC) { /* should not happen! */ + log(LOG_DEBUG, "arpresolve: ouch, empty static llinfo for %s\n", + inet_ntoa(SIN(dst)->sin_addr)); m_freem(m); - return (EINVAL); + error = EINVAL; + goto done; + } + + renew = (la->la_asked == 0 || la->la_expire != time_uptime); + if ((renew || m != NULL) && (flags & LLE_EXCLUSIVE) == 0) { + flags |= LLE_EXCLUSIVE; + LLE_RUNLOCK(la); + goto retry; } /* * There is an arptab entry, but no ethernet address * response yet. Replace the held mbuf with this * latest one. */ - if (m) { - if (la->la_hold) + if (m != NULL) { + if (la->la_hold != NULL) m_freem(la->la_hold); la->la_hold = m; + if (renew == 0 && (flags & LLE_EXCLUSIVE)) { + flags &= ~LLE_EXCLUSIVE; + LLE_DOWNGRADE(la); + } + } - KASSERT(rt->rt_expire > 0, ("sending ARP request for static entry")); - /* * Return EWOULDBLOCK if we have tried less than arp_maxtries. It * will be masked by ether_output(). Return EHOSTDOWN/EHOSTUNREACH @@ -499,22 +349,24 @@ arpresolve(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m, if (la->la_asked < V_arp_maxtries) error = EWOULDBLOCK; /* First request. */ else - error = (rt == rt0) ? EHOSTDOWN : EHOSTUNREACH; - - if (la->la_asked == 0 || rt->rt_expire != time_uptime) { - struct in_addr sin = - SIN(rt->rt_ifa->ifa_addr)->sin_addr; + error = + (rt0->rt_flags & RTF_GATEWAY) ? EHOSTDOWN : EHOSTUNREACH; - rt->rt_expire = time_uptime; - callout_reset(&la->la_timer, hz, arptimer, rt); + if (renew) { + LLE_ADDREF(la); + la->la_expire = time_uptime; + callout_reset(&la->la_timer, hz, arptimer, la); la->la_asked++; - RT_UNLOCK(rt); - - arprequest(ifp, &sin, &SIN(dst)->sin_addr, + LLE_WUNLOCK(la); + arprequest(ifp, NULL, &SIN(dst)->sin_addr, IF_LLADDR(ifp)); - } else - RT_UNLOCK(rt); - + return (error); + } +done: + if (flags & LLE_EXCLUSIVE) + LLE_WUNLOCK(la); + else + LLE_RUNLOCK(la); return (error); } @@ -598,21 +450,17 @@ in_arpinput(struct mbuf *m) { struct arphdr *ah; struct ifnet *ifp = m->m_pkthdr.rcvif; - struct llinfo_arp *la; + struct llentry *la = NULL; struct rtentry *rt; struct ifaddr *ifa; struct in_ifaddr *ia; - struct sockaddr_dl *sdl; struct sockaddr sa; struct in_addr isaddr, itaddr, myaddr; - struct mbuf *hold; u_int8_t *enaddr = NULL; - int op, rif_len; + int op, flags; + struct mbuf *m0; int req_len; int bridged = 0, is_bridge = 0; - u_int fibnum; - u_int goodfib = 0; - int firstpass = 1; #ifdef DEV_CARP int carp_match = 0; #endif @@ -649,7 +497,7 @@ in_arpinput(struct mbuf *m) */ LIST_FOREACH(ia, INADDR_HASH(itaddr.s_addr), ia_hash) { if (((bridged && ia->ia_ifp->if_bridge != NULL) || - (ia->ia_ifp == ifp)) && + ia->ia_ifp == ifp) && itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) goto match; #ifdef DEV_CARP @@ -663,7 +511,7 @@ in_arpinput(struct mbuf *m) } LIST_FOREACH(ia, INADDR_HASH(isaddr.s_addr), ia_hash) if (((bridged && ia->ia_ifp->if_bridge != NULL) || - (ia->ia_ifp == ifp)) && + ia->ia_ifp == ifp) && isaddr.s_addr == ia->ia_addr.sin_addr.s_addr) goto match; @@ -729,254 +577,151 @@ match: } if (ifp->if_flags & IFF_STATICARP) goto reply; - /* - * We look for any FIB that has this address to find - * the interface etc. - * For sanity checks that are FIB independent we abort the loop. - */ - for (fibnum = 0; fibnum < rt_numfibs; fibnum++) { - rt = arplookup(isaddr.s_addr, - itaddr.s_addr == myaddr.s_addr, 0, fibnum); - if (rt == NULL) - continue; - - sdl = SDL(rt->rt_gateway); - /* Only call this once */ - if (firstpass) { - sin.sin_addr.s_addr = isaddr.s_addr; - EVENTHANDLER_INVOKE(route_arp_update_event, rt, - ar_sha(ah), (struct sockaddr *)&sin); - } - - la = (struct llinfo_arp *)rt->rt_llinfo; - if (la == NULL) { - RT_UNLOCK(rt); - continue; - } - if (firstpass) { - /* The following is not an error when doing bridging. */ - if (!bridged && rt->rt_ifp != ifp + bzero(&sin, sizeof(sin)); + sin.sin_len = sizeof(struct sockaddr_in); + sin.sin_family = AF_INET; + sin.sin_addr = isaddr; + flags = (itaddr.s_addr == myaddr.s_addr) ? LLE_CREATE : 0; + flags |= LLE_EXCLUSIVE; + IF_AFDATA_LOCK(ifp); + la = lla_lookup(LLTABLE(ifp), flags, (struct sockaddr *)&sin); + IF_AFDATA_UNLOCK(ifp); + if (la != NULL) { + /* the following is not an error when doing bridging */ + if (!bridged && la->lle_tbl->llt_ifp != ifp #ifdef DEV_CARP - && (ifp->if_type != IFT_CARP || !carp_match) + && (ifp->if_type != IFT_CARP || !carp_match) #endif - ) { - if (log_arp_wrong_iface) - log(LOG_ERR, "arp: %s is on %s " - "but got reply from %*D " - "on %s\n", - inet_ntoa(isaddr), - rt->rt_ifp->if_xname, - ifp->if_addrlen, - (u_char *)ar_sha(ah), ":", - ifp->if_xname); - RT_UNLOCK(rt); - break; - } - if (sdl->sdl_alen && - bcmp(ar_sha(ah), LLADDR(sdl), sdl->sdl_alen)) { - if (rt->rt_expire) { - if (log_arp_movements) - log(LOG_INFO, - "arp: %s moved from %*D to %*D " - "on %s\n", - inet_ntoa(isaddr), - ifp->if_addrlen, - (u_char *)LLADDR(sdl), ":", - ifp->if_addrlen, - (u_char *)ar_sha(ah), ":", - ifp->if_xname); - } else { - RT_UNLOCK(rt); - if (log_arp_permanent_modify) - log(LOG_ERR, - "arp: %*D attempts to " - "modify permanent entry " - "for %s on %s\n", - ifp->if_addrlen, - (u_char *)ar_sha(ah), ":", - inet_ntoa(isaddr), - ifp->if_xname); - break; - } - } - /* - * sanity check for the address length. - * XXX this does not work for protocols - * with variable address length. -is - */ - if (sdl->sdl_alen && - sdl->sdl_alen != ah->ar_hln) { - log(LOG_WARNING, - "arp from %*D: new addr len %d, was %d", - ifp->if_addrlen, (u_char *) ar_sha(ah), - ":", ah->ar_hln, sdl->sdl_alen); + ) { + if (log_arp_wrong_iface) + log(LOG_ERR, "arp: %s is on %s " + "but got reply from %*D on %s\n", + inet_ntoa(isaddr), + la->lle_tbl->llt_ifp->if_xname, + ifp->if_addrlen, (u_char *)ar_sha(ah), ":", + ifp->if_xname); + goto reply; + } + if ((la->la_flags & LLE_VALID) && + bcmp(ar_sha(ah), &la->ll_addr, ifp->if_addrlen)) { + if (la->la_flags & LLE_STATIC) { + log(LOG_ERR, + "arp: %*D attempts to modify permanent " + "entry for %s on %s\n", + ifp->if_addrlen, (u_char *)ar_sha(ah), ":", + inet_ntoa(isaddr), ifp->if_xname); + goto reply; } - if (ifp->if_addrlen != ah->ar_hln) { - log(LOG_WARNING, - "arp from %*D: addr len: " - "new %d, i/f %d (ignored)", - ifp->if_addrlen, (u_char *) ar_sha(ah), - ":", ah->ar_hln, ifp->if_addrlen); - RT_UNLOCK(rt); - break; + if (log_arp_movements) { + log(LOG_INFO, "arp: %s moved from %*D " + "to %*D on %s\n", + inet_ntoa(isaddr), + ifp->if_addrlen, + (u_char *)&la->ll_addr, ":", + ifp->if_addrlen, (u_char *)ar_sha(ah), ":", + ifp->if_xname); } - firstpass = 0; - goodfib = fibnum; } - - /* Copy in the information received. */ - (void)memcpy(LLADDR(sdl), ar_sha(ah), - sdl->sdl_alen = ah->ar_hln); - /* - * If we receive an arp from a token-ring station over - * a token-ring nic then try to save the source routing info. - * XXXMRT Only minimal Token Ring support for MRT. - * Only do this on the first pass as if modifies the mbuf. - */ - if (ifp->if_type == IFT_ISO88025) { - struct iso88025_header *th = NULL; - struct iso88025_sockaddr_dl_data *trld; - - /* force the fib loop to end after this pass */ - fibnum = rt_numfibs - 1; - - th = (struct iso88025_header *)m->m_pkthdr.header; - trld = SDL_ISO88025(sdl); - rif_len = TR_RCF_RIFLEN(th->rcf); - if ((th->iso88025_shost[0] & TR_RII) && - (rif_len > 2)) { - trld->trld_rcf = th->rcf; - trld->trld_rcf ^= htons(TR_RCF_DIR); - memcpy(trld->trld_route, th->rd, rif_len - 2); - trld->trld_rcf &= ~htons(TR_RCF_BCST_MASK); - /* - * Set up source routing information for - * reply packet (XXX) - */ - m->m_data -= rif_len; - m->m_len += rif_len; - m->m_pkthdr.len += rif_len; - } else { - th->iso88025_shost[0] &= ~TR_RII; - trld->trld_rcf = 0; - } - m->m_data -= 8; - m->m_len += 8; - m->m_pkthdr.len += 8; - th->rcf = trld->trld_rcf; + + if (ifp->if_addrlen != ah->ar_hln) { + log(LOG_WARNING, + "arp from %*D: addr len: new %d, i/f %d (ignored)", + ifp->if_addrlen, (u_char *) ar_sha(ah), ":", + ah->ar_hln, ifp->if_addrlen); + goto reply; } + (void)memcpy(&la->ll_addr, ar_sha(ah), ifp->if_addrlen); + la->la_flags |= LLE_VALID; - if (rt->rt_expire) { - rt->rt_expire = time_uptime + V_arpt_keep; + if (!(la->la_flags & LLE_STATIC)) { + la->la_expire = time_uptime + V_arpt_keep; callout_reset(&la->la_timer, hz * V_arpt_keep, - arptimer, rt); + arptimer, la); } la->la_asked = 0; la->la_preempt = V_arp_maxtries; - hold = la->la_hold; - la->la_hold = NULL; - RT_UNLOCK(rt); - if (hold != NULL) - (*ifp->if_output)(ifp, hold, rt_key(rt), rt); - } /* end of FIB loop */ + if (la->la_hold != NULL) { + m0 = la->la_hold; + la->la_hold = 0; + memcpy(&sa, L3_ADDR(la), sizeof(sa)); + LLE_WUNLOCK(la); + + (*ifp->if_output)(ifp, m0, &sa, NULL); + return; + } + } reply: - - /* - * Decide if we have to respond to something. - */ if (op != ARPOP_REQUEST) goto drop; + if (itaddr.s_addr == myaddr.s_addr) { /* Shortcut.. the receiving interface is the target. */ (void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln); (void)memcpy(ar_sha(ah), enaddr, ah->ar_hln); } else { - /* It's not asking for our address. But it still may - * be something we should answer. - * - * XXX MRT - * We assume that link level info is independent of - * the table used and so we use whichever we can and don't - * have a better option. + struct llentry *lle = NULL; + + if (!V_arp_proxyall) + goto drop; + + sin.sin_addr = itaddr; + /* XXX MRT use table 0 for arp reply */ + rt = in_rtalloc1((struct sockaddr *)&sin, 0, 0UL, 0); + if (!rt) + goto drop; + + /* + * Don't send proxies for nodes on the same interface + * as this one came out of, or we'll get into a fight + * over who claims what Ether address. */ - /* Have we been asked to proxy for the target. */ - rt = arplookup(itaddr.s_addr, 0, SIN_PROXY, goodfib); - if (rt == NULL) { - /* Nope, only intersted now if proxying everything. */ - struct sockaddr_in sin; - - if (!V_arp_proxyall) - goto drop; - - bzero(&sin, sizeof sin); - sin.sin_family = AF_INET; - sin.sin_len = sizeof sin; - sin.sin_addr = itaddr; - - /* XXX MRT use table 0 for arp reply */ - rt = in_rtalloc1((struct sockaddr *)&sin, 0, 0UL, 0); - if (!rt) - goto drop; - /* - * Don't send proxies for nodes on the same interface - * as this one came out of, or we'll get into a fight - * over who claims what Ether address. - */ - if (rt->rt_ifp == ifp) { - RTFREE_LOCKED(rt); - goto drop; - } - (void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln); - (void)memcpy(ar_sha(ah), enaddr, ah->ar_hln); + if (!rt->rt_ifp || rt->rt_ifp == ifp) { RTFREE_LOCKED(rt); + goto drop; + } + IF_AFDATA_LOCK(rt->rt_ifp); + lle = lla_lookup(LLTABLE(rt->rt_ifp), 0, (struct sockaddr *)&sin); + IF_AFDATA_UNLOCK(rt->rt_ifp); + RTFREE_LOCKED(rt); - /* - * Also check that the node which sent the ARP packet - * is on the the interface we expect it to be on. This - * avoids ARP chaos if an interface is connected to the - * wrong network. - */ - sin.sin_addr = isaddr; - - /* XXX MRT use table 0 for arp checks */ - rt = in_rtalloc1((struct sockaddr *)&sin, 0, 0UL, 0); - if (!rt) - goto drop; - if (rt->rt_ifp != ifp) { - log(LOG_INFO, "arp_proxy: ignoring request" - " from %s via %s, expecting %s\n", - inet_ntoa(isaddr), ifp->if_xname, - rt->rt_ifp->if_xname); - RTFREE_LOCKED(rt); - goto drop; - } + if (lle != NULL) { + (void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln); + (void)memcpy(ar_sha(ah), &lle->ll_addr, ah->ar_hln); + LLE_RUNLOCK(lle); + } else + goto drop; + + /* + * Also check that the node which sent the ARP packet + * is on the the interface we expect it to be on. This + * avoids ARP chaos if an interface is connected to the + * wrong network. + */ + sin.sin_addr = isaddr; + + /* XXX MRT use table 0 for arp checks */ + rt = in_rtalloc1((struct sockaddr *)&sin, 0, 0UL, 0); + if (!rt) + goto drop; + if (rt->rt_ifp != ifp) { + log(LOG_INFO, "arp_proxy: ignoring request" + " from %s via %s, expecting %s\n", + inet_ntoa(isaddr), ifp->if_xname, + rt->rt_ifp->if_xname); RTFREE_LOCKED(rt); + goto drop; + } + RTFREE_LOCKED(rt); #ifdef DEBUG_PROXY - printf("arp: proxying for %s\n", - inet_ntoa(itaddr)); + printf("arp: proxying for %s\n", + inet_ntoa(itaddr)); #endif - } else { - /* - * Return proxied ARP replies only on the interface - * or bridge cluster where this network resides. - * Otherwise we may conflict with the host we are - * proxying for. - */ - if (rt->rt_ifp != ifp && - (rt->rt_ifp->if_bridge != ifp->if_bridge || - ifp->if_bridge == NULL)) { - RT_UNLOCK(rt); - goto drop; - } - sdl = SDL(rt->rt_gateway); - (void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln); - (void)memcpy(ar_sha(ah), LLADDR(sdl), ah->ar_hln); - RT_UNLOCK(rt); - } } + if (la != NULL) + LLE_WUNLOCK(la); if (itaddr.s_addr == myaddr.s_addr && IN_LINKLOCAL(ntohl(itaddr.s_addr))) { /* RFC 3927 link-local IPv4; always reply by broadcast. */ @@ -1002,68 +747,35 @@ reply: return; drop: + if (la != NULL) + LLE_WUNLOCK(la); m_freem(m); } #endif -/* - * Lookup or enter a new address in arptab. - */ -static struct rtentry * -arplookup(u_long addr, int create, int proxy, int fibnum) -{ - struct rtentry *rt; - struct sockaddr_inarp sin; - const char *why = 0; - - bzero(&sin, sizeof(sin)); - sin.sin_len = sizeof(sin); - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = addr; - if (proxy) - sin.sin_other = SIN_PROXY; - rt = in_rtalloc1((struct sockaddr *)&sin, create, 0UL, fibnum); - if (rt == 0) - return (0); - - if (rt->rt_flags & RTF_GATEWAY) - why = "host is not on local network"; - else if ((rt->rt_flags & RTF_LLINFO) == 0) - why = "could not allocate llinfo"; - else if (rt->rt_gateway->sa_family != AF_LINK) - why = "gateway route is not ours"; - - if (why) { -#define ISDYNCLONE(_rt) \ - (((_rt)->rt_flags & (RTF_STATIC | RTF_WASCLONED)) == RTF_WASCLONED) - if (create) - log(LOG_DEBUG, "arplookup %s failed: %s\n", - inet_ntoa(sin.sin_addr), why); - /* - * If there are no references to this Layer 2 route, - * and it is a cloned route, and not static, and - * arplookup() is creating the route, then purge - * it from the routing table as it is probably bogus. - */ - if (rt->rt_refcnt == 1 && ISDYNCLONE(rt)) - rtexpunge(rt); - RTFREE_LOCKED(rt); - return (0); -#undef ISDYNCLONE - } else { - RT_REMREF(rt); - return (rt); - } -} - void arp_ifinit(struct ifnet *ifp, struct ifaddr *ifa) { + struct llentry *lle; + if (ntohl(IA_SIN(ifa)->sin_addr.s_addr) != INADDR_ANY) arprequest(ifp, &IA_SIN(ifa)->sin_addr, &IA_SIN(ifa)->sin_addr, IF_LLADDR(ifp)); - ifa->ifa_rtrequest = arp_rtrequest; - ifa->ifa_flags |= RTF_CLONING; + /* + * interface address is considered static entry + * because the output of the arp utility shows + * that L2 entry as permanent + */ + IF_AFDATA_LOCK(ifp); + lle = lla_lookup(LLTABLE(ifp), (LLE_CREATE | LLE_IFADDR | LLE_STATIC), + (struct sockaddr *)IA_SIN(ifa)); + IF_AFDATA_UNLOCK(ifp); + if (lle == NULL) + log(LOG_INFO, "arp_ifinit: cannot create arp " + "entry for interface address\n"); + else + LLE_RUNLOCK(lle); + ifa->ifa_rtrequest = NULL; } void @@ -1072,8 +784,7 @@ arp_ifinit2(struct ifnet *ifp, struct ifaddr *ifa, u_char *enaddr) if (ntohl(IA_SIN(ifa)->sin_addr.s_addr) != INADDR_ANY) arprequest(ifp, &IA_SIN(ifa)->sin_addr, &IA_SIN(ifa)->sin_addr, enaddr); - ifa->ifa_rtrequest = arp_rtrequest; - ifa->ifa_flags |= RTF_CLONING; + ifa->ifa_rtrequest = NULL; } static void diff --git a/sys/netinet/if_ether.h b/sys/netinet/if_ether.h index 14df15f..ba4e2f6 100644 --- a/sys/netinet/if_ether.h +++ b/sys/netinet/if_ether.h @@ -109,8 +109,11 @@ struct sockaddr_inarp { extern u_char ether_ipmulticast_min[ETHER_ADDR_LEN]; extern u_char ether_ipmulticast_max[ETHER_ADDR_LEN]; +struct llentry; + int arpresolve(struct ifnet *ifp, struct rtentry *rt, - struct mbuf *m, struct sockaddr *dst, u_char *desten); + struct mbuf *m, struct sockaddr *dst, u_char *desten, + struct llentry **lle); void arp_ifinit(struct ifnet *, struct ifaddr *); void arp_ifinit2(struct ifnet *, struct ifaddr *, u_char *); #endif diff --git a/sys/netinet/in.c b/sys/netinet/in.c index 9b6dd48..94535b1 100644 --- a/sys/netinet/in.c +++ b/sys/netinet/in.c @@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$"); #include <sys/vimage.h> #include <net/if.h> +#include <net/if_llatbl.h> #include <net/if_types.h> #include <net/route.h> @@ -871,6 +872,8 @@ in_addprefix(struct in_ifaddr *target, int flags) return (error); } +extern void arp_ifscrub(struct ifnet *ifp, uint32_t addr); + /* * If there is no other address in the system that can serve a route to the * same prefix, remove the route. Hand over the route to the new address @@ -893,6 +896,8 @@ in_scrubprefix(struct in_ifaddr *target) prefix = target->ia_addr.sin_addr; mask = target->ia_sockmask.sin_addr; prefix.s_addr &= mask.s_addr; + /* remove arp cache */ + arp_ifscrub(target->ia_ifp, IA_SIN(target)->sin_addr.s_addr); } TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { @@ -1015,3 +1020,240 @@ in_ifdetach(struct ifnet *ifp) in_pcbpurgeif0(&V_udbinfo, ifp); in_purgemaddrs(ifp); } + +#include <sys/syslog.h> +#include <net/if_dl.h> +#include <netinet/if_ether.h> + +struct in_llentry { + struct llentry base; + struct sockaddr_in l3_addr4; +}; + +static struct llentry * +in_lltable_new(const struct sockaddr *l3addr, u_int flags) +{ + struct in_llentry *lle; + + lle = malloc(sizeof(struct in_llentry), M_LLTABLE, M_DONTWAIT | M_ZERO); + if (lle == NULL) /* NB: caller generates msg */ + return NULL; + + callout_init(&lle->base.la_timer, CALLOUT_MPSAFE); + /* + * For IPv4 this will trigger "arpresolve" to generate + * an ARP request. + */ + lle->base.la_expire = time_second; /* mark expired */ + lle->l3_addr4 = *(const struct sockaddr_in *)l3addr; + lle->base.lle_refcnt = 1; + LLE_LOCK_INIT(&lle->base); + return &lle->base; +} + +/* + * Deletes an address from the address table. + * This function is called by the timer functions + * such as arptimer() and nd6_llinfo_timer(), and + * the caller does the locking. + */ +static void +in_lltable_free(struct lltable *llt, struct llentry *lle) +{ + LLE_WUNLOCK(lle); + LLE_LOCK_DESTROY(lle); + free(lle, M_LLTABLE); +} + +static int +in_lltable_rtcheck(struct ifnet *ifp, const struct sockaddr *l3addr) +{ + struct rtentry *rt; + + KASSERT(l3addr->sa_family == AF_INET, + ("sin_family %d", l3addr->sa_family)); + + /* XXX rtalloc1 should take a const param */ + rt = rtalloc1(__DECONST(struct sockaddr *, l3addr), 0, 0); + if (rt == NULL || (rt->rt_flags & RTF_GATEWAY) || rt->rt_ifp != ifp) { + log(LOG_INFO, "IPv4 address: \"%s\" is not on the network\n", + inet_ntoa(((const struct sockaddr_in *)l3addr)->sin_addr)); + if (rt != NULL) + RTFREE_LOCKED(rt); + return (EINVAL); + } + RTFREE_LOCKED(rt); + return 0; +} + +/* + * Return NULL if not found or marked for deletion. + * If found return lle read locked. + */ +static struct llentry * +in_lltable_lookup(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; + struct llentries *lleh; + u_int hashkey; + + IF_AFDATA_LOCK_ASSERT(ifp); + KASSERT(l3addr->sa_family == AF_INET, + ("sin_family %d", l3addr->sa_family)); + + hashkey = sin->sin_addr.s_addr; + lleh = &llt->lle_head[LLATBL_HASH(hashkey, LLTBL_HASHMASK)]; + LIST_FOREACH(lle, lleh, lle_next) { + if (lle->la_flags & LLE_DELETED) + continue; + if (bcmp(L3_ADDR(lle), l3addr, sizeof(struct sockaddr_in)) == 0) + break; + } + if (lle == NULL) { +#ifdef DIAGNOSTICS + if (flags & LLE_DELETE) + log(LOG_INFO, "interface address is missing from cache = %p in delete\n", lle); +#endif + if (!(flags & LLE_CREATE)) + return (NULL); + /* + * A route that covers the given address must have + * been installed 1st because we are doing a resolution, + * verify this. + */ + if (!(flags & LLE_IFADDR) && + in_lltable_rtcheck(ifp, l3addr) != 0) + goto done; + + lle = in_lltable_new(l3addr, flags); + if (lle == NULL) { + log(LOG_INFO, "lla_lookup: new lle malloc failed\n"); + goto done; + } + lle->la_flags = flags & ~LLE_CREATE; + if ((flags & (LLE_CREATE | LLE_IFADDR)) == (LLE_CREATE | LLE_IFADDR)) { + bcopy(IF_LLADDR(ifp), &lle->ll_addr, ifp->if_addrlen); + lle->la_flags |= (LLE_VALID | LLE_STATIC); + } + + lle->lle_tbl = llt; + lle->lle_head = lleh; + LIST_INSERT_HEAD(lleh, lle, lle_next); + } else if (flags & LLE_DELETE) { + if (!(lle->la_flags & LLE_IFADDR) || (flags & LLE_IFADDR)) { + LLE_WLOCK(lle); + lle->la_flags = LLE_DELETED; + LLE_WUNLOCK(lle); +#ifdef DIAGNOSTICS + log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle); +#endif + } + lle = (void *)-1; + + } + if (lle != NULL && lle != (void *)-1) { + if (flags & LLE_EXCLUSIVE) + LLE_WLOCK(lle); + else + LLE_RLOCK(lle); + } +done: + return (lle); +} + +static int +in_lltable_dump(struct lltable *llt, struct sysctl_req *wr) +{ +#define SIN(lle) ((struct sockaddr_in *) L3_ADDR(lle)) + struct ifnet *ifp = llt->llt_ifp; + struct llentry *lle; + /* XXX stack use */ + struct { + struct rt_msghdr rtm; + struct sockaddr_inarp sin; + struct sockaddr_dl sdl; + } arpc; + int error, i; + + /* XXXXX + * current IFNET_RLOCK() is mapped to IFNET_WLOCK() + * so it is okay to use this ASSERT, change it when + * IFNET lock is finalized + */ + IFNET_WLOCK_ASSERT(); + + error = 0; + for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) { + LIST_FOREACH(lle, &llt->lle_head[i], lle_next) { + struct sockaddr_dl *sdl; + + /* skip deleted entries */ + if ((lle->la_flags & (LLE_DELETED|LLE_VALID)) != LLE_VALID) + continue; + /* + * produce a msg made of: + * struct rt_msghdr; + * struct sockaddr_inarp; (IPv4) + * struct sockaddr_dl; + */ + bzero(&arpc, sizeof(arpc)); + arpc.rtm.rtm_msglen = sizeof(arpc); + arpc.sin.sin_family = AF_INET; + arpc.sin.sin_len = sizeof(arpc.sin); + arpc.sin.sin_addr.s_addr = SIN(lle)->sin_addr.s_addr; + + /* publish */ + if (lle->la_flags & LLE_PUB) { + arpc.rtm.rtm_flags |= RTF_ANNOUNCE; + /* proxy only */ + if (lle->la_flags & LLE_PROXY) + arpc.sin.sin_other = SIN_PROXY; + } + + sdl = &arpc.sdl; + sdl->sdl_family = AF_LINK; + sdl->sdl_len = sizeof(*sdl); + sdl->sdl_alen = ifp->if_addrlen; + sdl->sdl_index = ifp->if_index; + sdl->sdl_type = ifp->if_type; + bcopy(&lle->ll_addr, LLADDR(sdl), ifp->if_addrlen); + + arpc.rtm.rtm_rmx.rmx_expire = + lle->la_flags & LLE_STATIC ? 0 : lle->la_expire; + arpc.rtm.rtm_flags |= RTF_HOST; + if (lle->la_flags & LLE_STATIC) + arpc.rtm.rtm_flags |= RTF_STATIC; + arpc.rtm.rtm_index = ifp->if_index; + error = SYSCTL_OUT(wr, &arpc, sizeof(arpc)); + if (error) + break; + } + } + return error; +#undef SIN +} + +void * +in_domifattach(struct ifnet *ifp) +{ + struct lltable *llt = lltable_init(ifp, AF_INET); + + if (llt != NULL) { + llt->llt_new = in_lltable_new; + llt->llt_free = in_lltable_free; + llt->llt_rtcheck = in_lltable_rtcheck; + llt->llt_lookup = in_lltable_lookup; + llt->llt_dump = in_lltable_dump; + } + return (llt); +} + +void +in_domifdetach(struct ifnet *ifp __unused, void *aux) +{ + struct lltable *llt = (struct lltable *)aux; + + lltable_free(llt); +} diff --git a/sys/netinet/in_mcast.c b/sys/netinet/in_mcast.c index e7916dd..6f5dfe1 100644 --- a/sys/netinet/in_mcast.c +++ b/sys/netinet/in_mcast.c @@ -1036,7 +1036,7 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) ro.ro_rt = NULL; *(struct sockaddr_in *)&ro.ro_dst = gsa->sin; - in_rtalloc_ign(&ro, RTF_CLONING, + in_rtalloc_ign(&ro, 0, inp->inp_inc.inc_fibnum); if (ro.ro_rt != NULL) { ifp = ro.ro_rt->rt_ifp; diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index 70f217a..6d1c2aa 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -570,7 +570,7 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr, * Find out route to destination. */ if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0) - in_rtalloc_ign(&sro, RTF_CLONING, inp->inp_inc.inc_fibnum); + in_rtalloc_ign(&sro, 0, inp->inp_inc.inc_fibnum); /* * If we found a route, use the address corresponding to @@ -695,6 +695,10 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr, ia = ifatoia(ifa_ifwithnet(sintosa(&sain))); if (cred == NULL || !jailed(cred)) { +#if __FreeBSD_version < 800000 + if (ia == NULL) + ia = (struct in_ifaddr *)sro.ro_rt->rt_ifa; +#endif if (ia == NULL) { error = ENETUNREACH; goto done; @@ -1696,7 +1700,7 @@ db_print_inconninfo(struct in_conninfo *inc, const char *name, int indent) indent += 2; #ifdef INET6 - if (inc->inc_flags == 1) { + if (inc->inc_flags & INC_ISIPV6) { /* IPv6. */ ip6_sprintf(laddr_str, &inc->inc6_laddr); ip6_sprintf(faddr_str, &inc->inc6_faddr); diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h index f0275bd..01636fe 100644 --- a/sys/netinet/in_pcb.h +++ b/sys/netinet/in_pcb.h @@ -106,6 +106,12 @@ struct in_conninfo { /* protocol dependent part */ struct in_endpoints inc_ie; }; + +/* + * Flags for inc_flags. + */ +#define INC_ISIPV6 0x01 + #define inc_isipv6 inc_flags /* temp compatability */ #define inc_fport inc_ie.ie_fport #define inc_lport inc_ie.ie_lport @@ -435,7 +441,7 @@ void inp_4tuple_get(struct inpcb *inp, uint32_t *laddr, uint16_t *lp, #define IN6P_RECVIF INP_RECVIF #define IN6P_MTUDISC INP_MTUDISC #define IN6P_FAITH INP_FAITH -#define IN6P_CONTROLOPTS INP_CONTROLOPTS +#define IN6P_CONTROLOPTS INP_CONTROLOPTS /* * socket AF version is {newer than,or include} * actual datagram AF version diff --git a/sys/netinet/in_proto.c b/sys/netinet/in_proto.c index a93f1f2..f3fbe0c 100644 --- a/sys/netinet/in_proto.c +++ b/sys/netinet/in_proto.c @@ -59,6 +59,7 @@ __FBSDID("$FreeBSD$"); #include <netinet/in.h> #include <netinet/in_systm.h> +#include <netinet/in_var.h> #include <netinet/ip.h> #include <netinet/ip_var.h> #include <netinet/ip_icmp.h> @@ -364,7 +365,9 @@ struct domain inetdomain = { .dom_rtattach = in_inithead, #endif .dom_rtoffset = 32, - .dom_maxrtkey = sizeof(struct sockaddr_in) + .dom_maxrtkey = sizeof(struct sockaddr_in), + .dom_ifattach = in_domifattach, + .dom_ifdetach = in_domifdetach }; DOMAIN_SET(inet); diff --git a/sys/netinet/in_rmx.c b/sys/netinet/in_rmx.c index aa4ca0d..f9e9d98 100644 --- a/sys/netinet/in_rmx.c +++ b/sys/netinet/in_rmx.c @@ -75,8 +75,8 @@ in_addroute(void *v_arg, void *n_arg, struct radix_node_head *head, { struct rtentry *rt = (struct rtentry *)treenodes; struct sockaddr_in *sin = (struct sockaddr_in *)rt_key(rt); - struct radix_node *ret; + RADIX_NODE_HEAD_WLOCK_ASSERT(head); /* * A little bit of help for both IP output and input: * For host routes, we make sure that RTF_BROADCAST @@ -106,31 +106,7 @@ in_addroute(void *v_arg, void *n_arg, struct radix_node_head *head, if (!rt->rt_rmx.rmx_mtu && rt->rt_ifp) rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; - ret = rn_addroute(v_arg, n_arg, head, treenodes); - if (ret == NULL && rt->rt_flags & RTF_HOST) { - struct rtentry *rt2; - /* - * We are trying to add a host route, but can't. - * Find out if it is because of an - * ARP entry and delete it if so. - */ - rt2 = in_rtalloc1((struct sockaddr *)sin, 0, - RTF_CLONING, rt->rt_fibnum); - if (rt2) { - if (rt2->rt_flags & RTF_LLINFO && - rt2->rt_flags & RTF_HOST && - rt2->rt_gateway && - rt2->rt_gateway->sa_family == AF_LINK) { - rtexpunge(rt2); - RTFREE_LOCKED(rt2); - ret = rn_addroute(v_arg, n_arg, head, - treenodes); - } else - RTFREE_LOCKED(rt2); - } - } - - return ret; + return (rn_addroute(v_arg, n_arg, head, treenodes)); } /* @@ -187,13 +163,10 @@ in_clsroute(struct radix_node *rn, struct radix_node_head *head) if (!(rt->rt_flags & RTF_UP)) return; /* prophylactic measures */ - if ((rt->rt_flags & (RTF_LLINFO | RTF_HOST)) != RTF_HOST) - return; - if (rt->rt_flags & RTPRF_OURS) return; - if (!(rt->rt_flags & (RTF_WASCLONED | RTF_DYNAMIC))) + if (!(rt->rt_flags & RTF_DYNAMIC)) return; /* @@ -434,7 +407,6 @@ in_ifadownkill(struct radix_node *rn, void *xap) * the routes that rtrequest() would have in any case, * so that behavior is not needed there. */ - rt->rt_flags &= ~RTF_CLONING; rtexpunge(rt); } RT_UNLOCK(rt); diff --git a/sys/netinet/in_var.h b/sys/netinet/in_var.h index 1190826..73868ad 100644 --- a/sys/netinet/in_var.h +++ b/sys/netinet/in_var.h @@ -84,9 +84,13 @@ extern u_char inetctlerrmap[]; /* * Hash table for IP addresses. */ -extern LIST_HEAD(in_ifaddrhashhead, in_ifaddr) *in_ifaddrhashtbl; -extern TAILQ_HEAD(in_ifaddrhead, in_ifaddr) in_ifaddrhead; +TAILQ_HEAD(in_ifaddrhead, in_ifaddr); +LIST_HEAD(in_ifaddrhashhead, in_ifaddr); +#ifdef VIMAGE_GLOBALS +extern struct in_ifaddrhashhead *in_ifaddrhashtbl; +extern struct in_ifaddrhead in_ifaddrhead; extern u_long in_ifaddrhmask; /* mask for hash table */ +#endif #define INADDR_NHASH_LOG2 9 #define INADDR_NHASH (1 << INADDR_NHASH_LOG2) @@ -227,7 +231,10 @@ SYSCTL_DECL(_net_inet_ip); SYSCTL_DECL(_net_inet_raw); #endif -extern LIST_HEAD(in_multihead, in_multi) in_multihead; +LIST_HEAD(in_multihead, in_multi); +#ifdef VIMAGE_GLOBALS +extern struct in_multihead in_multihead; +#endif /* * Lock macros for IPv4 layer multicast address lists. IPv4 lock goes @@ -314,6 +321,9 @@ void ip_input(struct mbuf *); int in_ifadown(struct ifaddr *ifa, int); void in_ifscrub(struct ifnet *, struct in_ifaddr *); struct mbuf *ip_fastforward(struct mbuf *); +void *in_domifattach(struct ifnet *); +void in_domifdetach(struct ifnet *, void *); + /* XXX */ void in_rtalloc_ign(struct route *ro, u_long ignflags, u_int fibnum); diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c index 9f6bc31..6d96163 100644 --- a/sys/netinet/ip_carp.c +++ b/sys/netinet/ip_carp.c @@ -371,14 +371,6 @@ carp_setroute(struct carp_softc *sc, int cmd) (cmd == RTM_DELETE && count == 0)) rtinit(ifa, cmd, RTF_UP | RTF_HOST); } -#ifdef INET6 - if (ifa->ifa_addr->sa_family == AF_INET6) { - if (cmd == RTM_ADD) - in6_ifaddloop(ifa); - else - in6_ifremloop(ifa); - } -#endif /* INET6 */ } splx(s); } diff --git a/sys/netinet/ip_fastfwd.c b/sys/netinet/ip_fastfwd.c index 407b08c..ea106df 100644 --- a/sys/netinet/ip_fastfwd.c +++ b/sys/netinet/ip_fastfwd.c @@ -128,7 +128,7 @@ ip_findroute(struct route *ro, struct in_addr dest, struct mbuf *m) dst->sin_family = AF_INET; dst->sin_len = sizeof(*dst); dst->sin_addr.s_addr = dest.s_addr; - in_rtalloc_ign(ro, RTF_CLONING, M_GETFIB(m)); + in_rtalloc_ign(ro, 0, M_GETFIB(m)); /* * Route there and interface still up? diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h index 6e7db99..831686d 100644 --- a/sys/netinet/ip_fw.h +++ b/sys/netinet/ip_fw.h @@ -637,7 +637,7 @@ void ipfw_nat_destroy(void); typedef int ip_fw_ctl_t(struct sockopt *); extern ip_fw_ctl_t *ip_fw_ctl_ptr; -#ifndef VIMAGE +#ifdef VIMAGE_GLOBALS extern int fw_one_pass; extern int fw_enable; #ifdef INET6 diff --git a/sys/netinet/ip_fw2.c b/sys/netinet/ip_fw2.c index 5c3ac59..1f2e67d 100644 --- a/sys/netinet/ip_fw2.c +++ b/sys/netinet/ip_fw2.c @@ -128,8 +128,8 @@ struct vnet_ipfw vnet_ipfw_0; static u_int32_t set_disable; static int fw_verbose; static struct callout ipfw_timeout; -#endif static int verbose_limit; +#endif static uma_zone_t ipfw_dyn_rule_zone; @@ -190,8 +190,9 @@ SYSCTL_V_INT(V_NET, vnet_ipfw, _net_inet_ip_fw, OID_AUTO, debug, CTLFLAG_RW, SYSCTL_V_INT(V_NET, vnet_ipfw, _net_inet_ip_fw, OID_AUTO, verbose, CTLFLAG_RW | CTLFLAG_SECURE3, fw_verbose, 0, "Log matches to ipfw rules"); -SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose_limit, CTLFLAG_RW, - &verbose_limit, 0, "Set upper limit of matches of ipfw rules logged"); +SYSCTL_V_INT(V_NET, vnet_ipfw, _net_inet_ip_fw, OID_AUTO, verbose_limit, + CTLFLAG_RW, verbose_limit, 0, + "Set upper limit of matches of ipfw rules logged"); SYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, default_rule, CTLFLAG_RD, NULL, IPFW_DEFAULT_RULE, "The default/max possible rule number."); SYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, tables_max, CTLFLAG_RD, @@ -527,7 +528,7 @@ verify_path(struct in_addr src, struct ifnet *ifp, u_int fib) dst->sin_family = AF_INET; dst->sin_len = sizeof(*dst); dst->sin_addr = src; - in_rtalloc_ign(&ro, RTF_CLONING, fib); + in_rtalloc_ign(&ro, 0, fib); if (ro.ro_rt == NULL) return 0; @@ -619,7 +620,7 @@ verify_path6(struct in6_addr *src, struct ifnet *ifp) dst->sin6_len = sizeof(*dst); dst->sin6_addr = *src; /* XXX MRT 0 for ipv6 at this time */ - rtalloc_ign((struct route *)&ro, RTF_CLONING); + rtalloc_ign((struct route *)&ro, 0); if (ro.ro_rt == NULL) return 0; @@ -1813,6 +1814,7 @@ add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr, INIT_VNET_IPFW(curvnet); struct radix_node_head *rnh; struct table_entry *ent; + struct radix_node *rn; if (tbl >= IPFW_TABLES_MAX) return (EINVAL); @@ -1825,8 +1827,8 @@ add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr, ent->mask.sin_addr.s_addr = htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0); ent->addr.sin_addr.s_addr = addr & ent->mask.sin_addr.s_addr; IPFW_WLOCK(ch); - if (rnh->rnh_addaddr(&ent->addr, &ent->mask, rnh, (void *)ent) == - NULL) { + rn = rnh->rnh_addaddr(&ent->addr, &ent->mask, rnh, (void *)ent); + if (rn == NULL) { IPFW_WUNLOCK(ch); free(ent, M_IPFW_TBL); return (EEXIST); diff --git a/sys/netinet/ip_fw_pfil.c b/sys/netinet/ip_fw_pfil.c index 952574d..694f8ab 100644 --- a/sys/netinet/ip_fw_pfil.c +++ b/sys/netinet/ip_fw_pfil.c @@ -435,8 +435,10 @@ ipfw_hook(void) if (pfh_inet == NULL) return ENOENT; - pfil_add_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet); - pfil_add_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet); + (void)pfil_add_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, + pfh_inet); + (void)pfil_add_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, + pfh_inet); return 0; } @@ -450,8 +452,10 @@ ipfw_unhook(void) if (pfh_inet == NULL) return ENOENT; - pfil_remove_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet); - pfil_remove_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet); + (void)pfil_remove_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, + pfh_inet); + (void)pfil_remove_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, + pfh_inet); return 0; } @@ -466,8 +470,10 @@ ipfw6_hook(void) if (pfh_inet6 == NULL) return ENOENT; - pfil_add_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6); - pfil_add_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet6); + (void)pfil_add_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, + pfh_inet6); + (void)pfil_add_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, + pfh_inet6); return 0; } @@ -481,8 +487,10 @@ ipfw6_unhook(void) if (pfh_inet6 == NULL) return ENOENT; - pfil_remove_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6); - pfil_remove_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet6); + (void)pfil_remove_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, + pfh_inet6); + (void)pfil_remove_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, + pfh_inet6); return 0; } diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index c99c53e..4a169ff 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -1286,7 +1286,7 @@ ip_rtaddr(struct in_addr dst, u_int fibnum) sin->sin_family = AF_INET; sin->sin_len = sizeof(*sin); sin->sin_addr = dst; - in_rtalloc_ign(&sro, RTF_CLONING, fibnum); + in_rtalloc_ign(&sro, 0, fibnum); if (sro.ro_rt == NULL) return (NULL); @@ -1412,7 +1412,7 @@ ip_forward(struct mbuf *m, int srcrt) sin->sin_family = AF_INET; sin->sin_len = sizeof(*sin); sin->sin_addr = ip->ip_dst; - in_rtalloc_ign(&ro, RTF_CLONING, M_GETFIB(m)); + in_rtalloc_ign(&ro, 0, M_GETFIB(m)); rt = ro.ro_rt; diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index 03cf56f..6cda8aa 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -567,7 +567,6 @@ passout: * to avoid confusing lower layers. */ m->m_flags &= ~(M_PROTOFLAGS); - error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst, ro->ro_rt); goto done; diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c index 9b5a3f3..9fe0eca 100644 --- a/sys/netinet/raw_ip.c +++ b/sys/netinet/raw_ip.c @@ -280,7 +280,7 @@ rip_input(struct mbuf *m, int off) if (!prison_check_ip4(inp->inp_cred, &ip->ip_dst)) continue; } - if (last) { + if (last != NULL) { struct mbuf *n; n = m_copy(m, 0, (int)M_COPYALL); @@ -310,7 +310,7 @@ rip_input(struct mbuf *m, int off) if (!prison_check_ip4(inp->inp_cred, &ip->ip_dst)) continue; } - if (last) { + if (last != NULL) { struct mbuf *n; n = m_copy(m, 0, (int)M_COPYALL); @@ -964,6 +964,7 @@ rip_pcblist(SYSCTL_HANDLER_ARGS) INP_RLOCK(inp); if (inp->inp_gencnt <= gencnt) { struct xinpcb xi; + bzero(&xi, sizeof(xi)); xi.xi_len = sizeof xi; /* XXX should avoid extra copy */ diff --git a/sys/netinet/tcp_hostcache.c b/sys/netinet/tcp_hostcache.c index 7c76160..c9b5b8c 100644 --- a/sys/netinet/tcp_hostcache.c +++ b/sys/netinet/tcp_hostcache.c @@ -249,7 +249,7 @@ tcp_hc_lookup(struct in_conninfo *inc) /* * Hash the foreign ip address. */ - if (inc->inc_isipv6) + if (inc->inc_flags & INC_ISIPV6) hash = HOSTCACHE_HASH6(&inc->inc6_faddr); else hash = HOSTCACHE_HASH(&inc->inc_faddr); @@ -267,7 +267,7 @@ tcp_hc_lookup(struct in_conninfo *inc) * Iterate through entries in bucket row looking for a match. */ TAILQ_FOREACH(hc_entry, &hc_head->hch_bucket, rmx_q) { - if (inc->inc_isipv6) { + if (inc->inc_flags & INC_ISIPV6) { if (memcmp(&inc->inc6_faddr, &hc_entry->ip6, sizeof(inc->inc6_faddr)) == 0) return hc_entry; @@ -305,7 +305,7 @@ tcp_hc_insert(struct in_conninfo *inc) /* * Hash the foreign ip address. */ - if (inc->inc_isipv6) + if (inc->inc_flags & INC_ISIPV6) hash = HOSTCACHE_HASH6(&inc->inc6_faddr); else hash = HOSTCACHE_HASH(&inc->inc_faddr); @@ -360,7 +360,7 @@ tcp_hc_insert(struct in_conninfo *inc) * Initialize basic information of hostcache entry. */ bzero(hc_entry, sizeof(*hc_entry)); - if (inc->inc_isipv6) + if (inc->inc_flags & INC_ISIPV6) bcopy(&inc->inc6_faddr, &hc_entry->ip6, sizeof(hc_entry->ip6)); else hc_entry->ip4 = inc->inc_faddr; diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index dfb2aff..30b3fde 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -737,9 +737,9 @@ findpcb: "tp not listening", __func__)); bzero(&inc, sizeof(inc)); - inc.inc_isipv6 = isipv6; #ifdef INET6 if (isipv6) { + inc.inc_flags |= INC_ISIPV6; inc.inc6_faddr = ip6->ip6_src; inc.inc6_laddr = ip6->ip6_dst; } else @@ -3338,14 +3338,11 @@ tcp_mssopt(struct in_conninfo *inc) u_long maxmtu = 0; u_long thcmtu = 0; size_t min_protoh; -#ifdef INET6 - int isipv6 = inc->inc_isipv6 ? 1 : 0; -#endif KASSERT(inc != NULL, ("tcp_mssopt with NULL in_conninfo pointer")); #ifdef INET6 - if (isipv6) { + if (inc->inc_flags & INC_ISIPV6) { mss = V_tcp_v6mssdflt; maxmtu = tcp_maxmtu6(inc, NULL); thcmtu = tcp_hc_getmtu(inc); /* IPv4 and IPv6 */ diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index 207d37a..9cb941a 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -434,7 +434,7 @@ tcpip_fillheaders(struct inpcb *inp, void *ip_ptr, void *tcp_ptr) ip6 = (struct ip6_hdr *)ip_ptr; ip6->ip6_flow = (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) | - (inp->in6p_flowinfo & IPV6_FLOWINFO_MASK); + (inp->inp_flow & IPV6_FLOWINFO_MASK); ip6->ip6_vfc = (ip6->ip6_vfc & ~IPV6_VERSION_MASK) | (IPV6_VERSION & IPV6_VERSION_MASK); ip6->ip6_nxt = IPPROTO_TCP; @@ -1306,7 +1306,6 @@ tcp_ctlinput(int cmd, struct sockaddr *sa, void *vip) * value (if given) and then notify. */ bzero(&inc, sizeof(inc)); - inc.inc_flags = 0; /* IPv4 */ inc.inc_faddr = faddr; inc.inc_fibnum = inp->inp_inc.inc_fibnum; @@ -1343,13 +1342,11 @@ tcp_ctlinput(int cmd, struct sockaddr *sa, void *vip) if (inp != NULL) INP_WUNLOCK(inp); } else { + bzero(&inc, sizeof(inc)); inc.inc_fport = th->th_dport; inc.inc_lport = th->th_sport; inc.inc_faddr = faddr; inc.inc_laddr = ip->ip_src; -#ifdef INET6 - inc.inc_isipv6 = 0; -#endif syncache_unreach(&inc, th); } INP_INFO_WUNLOCK(&V_tcbinfo); @@ -1419,11 +1416,12 @@ tcp6_ctlinput(int cmd, struct sockaddr *sa, void *d) (struct sockaddr *)ip6cp->ip6c_src, th.th_sport, cmd, NULL, notify); + bzero(&inc, sizeof(inc)); inc.inc_fport = th.th_dport; inc.inc_lport = th.th_sport; inc.inc6_faddr = ((struct sockaddr_in6 *)sa)->sin6_addr; inc.inc6_laddr = ip6cp->ip6c_src->sin6_addr; - inc.inc_isipv6 = 1; + inc.inc_flags |= INC_ISIPV6; INP_INFO_WLOCK(&V_tcbinfo); syncache_unreach(&inc, &th); INP_INFO_WUNLOCK(&V_tcbinfo); @@ -1486,13 +1484,13 @@ tcp6_ctlinput(int cmd, struct sockaddr *sa, void *d) static u_char isn_secret[32]; static int isn_last_reseed; static u_int32_t isn_offset, isn_offset_old; -static MD5_CTX isn_ctx; #endif tcp_seq tcp_new_isn(struct tcpcb *tp) { INIT_VNET_INET(tp->t_vnet); + MD5_CTX isn_ctx; u_int32_t md5_buffer[4]; tcp_seq new_isn; @@ -1508,25 +1506,25 @@ tcp_new_isn(struct tcpcb *tp) } /* Compute the md5 hash and return the ISN. */ - MD5Init(&V_isn_ctx); - MD5Update(&V_isn_ctx, (u_char *) &tp->t_inpcb->inp_fport, sizeof(u_short)); - MD5Update(&V_isn_ctx, (u_char *) &tp->t_inpcb->inp_lport, sizeof(u_short)); + MD5Init(&isn_ctx); + MD5Update(&isn_ctx, (u_char *) &tp->t_inpcb->inp_fport, sizeof(u_short)); + MD5Update(&isn_ctx, (u_char *) &tp->t_inpcb->inp_lport, sizeof(u_short)); #ifdef INET6 if ((tp->t_inpcb->inp_vflag & INP_IPV6) != 0) { - MD5Update(&V_isn_ctx, (u_char *) &tp->t_inpcb->in6p_faddr, + MD5Update(&isn_ctx, (u_char *) &tp->t_inpcb->in6p_faddr, sizeof(struct in6_addr)); - MD5Update(&V_isn_ctx, (u_char *) &tp->t_inpcb->in6p_laddr, + MD5Update(&isn_ctx, (u_char *) &tp->t_inpcb->in6p_laddr, sizeof(struct in6_addr)); } else #endif { - MD5Update(&V_isn_ctx, (u_char *) &tp->t_inpcb->inp_faddr, + MD5Update(&isn_ctx, (u_char *) &tp->t_inpcb->inp_faddr, sizeof(struct in_addr)); - MD5Update(&V_isn_ctx, (u_char *) &tp->t_inpcb->inp_laddr, + MD5Update(&isn_ctx, (u_char *) &tp->t_inpcb->inp_laddr, sizeof(struct in_addr)); } - MD5Update(&V_isn_ctx, (u_char *) &V_isn_secret, sizeof(V_isn_secret)); - MD5Final((u_char *) &md5_buffer, &V_isn_ctx); + MD5Update(&isn_ctx, (u_char *) &V_isn_secret, sizeof(V_isn_secret)); + MD5Final((u_char *) &md5_buffer, &isn_ctx); new_isn = (tcp_seq) md5_buffer[0]; V_isn_offset += ISN_STATIC_INCREMENT + (arc4random() & ISN_RANDOM_INCREMENT); @@ -1659,7 +1657,7 @@ tcp_maxmtu(struct in_conninfo *inc, int *flags) dst->sin_family = AF_INET; dst->sin_len = sizeof(*dst); dst->sin_addr = inc->inc_faddr; - in_rtalloc_ign(&sro, RTF_CLONING, inc->inc_fibnum); + in_rtalloc_ign(&sro, 0, inc->inc_fibnum); } if (sro.ro_rt != NULL) { ifp = sro.ro_rt->rt_ifp; @@ -1694,7 +1692,7 @@ tcp_maxmtu6(struct in_conninfo *inc, int *flags) sro6.ro_dst.sin6_family = AF_INET6; sro6.ro_dst.sin6_len = sizeof(struct sockaddr_in6); sro6.ro_dst.sin6_addr = inc->inc6_faddr; - rtalloc_ign((struct route *)&sro6, RTF_CLONING); + rtalloc_ign((struct route *)&sro6, 0); } if (sro6.ro_rt != NULL) { ifp = sro6.ro_rt->rt_ifp; @@ -2263,7 +2261,7 @@ tcp_log_addrs(struct in_conninfo *inc, struct tcphdr *th, void *ip4hdr, strcat(s, "TCP: ["); sp = s + strlen(s); - if (inc && inc->inc_isipv6 == 0) { + if (inc && ((inc->inc_flags & INC_ISIPV6) == 0)) { inet_ntoa_r(inc->inc_faddr, sp); sp = s + strlen(s); sprintf(sp, "]:%i to [", ntohs(inc->inc_fport)); diff --git a/sys/netinet/tcp_syncache.c b/sys/netinet/tcp_syncache.c index 838fd52..18fab28 100644 --- a/sys/netinet/tcp_syncache.c +++ b/sys/netinet/tcp_syncache.c @@ -430,7 +430,7 @@ syncache_lookup(struct in_conninfo *inc, struct syncache_head **schp) struct syncache_head *sch; #ifdef INET6 - if (inc->inc_isipv6) { + if (inc->inc_flags & INC_ISIPV6) { sch = &V_tcp_syncache.hashbase[ SYNCACHE_HASH6(inc, V_tcp_syncache.hashmask)]; *schp = sch; @@ -454,7 +454,7 @@ syncache_lookup(struct in_conninfo *inc, struct syncache_head **schp) /* Circle through bucket row to find matching entry. */ TAILQ_FOREACH(sc, &sch->sch_bucket, sc_hash) { #ifdef INET6 - if (sc->sc_inc.inc_isipv6) + if (sc->sc_inc.inc_flags & INC_ISIPV6) continue; #endif if (ENDPTS_EQ(&inc->inc_ie, &sc->sc_inc.inc_ie)) @@ -643,9 +643,9 @@ syncache_socket(struct syncache *sc, struct socket *lso, struct mbuf *m) INP_WLOCK(inp); /* Insert new socket into PCB hash list. */ - inp->inp_inc.inc_isipv6 = sc->sc_inc.inc_isipv6; + inp->inp_inc.inc_flags = sc->sc_inc.inc_flags; #ifdef INET6 - if (sc->sc_inc.inc_isipv6) { + if (sc->sc_inc.inc_flags & INC_ISIPV6) { inp->in6p_laddr = sc->sc_inc.inc6_laddr; } else { inp->inp_vflag &= ~INP_IPV6; @@ -662,7 +662,7 @@ syncache_socket(struct syncache *sc, struct socket *lso, struct mbuf *m) * put the PCB on the hash lists. */ #ifdef INET6 - if (sc->sc_inc.inc_isipv6) + if (sc->sc_inc.inc_flags & INC_ISIPV6) inp->in6p_laddr = in6addr_any; else #endif @@ -676,7 +676,7 @@ syncache_socket(struct syncache *sc, struct socket *lso, struct mbuf *m) printf("syncache_socket: could not copy policy\n"); #endif #ifdef INET6 - if (sc->sc_inc.inc_isipv6) { + if (sc->sc_inc.inc_flags & INC_ISIPV6) { struct inpcb *oinp = sotoinpcb(lso); struct in6_addr laddr6; struct sockaddr_in6 sin6; @@ -708,8 +708,8 @@ syncache_socket(struct syncache *sc, struct socket *lso, struct mbuf *m) goto abort; } /* Override flowlabel from in6_pcbconnect. */ - inp->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK; - inp->in6p_flowinfo |= sc->sc_flowlabel; + inp->inp_flow &= ~IPV6_FLOWLABEL_MASK; + inp->inp_flow |= sc->sc_flowlabel; } else #endif { @@ -993,8 +993,8 @@ _syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th, cred = crhold(so->so_cred); #ifdef INET6 - if (inc->inc_isipv6 && - (inp->in6p_flags & IN6P_AUTOFLOWLABEL)) + if ((inc->inc_flags & INC_ISIPV6) && + (inp->inp_flags & IN6P_AUTOFLOWLABEL)) autoflowlabel = 1; #endif ip_ttl = inp->inp_ip_ttl; @@ -1022,7 +1022,7 @@ _syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th, * Remember the IP options, if any. */ #ifdef INET6 - if (!inc->inc_isipv6) + if (!(inc->inc_flags & INC_ISIPV6)) #endif ipopts = (m) ? ip_srcroute(m) : NULL; @@ -1123,10 +1123,11 @@ _syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th, sc->sc_cred = cred; cred = NULL; sc->sc_ipopts = ipopts; + /* XXX-BZ this fib assignment is just useless. */ sc->sc_inc.inc_fibnum = inp->inp_inc.inc_fibnum; bcopy(inc, &sc->sc_inc, sizeof(struct in_conninfo)); #ifdef INET6 - if (!inc->inc_isipv6) + if (!(inc->inc_flags & INC_ISIPV6)) #endif { sc->sc_ip_tos = ip_tos; @@ -1272,7 +1273,7 @@ syncache_respond(struct syncache *sc) hlen = #ifdef INET6 - (sc->sc_inc.inc_isipv6) ? sizeof(struct ip6_hdr) : + (sc->sc_inc.inc_flags & INC_ISIPV6) ? sizeof(struct ip6_hdr) : #endif sizeof(struct ip); tlen = hlen + sizeof(struct tcphdr); @@ -1299,7 +1300,7 @@ syncache_respond(struct syncache *sc) m->m_pkthdr.rcvif = NULL; #ifdef INET6 - if (sc->sc_inc.inc_isipv6) { + if (sc->sc_inc.inc_flags & INC_ISIPV6) { ip6 = mtod(m, struct ip6_hdr *); ip6->ip6_vfc = IPV6_VERSION; ip6->ip6_nxt = IPPROTO_TCP; @@ -1390,7 +1391,7 @@ syncache_respond(struct syncache *sc) to.to_signature, IPSEC_DIR_OUTBOUND); #endif #ifdef INET6 - if (sc->sc_inc.inc_isipv6) + if (sc->sc_inc.inc_flags & INC_ISIPV6) ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) + optlen); else #endif @@ -1399,7 +1400,7 @@ syncache_respond(struct syncache *sc) optlen = 0; #ifdef INET6 - if (sc->sc_inc.inc_isipv6) { + if (sc->sc_inc.inc_flags & INC_ISIPV6) { th->th_sum = 0; th->th_sum = in6_cksum(m, IPPROTO_TCP, hlen, tlen + optlen - hlen); @@ -1653,8 +1654,8 @@ syncookie_lookup(struct in_conninfo *inc, struct syncache_head *sch, sc->sc_iss = ack; #ifdef INET6 - if (inc->inc_isipv6) { - if (sotoinpcb(so)->in6p_flags & IN6P_AUTOFLOWLABEL) + if (inc->inc_flags & INC_ISIPV6) { + if (sotoinpcb(so)->inp_flags & IN6P_AUTOFLOWLABEL) sc->sc_flowlabel = md5_buffer[1] & IPV6_FLOWLABEL_MASK; } else #endif @@ -1743,7 +1744,7 @@ syncache_pcblist(struct sysctl_req *req, int max_pcbs, int *pcbs_exported) continue; bzero(&xt, sizeof(xt)); xt.xt_len = sizeof(xt); - if (sc->sc_inc.inc_isipv6) + if (sc->sc_inc.inc_flags & INC_ISIPV6) xt.xt_inp.inp_vflag = INP_IPV6; else xt.xt_inp.inp_vflag = INP_IPV4; diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c index 37fafa0..3138547 100644 --- a/sys/netinet/tcp_timewait.c +++ b/sys/netinet/tcp_timewait.c @@ -538,7 +538,7 @@ tcp_twrespond(struct tcptw *tw, int flags) struct tcpopt to; #ifdef INET6 struct ip6_hdr *ip6 = NULL; - int isipv6 = inp->inp_inc.inc_isipv6; + int isipv6 = inp->inp_inc.inc_flags & INC_ISIPV6; #endif INP_WLOCK_ASSERT(inp); diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c index 2011dff..f6dcae1 100644 --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -519,7 +519,7 @@ tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td) } inp->inp_vflag &= ~INP_IPV4; inp->inp_vflag |= INP_IPV6; - inp->inp_inc.inc_isipv6 = 1; + inp->inp_inc.inc_flags |= INC_ISIPV6; if (prison_remote_ip6(td->td_ucred, &sin6p->sin6_addr) != 0) { error = EINVAL; goto out; @@ -1167,9 +1167,9 @@ tcp6_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td) inp->in6p_faddr = sin6->sin6_addr; inp->inp_fport = sin6->sin6_port; /* update flowinfo - draft-itojun-ipv6-flowlabel-api-00 */ - inp->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK; - if (inp->in6p_flags & IN6P_AUTOFLOWLABEL) - inp->in6p_flowinfo |= + inp->inp_flow &= ~IPV6_FLOWLABEL_MASK; + if (inp->inp_flags & IN6P_AUTOFLOWLABEL) + inp->inp_flow |= (htonl(ip6_randomflowlabel()) & IPV6_FLOWLABEL_MASK); in_pcbrehash(inp); diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h index ed872b9..a4392cb 100644 --- a/sys/netinet/tcp_var.h +++ b/sys/netinet/tcp_var.h @@ -38,7 +38,9 @@ /* * Kernel variables for tcp. */ +#ifdef VIMAGE_GLOBALS extern int tcp_do_rfc1323; +#endif /* TCP segment queue entry */ struct tseg_qent { @@ -48,7 +50,9 @@ struct tseg_qent { struct mbuf *tqe_m; /* mbuf contains packet */ }; LIST_HEAD(tsegqe_head, tseg_qent); +#ifdef VIMAGE_GLOBALS extern int tcp_reass_qsize; +#endif extern struct uma_zone *tcp_reass_zone; struct sackblk { diff --git a/sys/netinet/vinet.h b/sys/netinet/vinet.h index 65ccfa4..449334e 100644 --- a/sys/netinet/vinet.h +++ b/sys/netinet/vinet.h @@ -142,7 +142,6 @@ struct vnet_inet { int _isn_last_reseed; u_int32_t _isn_offset; u_int32_t _isn_offset_old; - MD5_CTX _isn_ctx; struct inpcbhead _udb; struct inpcbinfo _udbinfo; @@ -265,7 +264,6 @@ extern struct vnet_inet vnet_inet_0; #define V_ipsendredirects VNET_INET(ipsendredirects) #define V_ipstat VNET_INET(ipstat) #define V_ipstealth VNET_INET(ipstealth) -#define V_isn_ctx VNET_INET(isn_ctx) #define V_isn_last_reseed VNET_INET(isn_last_reseed) #define V_isn_offset VNET_INET(isn_offset) #define V_isn_offset_old VNET_INET(isn_offset_old) diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c index 59bc95a..7bdd8a8 100644 --- a/sys/netinet6/icmp6.c +++ b/sys/netinet6/icmp6.c @@ -85,6 +85,7 @@ __FBSDID("$FreeBSD$"); #include <net/if.h> #include <net/if_dl.h> +#include <net/if_llatbl.h> #include <net/if_types.h> #include <net/route.h> #include <net/vnet.h> @@ -1147,7 +1148,7 @@ icmp6_mtudisc_update(struct ip6ctlparam *ip6cp, int validated) mtu = IPV6_MMTU - 8; bzero(&inc, sizeof(inc)); - inc.inc_flags = 1; /* IPv6 */ + inc.inc_flags |= INC_ISIPV6; inc.inc6_faddr = *dst; if (in6_setscope(&inc.inc6_faddr, m->m_pkthdr.rcvif, NULL)) return; @@ -1898,8 +1899,8 @@ icmp6_rip6_input(struct mbuf **mp, int off) INIT_VNET_INET6(curvnet); struct mbuf *m = *mp; struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); - struct in6pcb *in6p; - struct in6pcb *last = NULL; + struct inpcb *in6p; + struct inpcb *last = NULL; struct sockaddr_in6 fromsa; struct icmp6_hdr *icmp6; struct mbuf *opts = NULL; @@ -1932,7 +1933,7 @@ icmp6_rip6_input(struct mbuf **mp, int off) LIST_FOREACH(in6p, &V_ripcb, inp_list) { if ((in6p->inp_vflag & INP_IPV6) == 0) continue; - if (in6p->in6p_ip6_nxt != IPPROTO_ICMPV6) + if (in6p->inp_ip_p != IPPROTO_ICMPV6) continue; if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) && !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst)) @@ -1946,7 +1947,7 @@ icmp6_rip6_input(struct mbuf **mp, int off) INP_RUNLOCK(in6p); continue; } - if (last) { + if (last != NULL) { struct mbuf *n = NULL; /* @@ -1982,13 +1983,13 @@ icmp6_rip6_input(struct mbuf **mp, int off) } if (n != NULL || (n = m_copy(m, 0, (int)M_COPYALL)) != NULL) { - if (last->in6p_flags & IN6P_CONTROLOPTS) + if (last->inp_flags & INP_CONTROLOPTS) ip6_savecontrol(last, n, &opts); /* strip intermediate headers */ m_adj(n, off); - SOCKBUF_LOCK(&last->in6p_socket->so_rcv); + SOCKBUF_LOCK(&last->inp_socket->so_rcv); if (sbappendaddr_locked( - &last->in6p_socket->so_rcv, + &last->inp_socket->so_rcv, (struct sockaddr *)&fromsa, n, opts) == 0) { /* should notify about lost packet */ @@ -1997,9 +1998,9 @@ icmp6_rip6_input(struct mbuf **mp, int off) m_freem(opts); } SOCKBUF_UNLOCK( - &last->in6p_socket->so_rcv); + &last->inp_socket->so_rcv); } else - sorwakeup_locked(last->in6p_socket); + sorwakeup_locked(last->inp_socket); opts = NULL; } INP_RUNLOCK(last); @@ -2007,8 +2008,8 @@ icmp6_rip6_input(struct mbuf **mp, int off) last = in6p; } INP_INFO_RUNLOCK(&V_ripcbinfo); - if (last) { - if (last->in6p_flags & IN6P_CONTROLOPTS) + if (last != NULL) { + if (last->inp_flags & INP_CONTROLOPTS) ip6_savecontrol(last, m, &opts); /* strip intermediate headers */ m_adj(m, off); @@ -2032,15 +2033,15 @@ icmp6_rip6_input(struct mbuf **mp, int off) } } } - SOCKBUF_LOCK(&last->in6p_socket->so_rcv); - if (sbappendaddr_locked(&last->in6p_socket->so_rcv, + SOCKBUF_LOCK(&last->inp_socket->so_rcv); + if (sbappendaddr_locked(&last->inp_socket->so_rcv, (struct sockaddr *)&fromsa, m, opts) == 0) { m_freem(m); if (opts) m_freem(opts); - SOCKBUF_UNLOCK(&last->in6p_socket->so_rcv); + SOCKBUF_UNLOCK(&last->inp_socket->so_rcv); } else - sorwakeup_locked(last->in6p_socket); + sorwakeup_locked(last->inp_socket); INP_RUNLOCK(last); } else { m_freem(m); @@ -2452,6 +2453,7 @@ icmp6_redirect_output(struct mbuf *m0, struct rtentry *rt) struct mbuf *m = NULL; /* newly allocated one */ struct ip6_hdr *ip6; /* m as struct ip6_hdr */ struct nd_redirect *nd_rd; + struct llentry *ln = NULL; size_t maxlen; u_char *p; struct ifnet *outif = NULL; @@ -2573,35 +2575,35 @@ icmp6_redirect_output(struct mbuf *m0, struct rtentry *rt) { /* target lladdr option */ - struct rtentry *rt_router = NULL; int len; - struct sockaddr_dl *sdl; struct nd_opt_hdr *nd_opt; char *lladdr; - rt_router = nd6_lookup(router_ll6, 0, ifp); - if (!rt_router) + IF_AFDATA_LOCK(ifp); + ln = nd6_lookup(router_ll6, 0, ifp); + IF_AFDATA_UNLOCK(ifp); + if (ln == NULL) goto nolladdropt; + len = sizeof(*nd_opt) + ifp->if_addrlen; len = (len + 7) & ~7; /* round by 8 */ /* safety check */ - if (len + (p - (u_char *)ip6) > maxlen) + if (len + (p - (u_char *)ip6) > maxlen) goto nolladdropt; - if (!(rt_router->rt_flags & RTF_GATEWAY) && - (rt_router->rt_flags & RTF_LLINFO) && - (rt_router->rt_gateway->sa_family == AF_LINK) && - (sdl = (struct sockaddr_dl *)rt_router->rt_gateway) && - sdl->sdl_alen) { + + if (ln->la_flags & LLE_VALID) { nd_opt = (struct nd_opt_hdr *)p; nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR; nd_opt->nd_opt_len = len >> 3; lladdr = (char *)(nd_opt + 1); - bcopy(LLADDR(sdl), lladdr, ifp->if_addrlen); + bcopy(&ln->ll_addr, lladdr, ifp->if_addrlen); p += len; } } -nolladdropt:; - +nolladdropt: + if (ln != NULL) + LLE_RUNLOCK(ln); + m->m_pkthdr.len = m->m_len = p - (u_char *)ip6; /* just to be safe */ diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c index c784845..6ba852c 100644 --- a/sys/netinet6/in6.c +++ b/sys/netinet6/in6.c @@ -88,6 +88,7 @@ __FBSDID("$FreeBSD$"); #include <netinet/in.h> #include <netinet/in_var.h> +#include <net/if_llatbl.h> #include <netinet/if_ether.h> #include <netinet/in_systm.h> #include <netinet/ip.h> @@ -135,152 +136,7 @@ static void in6_unlink_ifa(struct in6_ifaddr *, struct ifnet *); struct in6_multihead in6_multihead; /* XXX BSS initialization */ int (*faithprefix_p)(struct in6_addr *); -/* - * Subroutine for in6_ifaddloop() and in6_ifremloop(). - * This routine does actual work. - */ -static void -in6_ifloop_request(int cmd, struct ifaddr *ifa) -{ - struct sockaddr_in6 all1_sa; - struct rtentry *nrt = NULL; - int e; - char ip6buf[INET6_ADDRSTRLEN]; - - bzero(&all1_sa, sizeof(all1_sa)); - all1_sa.sin6_family = AF_INET6; - all1_sa.sin6_len = sizeof(struct sockaddr_in6); - all1_sa.sin6_addr = in6mask128; - - /* - * We specify the address itself as the gateway, and set the - * RTF_LLINFO flag, so that the corresponding host route would have - * the flag, and thus applications that assume traditional behavior - * would be happy. Note that we assume the caller of the function - * (probably implicitly) set nd6_rtrequest() to ifa->ifa_rtrequest, - * which changes the outgoing interface to the loopback interface. - */ - e = rtrequest(cmd, ifa->ifa_addr, ifa->ifa_addr, - (struct sockaddr *)&all1_sa, RTF_UP|RTF_HOST|RTF_LLINFO, &nrt); - if (e != 0) { - /* XXX need more descriptive message */ - - log(LOG_ERR, "in6_ifloop_request: " - "%s operation failed for %s (errno=%d)\n", - cmd == RTM_ADD ? "ADD" : "DELETE", - ip6_sprintf(ip6buf, - &((struct in6_ifaddr *)ifa)->ia_addr.sin6_addr), e); - } - - /* - * Report the addition/removal of the address to the routing socket. - * XXX: since we called rtinit for a p2p interface with a destination, - * we end up reporting twice in such a case. Should we rather - * omit the second report? - */ - if (nrt) { - RT_LOCK(nrt); - /* - * Make sure rt_ifa be equal to IFA, the second argument of - * the function. We need this because when we refer to - * rt_ifa->ia6_flags in ip6_input, we assume that the rt_ifa - * points to the address instead of the loopback address. - */ - if (cmd == RTM_ADD && ifa != nrt->rt_ifa) { - IFAFREE(nrt->rt_ifa); - IFAREF(ifa); - nrt->rt_ifa = ifa; - } - - rt_newaddrmsg(cmd, ifa, e, nrt); - if (cmd == RTM_DELETE) - RTFREE_LOCKED(nrt); - else { - /* the cmd must be RTM_ADD here */ - RT_REMREF(nrt); - RT_UNLOCK(nrt); - } - } -} - -/* - * Add ownaddr as loopback rtentry. We previously add the route only if - * necessary (ex. on a p2p link). However, since we now manage addresses - * separately from prefixes, we should always add the route. We can't - * rely on the cloning mechanism from the corresponding interface route - * any more. - */ -void -in6_ifaddloop(struct ifaddr *ifa) -{ - struct rtentry *rt; - int need_loop; - - /* If there is no loopback entry, allocate one. */ - rt = rtalloc1(ifa->ifa_addr, 0, 0); - need_loop = (rt == NULL || (rt->rt_flags & RTF_HOST) == 0 || - (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0); - if (rt) - RTFREE_LOCKED(rt); - if (need_loop) - in6_ifloop_request(RTM_ADD, ifa); -} - -/* - * Remove loopback rtentry of ownaddr generated by in6_ifaddloop(), - * if it exists. - */ -void -in6_ifremloop(struct ifaddr *ifa) -{ - INIT_VNET_INET6(curvnet); - struct in6_ifaddr *ia; - struct rtentry *rt; - int ia_count = 0; - - /* - * Some of BSD variants do not remove cloned routes - * from an interface direct route, when removing the direct route - * (see comments in net/net_osdep.h). Even for variants that do remove - * cloned routes, they could fail to remove the cloned routes when - * we handle multple addresses that share a common prefix. - * So, we should remove the route corresponding to the deleted address. - */ - /* - * Delete the entry only if exact one ifa exists. More than one ifa - * can exist if we assign a same single address to multiple - * (probably p2p) interfaces. - * XXX: we should avoid such a configuration in IPv6... - */ - for (ia = V_in6_ifaddr; ia; ia = ia->ia_next) { - if (IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa), &ia->ia_addr.sin6_addr)) { - ia_count++; - if (ia_count > 1) - break; - } - } - - if (ia_count == 1) { - /* - * Before deleting, check if a corresponding loopbacked host - * route surely exists. With this check, we can avoid to - * delete an interface direct route whose destination is same - * as the address being removed. This can happen when removing - * a subnet-router anycast address on an interface attahced - * to a shared medium. - */ - rt = rtalloc1(ifa->ifa_addr, 0, 0); - if (rt != NULL) { - if ((rt->rt_flags & RTF_HOST) != 0 && - (rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0) { - RTFREE_LOCKED(rt); - in6_ifloop_request(RTM_DELETE, ifa); - } else - RT_UNLOCK(rt); - } - } -} int in6_mask2len(struct in6_addr *mask, u_char *lim0) @@ -1131,10 +987,9 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra, } } if (!rt) { - /* XXX: we need RTF_CLONING to fake nd6_rtrequest */ error = rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr, (struct sockaddr *)&ia->ia_addr, - (struct sockaddr *)&mltmask, RTF_UP | RTF_CLONING, + (struct sockaddr *)&mltmask, RTF_UP, (struct rtentry **)0); if (error) goto cleanup; @@ -1208,7 +1063,7 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra, if (!rt) { error = rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr, (struct sockaddr *)&ia->ia_addr, - (struct sockaddr *)&mltmask, RTF_UP | RTF_CLONING, + (struct sockaddr *)&mltmask, RTF_UP, (struct rtentry **)0); if (error) goto cleanup; @@ -1287,34 +1142,16 @@ in6_purgeaddr(struct ifaddr *ifa) { struct ifnet *ifp = ifa->ifa_ifp; struct in6_ifaddr *ia = (struct in6_ifaddr *) ifa; - char ip6buf[INET6_ADDRSTRLEN]; struct in6_multi_mship *imm; /* stop DAD processing */ nd6_dad_stop(ifa); - /* - * delete route to the destination of the address being purged. - * The interface must be p2p or loopback in this case. - */ - if ((ia->ia_flags & IFA_ROUTE) != 0 && ia->ia_dstaddr.sin6_len != 0) { - int e; - - if ((e = rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST)) - != 0) { - log(LOG_ERR, "in6_purgeaddr: failed to remove " - "a route to the p2p destination: %s on %s, " - "errno=%d\n", - ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr), - if_name(ifp), e); - /* proceed anyway... */ - } else - ia->ia_flags &= ~IFA_ROUTE; - } - - /* Remove ownaddr's loopback rtentry, if it exists. */ - in6_ifremloop(&(ia->ia_ifa)); - + IF_AFDATA_LOCK(ifp); + lla_lookup(LLTABLE6(ifp), (LLE_DELETE | LLE_IFADDR), + (struct sockaddr *)&ia->ia_addr); + IF_AFDATA_UNLOCK(ifp); + /* * leave from multicast groups we have joined for the interface */ @@ -1688,26 +1525,15 @@ in6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia, /* we could do in(6)_socktrim here, but just omit it at this moment. */ - if (newhost) { - /* - * set the rtrequest function to create llinfo. It also - * adjust outgoing interface of the route for the local - * address when called via in6_ifaddloop() below. - */ - ia->ia_ifa.ifa_rtrequest = nd6_rtrequest; - } - /* * Special case: * If a new destination address is specified for a point-to-point * interface, install a route to the destination as an interface - * direct route. In addition, if the link is expected to have neighbor - * cache entries, specify RTF_LLINFO so that a cache entry for the - * destination address will be created. - * created + * direct route. * XXX: the logic below rejects assigning multiple addresses on a p2p * interface that share the same destination. */ +#if 0 /* QL - verify */ plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */ if (!(ia->ia_flags & IFA_ROUTE) && plen == 128 && ia->ia_dstaddr.sin6_family == AF_INET6) { @@ -1715,7 +1541,6 @@ in6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia, struct rtentry *rt = NULL, **rtp = NULL; if (nd6_need_cache(ifp) != 0) { - rtflags |= RTF_LLINFO; rtp = &rt; } @@ -1744,16 +1569,36 @@ in6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia, } ia->ia_flags |= IFA_ROUTE; } - if (plen < 128) { - /* - * The RTF_CLONING flag is necessary for in6_is_ifloop_auto(). - */ - ia->ia_ifa.ifa_flags |= RTF_CLONING; +#else + plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */ + if (!(ia->ia_flags & IFA_ROUTE) && plen == 128 && + ia->ia_dstaddr.sin6_family == AF_INET6) { + if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, + RTF_UP | RTF_HOST)) != 0) + return (error); + ia->ia_flags |= IFA_ROUTE; } +#endif /* Add ownaddr as loopback rtentry, if necessary (ex. on p2p link). */ - if (newhost) - in6_ifaddloop(&(ia->ia_ifa)); + if (newhost) { + struct llentry *ln; + + IF_AFDATA_LOCK(ifp); + ia->ia_ifa.ifa_rtrequest = NULL; + + /* XXX QL + * we need to report rt_newaddrmsg + */ + ln = lla_lookup(LLTABLE6(ifp), (LLE_CREATE | LLE_IFADDR | LLE_EXCLUSIVE), + (struct sockaddr *)&ia->ia_addr); + IF_AFDATA_UNLOCK(ifp); + if (ln != NULL) { + ln->la_expire = 0; /* for IPv6 this means permanent */ + ln->ln_state = ND6_LLINFO_REACHABLE; + LLE_WUNLOCK(ln); + } + } return (error); } @@ -2237,6 +2082,216 @@ in6_if2idlen(struct ifnet *ifp) } } +#include <sys/sysctl.h> + +struct in6_llentry { + struct llentry base; + struct sockaddr_in6 l3_addr6; +}; + +static struct llentry * +in6_lltable_new(const struct sockaddr *l3addr, u_int flags) +{ + struct in6_llentry *lle; + + lle = malloc(sizeof(struct in6_llentry), M_LLTABLE, + M_DONTWAIT | M_ZERO); + if (lle == NULL) /* NB: caller generates msg */ + return NULL; + + callout_init(&lle->base.ln_timer_ch, CALLOUT_MPSAFE); + lle->l3_addr6 = *(const struct sockaddr_in6 *)l3addr; + lle->base.lle_refcnt = 1; + LLE_LOCK_INIT(&lle->base); + return &lle->base; +} + +/* + * Deletes an address from the address table. + * This function is called by the timer functions + * such as arptimer() and nd6_llinfo_timer(), and + * the caller does the locking. + */ +static void +in6_lltable_free(struct lltable *llt, struct llentry *lle) +{ + LLE_WUNLOCK(lle); + LLE_LOCK_DESTROY(lle); + free(lle, M_LLTABLE); +} + +static int +in6_lltable_rtcheck(struct ifnet *ifp, const struct sockaddr *l3addr) +{ + struct rtentry *rt; + char ip6buf[INET6_ADDRSTRLEN]; + + KASSERT(l3addr->sa_family == AF_INET6, + ("sin_family %d", l3addr->sa_family)); + + /* XXX rtalloc1 should take a const param */ + rt = rtalloc1(__DECONST(struct sockaddr *, l3addr), 0, 0); + if (rt == NULL || (rt->rt_flags & RTF_GATEWAY) || rt->rt_ifp != ifp) { + struct ifaddr *ifa; + /* + * Create an ND6 cache for an IPv6 neighbor + * that is not covered by our own prefix. + */ + /* XXX ifaof_ifpforaddr should take a const param */ + ifa = ifaof_ifpforaddr(__DECONST(struct sockaddr *, l3addr), ifp); + if (ifa != NULL) { + if (rt != NULL) + rtfree(rt); + return 0; + } + log(LOG_INFO, "IPv6 address: \"%s\" is not on the network\n", + ip6_sprintf(ip6buf, &((const struct sockaddr_in6 *)l3addr)->sin6_addr)); + if (rt != NULL) + rtfree(rt); + return EINVAL; + } + rtfree(rt); + return 0; +} + +static struct llentry * +in6_lltable_lookup(struct lltable *llt, u_int flags, + const struct sockaddr *l3addr) +{ + const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)l3addr; + struct ifnet *ifp = llt->llt_ifp; + struct llentry *lle; + struct llentries *lleh; + u_int hashkey; + + IF_AFDATA_LOCK_ASSERT(ifp); + KASSERT(l3addr->sa_family == AF_INET6, + ("sin_family %d", l3addr->sa_family)); + + hashkey = sin6->sin6_addr.s6_addr32[3]; + lleh = &llt->lle_head[LLATBL_HASH(hashkey, LLTBL_HASHMASK)]; + LIST_FOREACH(lle, lleh, lle_next) { + if (lle->la_flags & LLE_DELETED) + continue; + if (bcmp(L3_ADDR(lle), l3addr, l3addr->sa_len) == 0) + break; + } + + if (lle == NULL) { + if (!(flags & LLE_CREATE)) + return (NULL); + /* + * A route that covers the given address must have + * been installed 1st because we are doing a resolution, + * verify this. + */ + if (!(flags & LLE_IFADDR) && + in6_lltable_rtcheck(ifp, l3addr) != 0) + return NULL; + + lle = in6_lltable_new(l3addr, flags); + if (lle == NULL) { + log(LOG_INFO, "lla_lookup: new lle malloc failed\n"); + return NULL; + } + lle->la_flags = flags & ~LLE_CREATE; + if ((flags & (LLE_CREATE | LLE_IFADDR)) == (LLE_CREATE | LLE_IFADDR)) { + bcopy(IF_LLADDR(ifp), &lle->ll_addr, ifp->if_addrlen); + lle->la_flags |= (LLE_VALID | LLE_STATIC); + } + + lle->lle_tbl = llt; + lle->lle_head = lleh; + LIST_INSERT_HEAD(lleh, lle, lle_next); + } else if (flags & LLE_DELETE) { + LLE_WLOCK(lle); + lle->la_flags = LLE_DELETED; + LLE_WUNLOCK(lle); +#ifdef DIAGNOSTICS + log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle); +#endif + lle = (void *)-1; + } + if (LLE_IS_VALID(lle)) { + if (flags & LLE_EXCLUSIVE) + LLE_WLOCK(lle); + else + LLE_RLOCK(lle); + } + return (lle); +} + +static int +in6_lltable_dump(struct lltable *llt, struct sysctl_req *wr) +{ + struct ifnet *ifp = llt->llt_ifp; + struct llentry *lle; + /* XXX stack use */ + struct { + struct rt_msghdr rtm; + struct sockaddr_in6 sin6; + /* + * ndp.c assumes that sdl is word aligned + */ +#ifdef __LP64__ + uint32_t pad; +#endif + struct sockaddr_dl sdl; + } ndpc; + int i, error; + + /* XXXXX + * current IFNET_RLOCK() is mapped to IFNET_WLOCK() + * so it is okay to use this ASSERT, change it when + * IFNET lock is finalized + */ + IFNET_WLOCK_ASSERT(); + + error = 0; + for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) { + LIST_FOREACH(lle, &llt->lle_head[i], lle_next) { + struct sockaddr_dl *sdl; + + /* skip deleted or invalid entries */ + if ((lle->la_flags & (LLE_DELETED|LLE_VALID)) != LLE_VALID) + continue; + /* + * produce a msg made of: + * struct rt_msghdr; + * struct sockaddr_in6 (IPv6) + * struct sockaddr_dl; + */ + bzero(&ndpc, sizeof(ndpc)); + ndpc.rtm.rtm_msglen = sizeof(ndpc); + ndpc.sin6.sin6_family = AF_INET6; + ndpc.sin6.sin6_len = sizeof(ndpc.sin6); + bcopy(L3_ADDR(lle), &ndpc.sin6, L3_ADDR_LEN(lle)); + + /* publish */ + if (lle->la_flags & LLE_PUB) + ndpc.rtm.rtm_flags |= RTF_ANNOUNCE; + + sdl = &ndpc.sdl; + sdl->sdl_family = AF_LINK; + sdl->sdl_len = sizeof(*sdl); + sdl->sdl_alen = ifp->if_addrlen; + sdl->sdl_index = ifp->if_index; + sdl->sdl_type = ifp->if_type; + bcopy(&lle->ll_addr, LLADDR(sdl), ifp->if_addrlen); + ndpc.rtm.rtm_rmx.rmx_expire = + lle->la_flags & LLE_STATIC ? 0 : lle->la_expire; + ndpc.rtm.rtm_flags |= RTF_HOST; + if (lle->la_flags & LLE_STATIC) + ndpc.rtm.rtm_flags |= RTF_STATIC; + ndpc.rtm.rtm_index = ifp->if_index; + error = SYSCTL_OUT(wr, &ndpc, sizeof(ndpc)); + if (error) + break; + } + } + return error; +} + void * in6_domifattach(struct ifnet *ifp) { @@ -2256,6 +2311,14 @@ in6_domifattach(struct ifnet *ifp) ext->nd_ifinfo = nd6_ifattach(ifp); ext->scope6_id = scope6_ifattach(ifp); + ext->lltable = lltable_init(ifp, AF_INET6); + if (ext->lltable != NULL) { + ext->lltable->llt_new = in6_lltable_new; + ext->lltable->llt_free = in6_lltable_free; + ext->lltable->llt_rtcheck = in6_lltable_rtcheck; + ext->lltable->llt_lookup = in6_lltable_lookup; + ext->lltable->llt_dump = in6_lltable_dump; + } return ext; } @@ -2266,6 +2329,7 @@ in6_domifdetach(struct ifnet *ifp, void *aux) scope6_ifdetach(ext->scope6_id); nd6_ifdetach(ext->nd_ifinfo); + lltable_free(ext->lltable); free(ext->in6_ifstat, M_IFADDR); free(ext->icmp6_ifstat, M_IFADDR); free(ext, M_IFADDR); diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c index ad19bee..753f45d 100644 --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -394,9 +394,9 @@ in6_pcbconnect(register struct inpcb *inp, struct sockaddr *nam, inp->in6p_faddr = sin6->sin6_addr; inp->inp_fport = sin6->sin6_port; /* update flowinfo - draft-itojun-ipv6-flowlabel-api-00 */ - inp->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK; - if (inp->in6p_flags & IN6P_AUTOFLOWLABEL) - inp->in6p_flowinfo |= + inp->inp_flow &= ~IPV6_FLOWLABEL_MASK; + if (inp->inp_flags & IN6P_AUTOFLOWLABEL) + inp->inp_flow |= (htonl(ip6_randomflowlabel()) & IPV6_FLOWLABEL_MASK); in_pcbrehash(inp); @@ -414,7 +414,7 @@ in6_pcbdisconnect(struct inpcb *inp) bzero((caddr_t)&inp->in6p_faddr, sizeof(inp->in6p_faddr)); inp->inp_fport = 0; /* clear flowinfo - draft-itojun-ipv6-flowlabel-api-00 */ - inp->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK; + inp->inp_flow &= ~IPV6_FLOWLABEL_MASK; in_pcbrehash(inp); } @@ -617,7 +617,7 @@ in6_pcbnotify(struct inpcbinfo *pcbinfo, struct sockaddr *dst, */ if (lport == 0 && fport == 0 && flowinfo && inp->inp_socket != NULL && - flowinfo == (inp->in6p_flowinfo & IPV6_FLOWLABEL_MASK) && + flowinfo == (inp->inp_flow & IPV6_FLOWLABEL_MASK) && IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, &sa6_src.sin6_addr)) goto do_notify; else if (!IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, @@ -736,7 +736,7 @@ in6_pcblookup_local(struct inpcbinfo *pcbinfo, struct in6_addr *laddr, void in6_pcbpurgeif0(struct inpcbinfo *pcbinfo, struct ifnet *ifp) { - struct in6pcb *in6p; + struct inpcb *in6p; struct ip6_moptions *im6o; struct in6_multi_mship *imm, *nimm; diff --git a/sys/netinet6/in6_rmx.c b/sys/netinet6/in6_rmx.c index 7e1a262..ade7649 100644 --- a/sys/netinet6/in6_rmx.c +++ b/sys/netinet6/in6_rmx.c @@ -124,6 +124,7 @@ in6_addroute(void *v_arg, void *n_arg, struct radix_node_head *head, struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)rt_key(rt); struct radix_node *ret; + RADIX_NODE_HEAD_WLOCK_ASSERT(head); if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) rt->rt_flags |= RTF_MULTICAST; @@ -153,27 +154,7 @@ in6_addroute(void *v_arg, void *n_arg, struct radix_node_head *head, rt->rt_rmx.rmx_mtu = IN6_LINKMTU(rt->rt_ifp); ret = rn_addroute(v_arg, n_arg, head, treenodes); - if (ret == NULL && rt->rt_flags & RTF_HOST) { - struct rtentry *rt2; - /* - * We are trying to add a host route, but can't. - * Find out if it is because of an - * ARP entry and delete it if so. - */ - rt2 = rtalloc1((struct sockaddr *)sin6, 0, RTF_CLONING); - if (rt2) { - if (rt2->rt_flags & RTF_LLINFO && - rt2->rt_flags & RTF_HOST && - rt2->rt_gateway && - rt2->rt_gateway->sa_family == AF_LINK) { - rtexpunge(rt2); - RTFREE_LOCKED(rt2); - ret = rn_addroute(v_arg, n_arg, head, - treenodes); - } else - RTFREE_LOCKED(rt2); - } - } else if (ret == NULL && rt->rt_flags & RTF_CLONING) { + if (ret == NULL) { struct rtentry *rt2; /* * We are trying to add a net route, but can't. @@ -187,10 +168,9 @@ in6_addroute(void *v_arg, void *n_arg, struct radix_node_head *head, * net route entry, 3ffe:0501:: -> if0. * This case should not raise an error. */ - rt2 = rtalloc1((struct sockaddr *)sin6, 0, RTF_CLONING); + rt2 = rtalloc1((struct sockaddr *)sin6, 0, RTF_RNH_LOCKED); if (rt2) { - if ((rt2->rt_flags & (RTF_CLONING|RTF_HOST|RTF_GATEWAY)) - == RTF_CLONING + if (((rt2->rt_flags & (RTF_HOST|RTF_GATEWAY)) == 0) && rt2->rt_gateway && rt2->rt_gateway->sa_family == AF_LINK && rt2->rt_ifp == rt->rt_ifp) { @@ -199,7 +179,7 @@ in6_addroute(void *v_arg, void *n_arg, struct radix_node_head *head, RTFREE_LOCKED(rt2); } } - return ret; + return (ret); } /* @@ -240,39 +220,6 @@ SYSCTL_V_INT(V_NET, vnet_inet6, _net_inet6_ip6, IPV6CTL_RTMAXCACHE, rtmaxcache, CTLFLAG_RW, rtq_toomany6 , 0, ""); -/* - * On last reference drop, mark the route as belong to us so that it can be - * timed out. - */ -static void -in6_clsroute(struct radix_node *rn, struct radix_node_head *head) -{ - INIT_VNET_INET6(curvnet); - struct rtentry *rt = (struct rtentry *)rn; - - RT_LOCK_ASSERT(rt); - - if (!(rt->rt_flags & RTF_UP)) - return; /* prophylactic measures */ - - if ((rt->rt_flags & (RTF_LLINFO | RTF_HOST)) != RTF_HOST) - return; - - if ((rt->rt_flags & (RTF_WASCLONED | RTPRF_OURS)) != RTF_WASCLONED) - return; - - /* - * As requested by David Greenman: - * If rtq_reallyold6 is 0, just delete the route without - * waiting for a timeout cycle to kill it. - */ - if (V_rtq_reallyold6 != 0) { - rt->rt_flags |= RTPRF_OURS; - rt->rt_rmx.rmx_expire = time_uptime + V_rtq_reallyold6; - } else { - rtexpunge(rt); - } -} struct rtqk_arg { struct radix_node_head *rnh; @@ -307,7 +254,7 @@ in6_rtqkill(struct radix_node *rn, void *rock) err = rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt), rt->rt_gateway, rt_mask(rt), - rt->rt_flags, 0); + rt->rt_flags|RTF_RNH_LOCKED, 0); if (err) { log(LOG_WARNING, "in6_rtqkill: error %d", err); } else { @@ -495,7 +442,6 @@ in6_inithead(void **head, int off) rnh = *head; rnh->rnh_addaddr = in6_addroute; rnh->rnh_matchaddr = in6_matroute; - rnh->rnh_close = in6_clsroute; callout_init(&V_rtq_timer6, CALLOUT_MPSAFE); in6_rtqtimo(rnh); /* kick off timeout first time */ callout_init(&V_rtq_mtutimer, CALLOUT_MPSAFE); diff --git a/sys/netinet6/in6_src.c b/sys/netinet6/in6_src.c index 4d7723a..ca65bc9 100644 --- a/sys/netinet6/in6_src.c +++ b/sys/netinet6/in6_src.c @@ -87,6 +87,7 @@ __FBSDID("$FreeBSD$"); #include <net/if.h> #include <net/route.h> +#include <net/if_llatbl.h> #ifdef RADIX_MPATH #include <net/radix_mpath.h> #endif @@ -131,7 +132,7 @@ int ip6_prefer_tempaddr; static int selectroute __P((struct sockaddr_in6 *, struct ip6_pktopts *, struct ip6_moptions *, struct route_in6 *, struct ifnet **, - struct rtentry **, int, int)); + struct rtentry **, int)); static int in6_selectif __P((struct sockaddr_in6 *, struct ip6_pktopts *, struct ip6_moptions *, struct route_in6 *ro, struct ifnet **)); @@ -479,8 +480,7 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, static int selectroute(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, struct ip6_moptions *mopts, struct route_in6 *ro, - struct ifnet **retifp, struct rtentry **retrt, int clone, - int norouteok) + struct ifnet **retifp, struct rtentry **retrt, int norouteok) { INIT_VNET_INET6(curvnet); int error = 0; @@ -536,9 +536,10 @@ selectroute(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, */ if (opts && opts->ip6po_nexthop) { struct route_in6 *ron; - + struct llentry *la; + sin6_next = satosin6(opts->ip6po_nexthop); - + /* at this moment, we only support AF_INET6 next hops */ if (sin6_next->sin6_family != AF_INET6) { error = EAFNOSUPPORT; /* or should we proceed? */ @@ -550,6 +551,36 @@ selectroute(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, * by that address must be a neighbor of the sending host. */ ron = &opts->ip6po_nextroute; + /* + * XXX what do we do here? + * PLZ to be fixing + */ + + + if (ron->ro_rt == NULL) { + rtalloc((struct route *)ron); /* multi path case? */ + if (ron->ro_rt == NULL) { + if (ron->ro_rt) { + RTFREE(ron->ro_rt); + ron->ro_rt = NULL; + } + error = EHOSTUNREACH; + goto done; + } + } + + rt = ron->ro_rt; + ifp = rt->rt_ifp; + IF_AFDATA_LOCK(ifp); + la = lla_lookup(LLTABLE6(ifp), 0, (struct sockaddr *)&sin6_next->sin6_addr); + IF_AFDATA_UNLOCK(ifp); + if (la != NULL) + LLE_RUNLOCK(la); + else { + error = EHOSTUNREACH; + goto done; + } +#if 0 if ((ron->ro_rt && (ron->ro_rt->rt_flags & (RTF_UP | RTF_LLINFO)) != (RTF_UP | RTF_LLINFO)) || @@ -573,16 +604,14 @@ selectroute(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, goto done; } } - rt = ron->ro_rt; - ifp = rt->rt_ifp; +#endif /* * When cloning is required, try to allocate a route to the * destination so that the caller can store path MTU * information. */ - if (!clone) - goto done; + goto done; } /* @@ -608,21 +637,17 @@ selectroute(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, *sa6 = *dstsock; sa6->sin6_scope_id = 0; - if (clone) { #ifdef RADIX_MPATH rtalloc_mpath((struct route *)ro, ntohl(sa6->sin6_addr.s6_addr32[3])); -#else - rtalloc((struct route *)ro); -#endif - } else { +#else ro->ro_rt = rtalloc1(&((struct route *)ro) - ->ro_dst, 0, 0UL); + ->ro_dst, 0, 0UL); if (ro->ro_rt) RT_UNLOCK(ro->ro_rt); - } +#endif } - + /* * do not care about the result if we have the nexthop * explicitly specified. @@ -693,7 +718,7 @@ in6_selectif(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, } if ((error = selectroute(dstsock, opts, mopts, ro, retifp, - &rt, 0, 1)) != 0) { + &rt, 1)) != 0) { if (ro == &sro && rt && rt == sro.ro_rt) RTFREE(rt); return (error); @@ -745,11 +770,11 @@ in6_selectif(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, int in6_selectroute(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, struct ip6_moptions *mopts, struct route_in6 *ro, - struct ifnet **retifp, struct rtentry **retrt, int clone) + struct ifnet **retifp, struct rtentry **retrt) { return (selectroute(dstsock, opts, mopts, ro, retifp, - retrt, clone, 0)); + retrt, 0)); } /* @@ -760,7 +785,7 @@ in6_selectroute(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, * 3. The system default hoplimit. */ int -in6_selecthlim(struct in6pcb *in6p, struct ifnet *ifp) +in6_selecthlim(struct inpcb *in6p, struct ifnet *ifp) { INIT_VNET_INET6(curvnet); diff --git a/sys/netinet6/in6_var.h b/sys/netinet6/in6_var.h index e906d7c..b5dba5e 100644 --- a/sys/netinet6/in6_var.h +++ b/sys/netinet6/in6_var.h @@ -88,13 +88,17 @@ struct in6_addrlifetime { struct nd_ifinfo; struct scope6_id; +struct lltable; struct in6_ifextra { struct in6_ifstat *in6_ifstat; struct icmp6_ifstat *icmp6_ifstat; struct nd_ifinfo *nd_ifinfo; struct scope6_id *scope6_id; + struct lltable *lltable; }; +#define LLTABLE6(ifp) (((struct in6_ifextra *)(ifp)->if_afdata[AF_INET6])->lltable) + struct in6_ifaddr { struct ifaddr ia_ifa; /* protocol-independent info */ #define ia_ifp ia_ifa.ifa_ifp @@ -474,6 +478,8 @@ struct in6_rrenumreq { extern struct in6_ifaddr *in6_ifaddr; extern struct icmp6stat icmp6stat; + +extern unsigned long in6_maxmtu; #endif /* VIMAGE_GLOBALS */ #define in6_ifstat_inc(ifp, tag) \ do { \ @@ -483,7 +489,6 @@ do { \ extern struct in6_addr zeroin6_addr; extern u_char inet6ctlerrmap[]; -extern unsigned long in6_maxmtu; #ifdef MALLOC_DECLARE MALLOC_DECLARE(M_IP6MADDR); #endif /* MALLOC_DECLARE */ diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c index 7edcaa3..228777b 100644 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -92,6 +92,7 @@ __FBSDID("$FreeBSD$"); #include <netinet/in.h> #include <netinet/in_systm.h> +#include <net/if_llatbl.h> #ifdef INET #include <netinet/ip.h> #include <netinet/ip_icmp.h> @@ -130,7 +131,6 @@ struct vnet_inet6 vnet_inet6_0; static int ip6qmaxlen; struct in6_ifaddr *in6_ifaddr; struct ip6stat ip6stat; -#endif extern struct callout in6_tmpaddrtimer_ch; @@ -144,7 +144,8 @@ extern int icmp6_nodeinfo; extern int udp6_sendspace; extern int udp6_recvspace; -#ifdef VIMAGE_GLOBALS +extern struct route_in6 ip6_forward_rt; + int ip6_forward_srcrt; /* XXX */ int ip6_sourcecheck; /* XXX */ int ip6_sourcecheck_interval; /* XXX */ @@ -301,8 +302,6 @@ ip6_init2(void *dummy) /* This must be after route_init(), which is now SI_ORDER_THIRD */ SYSINIT(netinet6init2, SI_SUB_PROTO_DOMAIN, SI_ORDER_MIDDLE, ip6_init2, NULL); -extern struct route_in6 ip6_forward_rt; - void ip6_input(struct mbuf *m) { @@ -313,9 +312,11 @@ ip6_input(struct mbuf *m) u_int32_t plen; u_int32_t rtalert = ~0; int nxt, ours = 0; - struct ifnet *deliverifp = NULL; + struct ifnet *deliverifp = NULL, *ifp = NULL; struct in6_addr odst; int srcrt = 0; + struct llentry *lle = NULL; + struct sockaddr_in6 dst6; #ifdef IPSEC /* @@ -550,6 +551,25 @@ passin: /* * Unicast check */ + + bzero(&dst6, sizeof(dst6)); + dst6.sin6_family = AF_INET6; + dst6.sin6_len = sizeof(struct sockaddr_in6); + dst6.sin6_addr = ip6->ip6_dst; + ifp = m->m_pkthdr.rcvif; + IF_AFDATA_LOCK(ifp); + lle = lla_lookup(LLTABLE6(ifp), 0, + (struct sockaddr *)&dst6); + IF_AFDATA_UNLOCK(ifp); + if ((lle != NULL) && (lle->la_flags & LLE_IFADDR)) { + ours = 1; + deliverifp = ifp; + LLE_RUNLOCK(lle); + goto hbhcheck; + } + if (lle != NULL) + LLE_RUNLOCK(lle); + if (V_ip6_forward_rt.ro_rt != NULL && (V_ip6_forward_rt.ro_rt->rt_flags & RTF_UP) != 0 && IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, @@ -1206,7 +1226,7 @@ ip6_savecontrol(struct inpcb *in6p, struct mbuf *m, struct mbuf **mp) if (v4only) return; - if ((in6p->in6p_flags & IN6P_TCLASS) != 0) { + if ((in6p->inp_flags & IN6P_TCLASS) != 0) { u_int32_t flowinfo; int tclass; @@ -1227,7 +1247,7 @@ ip6_savecontrol(struct inpcb *in6p, struct mbuf *m, struct mbuf **mp) * returned to normal user. * See also RFC 2292 section 6 (or RFC 3542 section 8). */ - if ((in6p->in6p_flags & IN6P_HOPOPTS) != 0) { + if ((in6p->inp_flags & IN6P_HOPOPTS) != 0) { /* * Check if a hop-by-hop options header is contatined in the * received packet, and if so, store the options as ancillary @@ -1279,7 +1299,7 @@ ip6_savecontrol(struct inpcb *in6p, struct mbuf *m, struct mbuf **mp) } } - if ((in6p->in6p_flags & (IN6P_RTHDR | IN6P_DSTOPTS)) != 0) { + if ((in6p->inp_flags & (IN6P_RTHDR | IN6P_DSTOPTS)) != 0) { int nxt = ip6->ip6_nxt, off = sizeof(struct ip6_hdr); /* @@ -1340,7 +1360,7 @@ ip6_savecontrol(struct inpcb *in6p, struct mbuf *m, struct mbuf **mp) switch (nxt) { case IPPROTO_DSTOPTS: - if (!(in6p->in6p_flags & IN6P_DSTOPTS)) + if (!(in6p->inp_flags & IN6P_DSTOPTS)) break; *mp = sbcreatecontrol((caddr_t)ip6e, elen, @@ -1351,7 +1371,7 @@ ip6_savecontrol(struct inpcb *in6p, struct mbuf *m, struct mbuf **mp) mp = &(*mp)->m_next; break; case IPPROTO_ROUTING: - if (!in6p->in6p_flags & IN6P_RTHDR) + if (!in6p->inp_flags & IN6P_RTHDR) break; *mp = sbcreatecontrol((caddr_t)ip6e, elen, diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c index 6e5d0d0..ba40b68 100644 --- a/sys/netinet6/ip6_output.c +++ b/sys/netinet6/ip6_output.c @@ -615,7 +615,7 @@ again: dst_sa.sin6_len = sizeof(dst_sa); dst_sa.sin6_addr = ip6->ip6_dst; if ((error = in6_selectroute(&dst_sa, opt, im6o, ro, - &ifp, &rt, 0)) != 0) { + &ifp, &rt)) != 0) { switch (error) { case EHOSTUNREACH: V_ip6stat.ip6s_noroute++; @@ -1320,7 +1320,7 @@ ip6_getpmtu(struct route_in6 *ro_pmtu, struct route_in6 *ro, struct in_conninfo inc; bzero(&inc, sizeof(inc)); - inc.inc_flags = 1; /* IPv6 */ + inc.inc_flags |= INC_ISIPV6; inc.inc6_faddr = *dst; if (ifp == NULL) @@ -1464,7 +1464,7 @@ ip6_ctloutput(struct socket *so, struct sockopt *sopt) else { /* -1 = kernel default */ in6p->in6p_hops = optval; - if ((in6p->in6p_vflag & + if ((in6p->inp_vflag & INP_IPV4) != 0) in6p->inp_ip_ttl = optval; } @@ -1472,19 +1472,19 @@ ip6_ctloutput(struct socket *so, struct sockopt *sopt) #define OPTSET(bit) \ do { \ if (optval) \ - in6p->in6p_flags |= (bit); \ + in6p->inp_flags |= (bit); \ else \ - in6p->in6p_flags &= ~(bit); \ + in6p->inp_flags &= ~(bit); \ } while (/*CONSTCOND*/ 0) #define OPTSET2292(bit) \ do { \ - in6p->in6p_flags |= IN6P_RFC2292; \ + in6p->inp_flags |= IN6P_RFC2292; \ if (optval) \ - in6p->in6p_flags |= (bit); \ + in6p->inp_flags |= (bit); \ else \ - in6p->in6p_flags &= ~(bit); \ + in6p->inp_flags &= ~(bit); \ } while (/*CONSTCOND*/ 0) -#define OPTBIT(bit) (in6p->in6p_flags & (bit) ? 1 : 0) +#define OPTBIT(bit) (in6p->inp_flags & (bit) ? 1 : 0) case IPV6_RECVPKTINFO: /* cannot mix with RFC2292 */ @@ -1558,7 +1558,7 @@ do { \ break; case IPV6_FAITH: - OPTSET(IN6P_FAITH); + OPTSET(INP_FAITH); break; case IPV6_RECVPATHMTU: @@ -1578,16 +1578,16 @@ do { \ * available only prior to bind(2). * see ipng mailing list, Jun 22 2001. */ - if (in6p->in6p_lport || + if (in6p->inp_lport || !IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) { error = EINVAL; break; } OPTSET(IN6P_IPV6_V6ONLY); if (optval) - in6p->in6p_vflag &= ~INP_IPV4; + in6p->inp_vflag &= ~INP_IPV4; else - in6p->in6p_vflag |= INP_IPV4; + in6p->inp_vflag |= INP_IPV4; break; case IPV6_RECVTCLASS: /* cannot mix with RFC2292 XXX */ @@ -1768,18 +1768,18 @@ do { \ switch (optval) { case IPV6_PORTRANGE_DEFAULT: - in6p->in6p_flags &= ~(IN6P_LOWPORT); - in6p->in6p_flags &= ~(IN6P_HIGHPORT); + in6p->inp_flags &= ~(INP_LOWPORT); + in6p->inp_flags &= ~(INP_HIGHPORT); break; case IPV6_PORTRANGE_HIGH: - in6p->in6p_flags &= ~(IN6P_LOWPORT); - in6p->in6p_flags |= IN6P_HIGHPORT; + in6p->inp_flags &= ~(INP_LOWPORT); + in6p->inp_flags |= INP_HIGHPORT; break; case IPV6_PORTRANGE_LOW: - in6p->in6p_flags &= ~(IN6P_HIGHPORT); - in6p->in6p_flags |= IN6P_LOWPORT; + in6p->inp_flags &= ~(INP_HIGHPORT); + in6p->inp_flags |= INP_LOWPORT; break; default: @@ -1881,7 +1881,7 @@ do { \ break; case IPV6_FAITH: - optval = OPTBIT(IN6P_FAITH); + optval = OPTBIT(INP_FAITH); break; case IPV6_V6ONLY: @@ -1891,10 +1891,10 @@ do { \ case IPV6_PORTRANGE: { int flags; - flags = in6p->in6p_flags; - if (flags & IN6P_HIGHPORT) + flags = in6p->inp_flags; + if (flags & INP_HIGHPORT) optval = IPV6_PORTRANGE_HIGH; - else if (flags & IN6P_LOWPORT) + else if (flags & INP_LOWPORT) optval = IPV6_PORTRANGE_LOW; else optval = 0; @@ -2050,7 +2050,7 @@ ip6_raw_ctloutput(struct socket *so, struct sockopt *sopt) { int error = 0, optval, optlen; const int icmp6off = offsetof(struct icmp6_hdr, icmp6_cksum); - struct in6pcb *in6p = sotoin6pcb(so); + struct inpcb *in6p = sotoinpcb(so); int level, op, optname; level = sopt->sopt_level; @@ -3326,7 +3326,7 @@ ip6_splithdr(struct mbuf *m, struct ip6_exthdrs *exthdrs) * Compute IPv6 extension header length. */ int -ip6_optlen(struct in6pcb *in6p) +ip6_optlen(struct inpcb *in6p) { int len; diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h index e384da1..55bc5db 100644 --- a/sys/netinet6/ip6_var.h +++ b/sys/netinet6/ip6_var.h @@ -313,15 +313,16 @@ extern int ip6_auto_linklocal; extern int ip6_use_tempaddr; /* whether to use temporary addresses. */ extern int ip6_prefer_tempaddr; /* whether to prefer temporary addresses in the source address selection */ -#endif /* VIMAGE_GLOBALS */ + +#ifdef IPSTEALTH +extern int ip6stealth; +#endif extern int ip6_use_defzone; /* whether to use the default scope zone when unspecified */ +#endif /* VIMAGE_GLOBALS */ extern struct pfil_head inet6_pfil_hook; /* packet filter hooks */ -#ifdef IPSTEALTH -extern int ip6stealth; -#endif extern struct pr_usrreqs rip6_usrreqs; struct sockopt; @@ -397,7 +398,7 @@ struct in6_addr *in6_selectsrc __P((struct sockaddr_in6 *, struct ip6_pktopts *, struct ifnet **, int *)); int in6_selectroute __P((struct sockaddr_in6 *, struct ip6_pktopts *, struct ip6_moptions *, struct route_in6 *, struct ifnet **, - struct rtentry **, int)); + struct rtentry **)); u_int32_t ip6_randomid __P((void)); u_int32_t ip6_randomflowlabel __P((void)); #endif /* _KERNEL */ diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c index 18e81c3..e2ca9eb 100644 --- a/sys/netinet6/nd6.c +++ b/sys/netinet6/nd6.c @@ -48,6 +48,8 @@ __FBSDID("$FreeBSD$"); #include <sys/protosw.h> #include <sys/errno.h> #include <sys/syslog.h> +#include <sys/lock.h> +#include <sys/rwlock.h> #include <sys/queue.h> #include <sys/sysctl.h> @@ -61,6 +63,8 @@ __FBSDID("$FreeBSD$"); #include <net/vnet.h> #include <netinet/in.h> +#include <net/if_llatbl.h> +#define L3_ADDR_SIN6(le) ((struct sockaddr_in6 *) L3_ADDR(le)) #include <netinet/if_ether.h> #include <netinet6/in6_var.h> #include <netinet/ip6.h> @@ -98,8 +102,9 @@ int nd6_maxqueuelen; int nd6_debug; /* for debugging? */ +#if 0 static int nd6_inuse, nd6_allocated; -struct llinfo_nd6 llinfo_nd6; +#endif struct nd_drhead nd_defrouter; struct nd_prhead nd_prefix; @@ -114,9 +119,9 @@ static int nd6_is_new_addr_neighbor __P((struct sockaddr_in6 *, static void nd6_setmtu0(struct ifnet *, struct nd_ifinfo *); static void nd6_slowtimo(void *); static int regen_tmpaddr(struct in6_ifaddr *); -static struct llinfo_nd6 *nd6_free(struct rtentry *, int); +static struct llentry *nd6_free(struct llentry *, int); static void nd6_llinfo_timer(void *); -static void clear_llinfo_pqueue(struct llinfo_nd6 *); +static void clear_llinfo_pqueue(struct llentry *); #ifdef VIMAGE_GLOBALS struct callout nd6_slowtimo_ch; @@ -162,8 +167,13 @@ nd6_init(void) V_dad_ignore_ns = 0; /* ignore NS in DAD - specwise incorrect*/ V_dad_maxtry = 15; /* max # of *tries* to transmit DAD packet */ + /* + * XXX just to get this to compile KMM + */ +#ifdef notyet V_llinfo_nd6.ln_next = &V_llinfo_nd6; V_llinfo_nd6.ln_prev = &V_llinfo_nd6; +#endif LIST_INIT(&V_nd_prefix); V_ip6_use_tempaddr = 0; @@ -424,14 +434,23 @@ skip1: * ND6 timer routine to handle ND6 entries */ void -nd6_llinfo_settimer(struct llinfo_nd6 *ln, long tick) +nd6_llinfo_settimer_locked(struct llentry *ln, long tick) { if (tick < 0) { - ln->ln_expire = 0; + ln->la_expire = 0; ln->ln_ntick = 0; callout_stop(&ln->ln_timer_ch); + /* + * XXX - do we know that there is + * callout installed? i.e. are we + * guaranteed that we're not dropping + * a reference that we did not add? + * KMM + */ + LLE_REMREF(ln); } else { - ln->ln_expire = time_second + tick / hz; + ln->la_expire = time_second + tick / hz; + LLE_ADDREF(ln); if (tick > INT_MAX) { ln->ln_ntick = tick - INT_MAX; callout_reset(&ln->ln_timer_ch, INT_MAX, @@ -444,16 +463,34 @@ nd6_llinfo_settimer(struct llinfo_nd6 *ln, long tick) } } +void +nd6_llinfo_settimer(struct llentry *ln, long tick) +{ + + LLE_WLOCK(ln); + nd6_llinfo_settimer_locked(ln, tick); + LLE_WUNLOCK(ln); +} + static void nd6_llinfo_timer(void *arg) { - struct llinfo_nd6 *ln; - struct rtentry *rt; + struct llentry *ln; struct in6_addr *dst; struct ifnet *ifp; struct nd_ifinfo *ndi = NULL; - ln = (struct llinfo_nd6 *)arg; + ln = (struct llentry *)arg; + if (ln == NULL) { + panic("%s: NULL entry!\n", __func__); + return; + } + + if ((ifp = ((ln->lle_tbl != NULL) ? ln->lle_tbl->llt_ifp : NULL)) == NULL) + panic("ln ifp == NULL"); + + CURVNET_SET(ifp->if_vnet); + INIT_VNET_INET6(curvnet); if (ln->ln_ntick > 0) { if (ln->ln_ntick > INT_MAX) { @@ -463,52 +500,44 @@ nd6_llinfo_timer(void *arg) ln->ln_ntick = 0; nd6_llinfo_settimer(ln, ln->ln_ntick); } - return; + goto done; } - if ((rt = ln->ln_rt) == NULL) - panic("ln->ln_rt == NULL"); - if ((ifp = rt->rt_ifp) == NULL) - panic("ln->ln_rt->rt_ifp == NULL"); ndi = ND_IFINFO(ifp); + dst = &L3_ADDR_SIN6(ln)->sin6_addr; + if ((ln->la_flags & LLE_STATIC) || (ln->la_expire > time_second)) { + goto done; + } - CURVNET_SET(ifp->if_vnet); - INIT_VNET_INET6(curvnet); - - /* sanity check */ - if (rt->rt_llinfo && (struct llinfo_nd6 *)rt->rt_llinfo != ln) - panic("rt_llinfo(%p) is not equal to ln(%p)", - rt->rt_llinfo, ln); - if (rt_key(rt) == NULL) - panic("rt key is NULL in nd6_timer(ln=%p)", ln); - - dst = &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr; + if (ln->la_flags & LLE_DELETED) { + (void)nd6_free(ln, 0); + goto done; + } switch (ln->ln_state) { case ND6_LLINFO_INCOMPLETE: - if (ln->ln_asked < V_nd6_mmaxtries) { - ln->ln_asked++; + if (ln->la_asked < V_nd6_mmaxtries) { + ln->la_asked++; nd6_llinfo_settimer(ln, (long)ndi->retrans * hz / 1000); nd6_ns_output(ifp, NULL, dst, ln, 0); } else { - struct mbuf *m = ln->ln_hold; + struct mbuf *m = ln->la_hold; if (m) { struct mbuf *m0; /* - * assuming every packet in ln_hold has the + * assuming every packet in la_hold has the * same IP header */ m0 = m->m_nextpkt; m->m_nextpkt = NULL; icmp6_error2(m, ICMP6_DST_UNREACH, - ICMP6_DST_UNREACH_ADDR, 0, rt->rt_ifp); + ICMP6_DST_UNREACH_ADDR, 0, ifp); - ln->ln_hold = m0; + ln->la_hold = m0; clear_llinfo_pqueue(ln); } - if (rt && rt->rt_llinfo) - (void)nd6_free(rt, 0); + (void)nd6_free(ln, 0); ln = NULL; } break; @@ -522,8 +551,7 @@ nd6_llinfo_timer(void *arg) case ND6_LLINFO_STALE: /* Garbage Collection(RFC 2461 5.3) */ if (!ND6_LLINFO_PERMANENT(ln)) { - if (rt && rt->rt_llinfo) - (void)nd6_free(rt, 1); + (void)nd6_free(ln, 1); ln = NULL; } break; @@ -531,7 +559,7 @@ nd6_llinfo_timer(void *arg) case ND6_LLINFO_DELAY: if (ndi && (ndi->flags & ND6_IFF_PERFORMNUD) != 0) { /* We need NUD */ - ln->ln_asked = 1; + ln->la_asked = 1; ln->ln_state = ND6_LLINFO_PROBE; nd6_llinfo_settimer(ln, (long)ndi->retrans * hz / 1000); nd6_ns_output(ifp, dst, dst, ln, 0); @@ -541,31 +569,20 @@ nd6_llinfo_timer(void *arg) } break; case ND6_LLINFO_PROBE: - if (ln->ln_asked < V_nd6_umaxtries) { - ln->ln_asked++; + if (ln->la_asked < V_nd6_umaxtries) { + ln->la_asked++; nd6_llinfo_settimer(ln, (long)ndi->retrans * hz / 1000); nd6_ns_output(ifp, dst, dst, ln, 0); - } else if (rt->rt_ifa != NULL && - rt->rt_ifa->ifa_addr->sa_family == AF_INET6 && - (((struct in6_ifaddr *)rt->rt_ifa)->ia_flags & IFA_ROUTE)) { - /* - * This is an unreachable neighbor whose address is - * specified as the destination of a p2p interface - * (see in6_ifinit()). We should not free the entry - * since this is sort of a "static" entry generated - * via interface address configuration. - */ - ln->ln_asked = 0; - ln->ln_expire = 0; /* make it permanent */ - ln->ln_state = ND6_LLINFO_STALE; } else { - if (rt && rt->rt_llinfo) - (void)nd6_free(rt, 0); + (void)nd6_free(ln, 0); ln = NULL; } break; } CURVNET_RESTORE(); +done: + if (ln != NULL) + LLE_FREE(ln); } @@ -772,7 +789,6 @@ void nd6_purge(struct ifnet *ifp) { INIT_VNET_INET6(ifp->if_vnet); - struct llinfo_nd6 *ln, *nln; struct nd_defrouter *dr, *ndr; struct nd_prefix *pr, *npr; @@ -829,132 +845,54 @@ nd6_purge(struct ifnet *ifp) nd6_setdefaultiface(0); if (!V_ip6_forwarding && V_ip6_accept_rtadv) { /* XXX: too restrictive? */ - /* refresh default router list */ + /* refresh default router list + * + * + */ defrouter_select(); + } - /* - * Nuke neighbor cache entries for the ifp. - * Note that rt->rt_ifp may not be the same as ifp, - * due to KAME goto ours hack. See RTM_RESOLVE case in - * nd6_rtrequest(), and ip6_input(). + /* XXXXX + * We do not nuke the neighbor cache entries here any more + * because the neighbor cache is kept in if_afdata[AF_INET6]. + * nd6_purge() is invoked by in6_ifdetach() which is called + * from if_detach() where everything gets purged. So let + * in6_domifdetach() do the actual L2 table purging work. */ - ln = V_llinfo_nd6.ln_next; - while (ln && ln != &V_llinfo_nd6) { - struct rtentry *rt; - struct sockaddr_dl *sdl; - - nln = ln->ln_next; - rt = ln->ln_rt; - if (rt && rt->rt_gateway && - rt->rt_gateway->sa_family == AF_LINK) { - sdl = (struct sockaddr_dl *)rt->rt_gateway; - if (sdl->sdl_index == ifp->if_index) - nln = nd6_free(rt, 0); - } - ln = nln; - } } -struct rtentry * -nd6_lookup(struct in6_addr *addr6, int create, struct ifnet *ifp) +/* + * the caller acquires and releases the lock on the lltbls + * Returns the llentry locked + */ +struct llentry * +nd6_lookup(struct in6_addr *addr6, int flags, struct ifnet *ifp) { INIT_VNET_INET6(curvnet); - struct rtentry *rt; struct sockaddr_in6 sin6; - char ip6buf[INET6_ADDRSTRLEN]; - + struct llentry *ln; + int llflags = 0; + bzero(&sin6, sizeof(sin6)); sin6.sin6_len = sizeof(struct sockaddr_in6); sin6.sin6_family = AF_INET6; sin6.sin6_addr = *addr6; - rt = rtalloc1((struct sockaddr *)&sin6, create, 0UL); - if (rt) { - if ((rt->rt_flags & RTF_LLINFO) == 0 && create) { - /* - * This is the case for the default route. - * If we want to create a neighbor cache for the - * address, we should free the route for the - * destination and allocate an interface route. - */ - RTFREE_LOCKED(rt); - rt = NULL; - } - } - if (rt == NULL) { - if (create && ifp) { - int e; - /* - * If no route is available and create is set, - * we allocate a host route for the destination - * and treat it like an interface route. - * This hack is necessary for a neighbor which can't - * be covered by our own prefix. - */ - struct ifaddr *ifa = - ifaof_ifpforaddr((struct sockaddr *)&sin6, ifp); - if (ifa == NULL) - return (NULL); + IF_AFDATA_LOCK_ASSERT(ifp); - /* - * Create a new route. RTF_LLINFO is necessary - * to create a Neighbor Cache entry for the - * destination in nd6_rtrequest which will be - * called in rtrequest via ifa->ifa_rtrequest. - */ - if ((e = rtrequest(RTM_ADD, (struct sockaddr *)&sin6, - ifa->ifa_addr, (struct sockaddr *)&all1_sa, - (ifa->ifa_flags | RTF_HOST | RTF_LLINFO) & - ~RTF_CLONING, &rt)) != 0) { - log(LOG_ERR, - "nd6_lookup: failed to add route for a " - "neighbor(%s), errno=%d\n", - ip6_sprintf(ip6buf, addr6), e); - } - if (rt == NULL) - return (NULL); - RT_LOCK(rt); - if (rt->rt_llinfo) { - struct llinfo_nd6 *ln = - (struct llinfo_nd6 *)rt->rt_llinfo; - ln->ln_state = ND6_LLINFO_NOSTATE; - } - } else - return (NULL); - } - RT_LOCK_ASSERT(rt); - RT_REMREF(rt); - /* - * Validation for the entry. - * Note that the check for rt_llinfo is necessary because a cloned - * route from a parent route that has the L flag (e.g. the default - * route to a p2p interface) may have the flag, too, while the - * destination is not actually a neighbor. - * XXX: we can't use rt->rt_ifp to check for the interface, since - * it might be the loopback interface if the entry is for our - * own address on a non-loopback interface. Instead, we should - * use rt->rt_ifa->ifa_ifp, which would specify the REAL - * interface. - * Note also that ifa_ifp and ifp may differ when we connect two - * interfaces to a same link, install a link prefix to an interface, - * and try to install a neighbor cache on an interface that does not - * have a route to the prefix. - */ - if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_flags & RTF_LLINFO) == 0 || - rt->rt_gateway->sa_family != AF_LINK || rt->rt_llinfo == NULL || - (ifp && rt->rt_ifa->ifa_ifp != ifp)) { - if (create) { - nd6log((LOG_DEBUG, - "nd6_lookup: failed to lookup %s (if = %s)\n", - ip6_sprintf(ip6buf, addr6), - ifp ? if_name(ifp) : "unspec")); - } - RT_UNLOCK(rt); - return (NULL); + if (flags & ND6_CREATE) + llflags |= LLE_CREATE; + if (flags & ND6_EXCLUSIVE) + llflags |= LLE_EXCLUSIVE; + + ln = lla_lookup(LLTABLE6(ifp), llflags, (struct sockaddr *)&sin6); + if ((ln != NULL) && (flags & LLE_CREATE)) { + ln->ln_state = ND6_LLINFO_NOSTATE; + callout_init(&ln->ln_timer_ch, 0); } - RT_UNLOCK(rt); /* XXX not ready to return rt locked */ - return (rt); + + return (ln); } /* @@ -1040,7 +978,10 @@ nd6_is_new_addr_neighbor(struct sockaddr_in6 *addr, struct ifnet *ifp) int nd6_is_addr_neighbor(struct sockaddr_in6 *addr, struct ifnet *ifp) { + struct llentry *lle; + int rc = 0; + IF_AFDATA_UNLOCK_ASSERT(ifp); if (nd6_is_new_addr_neighbor(addr, ifp)) return (1); @@ -1048,10 +989,13 @@ nd6_is_addr_neighbor(struct sockaddr_in6 *addr, struct ifnet *ifp) * Even if the address matches none of our addresses, it might be * in the neighbor cache. */ - if (nd6_lookup(&addr->sin6_addr, 0, ifp) != NULL) - return (1); - - return (0); + IF_AFDATA_LOCK(ifp); + if ((lle = nd6_lookup(&addr->sin6_addr, 0, ifp)) != NULL) { + LLE_RUNLOCK(lle); + rc = 1; + } + IF_AFDATA_UNLOCK(ifp); + return (rc); } /* @@ -1060,13 +1004,13 @@ nd6_is_addr_neighbor(struct sockaddr_in6 *addr, struct ifnet *ifp) * make it global, unless you have a strong reason for the change, and are sure * that the change is safe. */ -static struct llinfo_nd6 * -nd6_free(struct rtentry *rt, int gc) +static struct llentry * +nd6_free(struct llentry *ln, int gc) { INIT_VNET_INET6(curvnet); - struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo, *next; - struct in6_addr in6 = ((struct sockaddr_in6 *)rt_key(rt))->sin6_addr; + struct llentry *next; struct nd_defrouter *dr; + struct ifnet *ifp=NULL; /* * we used to have pfctlinput(PRC_HOSTDEAD) here. @@ -1079,8 +1023,7 @@ nd6_free(struct rtentry *rt, int gc) if (!V_ip6_forwarding) { int s; s = splnet(); - dr = defrouter_lookup(&((struct sockaddr_in6 *)rt_key(rt))->sin6_addr, - rt->rt_ifp); + dr = defrouter_lookup(&L3_ADDR_SIN6(ln)->sin6_addr, ln->lle_tbl->llt_ifp); if (dr != NULL && dr->expire && ln->ln_state == ND6_LLINFO_STALE && gc) { @@ -1102,7 +1045,7 @@ nd6_free(struct rtentry *rt, int gc) else nd6_llinfo_settimer(ln, (long)V_nd6_gctimer * hz); splx(s); - return (ln->ln_next); + return (LIST_NEXT(ln, lle_next)); } if (ln->ln_router || dr) { @@ -1111,7 +1054,7 @@ nd6_free(struct rtentry *rt, int gc) * is in the Default Router List. * See a corresponding comment in nd6_na_input(). */ - rt6_flush(&in6, rt->rt_ifp); + rt6_flush(&L3_ADDR_SIN6(ln)->sin6_addr, ln->lle_tbl->llt_ifp); } if (dr) { @@ -1152,15 +1095,13 @@ nd6_free(struct rtentry *rt, int gc) * might have freed other entries (particularly the old next entry) as * a side effect (XXX). */ - next = ln->ln_next; + next = LIST_NEXT(ln, lle_next); - /* - * Detach the route from the routing tree and the list of neighbor - * caches, and disable the route entry not to be used in already - * cached routes. - */ - rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, - rt_mask(rt), 0, (struct rtentry **)0); + ifp = ln->lle_tbl->llt_ifp; + IF_AFDATA_LOCK(ifp); + LLE_WLOCK(ln); + llentry_free(ln); + IF_AFDATA_UNLOCK(ifp); return (next); } @@ -1174,297 +1115,42 @@ void nd6_nud_hint(struct rtentry *rt, struct in6_addr *dst6, int force) { INIT_VNET_INET6(curvnet); - struct llinfo_nd6 *ln; + struct llentry *ln; + struct ifnet *ifp; - /* - * If the caller specified "rt", use that. Otherwise, resolve the - * routing table by supplied "dst6". - */ - if (rt == NULL) { - if (dst6 == NULL) - return; - if ((rt = nd6_lookup(dst6, 0, NULL)) == NULL) - return; - } - - if ((rt->rt_flags & RTF_GATEWAY) != 0 || - (rt->rt_flags & RTF_LLINFO) == 0 || - rt->rt_llinfo == NULL || rt->rt_gateway == NULL || - rt->rt_gateway->sa_family != AF_LINK) { - /* This is not a host route. */ + if ((dst6 == NULL) || (rt == NULL)) return; - } - ln = (struct llinfo_nd6 *)rt->rt_llinfo; - if (ln->ln_state < ND6_LLINFO_REACHABLE) + ifp = rt->rt_ifp; + IF_AFDATA_LOCK(ifp); + ln = nd6_lookup(dst6, ND6_EXCLUSIVE, NULL); + IF_AFDATA_UNLOCK(ifp); + if (ln == NULL) return; + if (ln->ln_state < ND6_LLINFO_REACHABLE) + goto done; + /* * if we get upper-layer reachability confirmation many times, * it is possible we have false information. */ if (!force) { ln->ln_byhint++; - if (ln->ln_byhint > V_nd6_maxnudhint) - return; + if (ln->ln_byhint > V_nd6_maxnudhint) { + goto done; + } } - ln->ln_state = ND6_LLINFO_REACHABLE; + ln->ln_state = ND6_LLINFO_REACHABLE; if (!ND6_LLINFO_PERMANENT(ln)) { nd6_llinfo_settimer(ln, (long)ND_IFINFO(rt->rt_ifp)->reachable * hz); } +done: + LLE_WUNLOCK(ln); } -/* - * info - XXX unused - */ -void -nd6_rtrequest(int req, struct rtentry *rt, struct rt_addrinfo *info) -{ - struct sockaddr *gate = rt->rt_gateway; - struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo; - static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; - struct ifnet *ifp = rt->rt_ifp; - struct ifaddr *ifa; - INIT_VNET_NET(ifp->if_vnet); - INIT_VNET_INET6(ifp->if_vnet); - - RT_LOCK_ASSERT(rt); - - if ((rt->rt_flags & RTF_GATEWAY) != 0) - return; - - if (nd6_need_cache(ifp) == 0 && (rt->rt_flags & RTF_HOST) == 0) { - /* - * This is probably an interface direct route for a link - * which does not need neighbor caches (e.g. fe80::%lo0/64). - * We do not need special treatment below for such a route. - * Moreover, the RTF_LLINFO flag which would be set below - * would annoy the ndp(8) command. - */ - return; - } - - if (req == RTM_RESOLVE && - (nd6_need_cache(ifp) == 0 || /* stf case */ - !nd6_is_new_addr_neighbor((struct sockaddr_in6 *)rt_key(rt), - ifp))) { - /* - * FreeBSD and BSD/OS often make a cloned host route based - * on a less-specific route (e.g. the default route). - * If the less specific route does not have a "gateway" - * (this is the case when the route just goes to a p2p or an - * stf interface), we'll mistakenly make a neighbor cache for - * the host route, and will see strange neighbor solicitation - * for the corresponding destination. In order to avoid the - * confusion, we check if the destination of the route is - * a neighbor in terms of neighbor discovery, and stop the - * process if not. Additionally, we remove the LLINFO flag - * so that ndp(8) will not try to get the neighbor information - * of the destination. - */ - rt->rt_flags &= ~RTF_LLINFO; - return; - } - - switch (req) { - case RTM_ADD: - /* - * There is no backward compatibility :) - * - * if ((rt->rt_flags & RTF_HOST) == 0 && - * SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff) - * rt->rt_flags |= RTF_CLONING; - */ - if ((rt->rt_flags & RTF_CLONING) || - ((rt->rt_flags & RTF_LLINFO) && ln == NULL)) { - /* - * Case 1: This route should come from a route to - * interface (RTF_CLONING case) or the route should be - * treated as on-link but is currently not - * (RTF_LLINFO && ln == NULL case). - */ - rt_setgate(rt, rt_key(rt), - (struct sockaddr *)&null_sdl); - gate = rt->rt_gateway; - SDL(gate)->sdl_type = ifp->if_type; - SDL(gate)->sdl_index = ifp->if_index; - if (ln) - nd6_llinfo_settimer(ln, 0); - if ((rt->rt_flags & RTF_CLONING) != 0) - break; - } - /* - * In IPv4 code, we try to annonuce new RTF_ANNOUNCE entry here. - * We don't do that here since llinfo is not ready yet. - * - * There are also couple of other things to be discussed: - * - unsolicited NA code needs improvement beforehand - * - RFC2461 says we MAY send multicast unsolicited NA - * (7.2.6 paragraph 4), however, it also says that we - * SHOULD provide a mechanism to prevent multicast NA storm. - * we don't have anything like it right now. - * note that the mechanism needs a mutual agreement - * between proxies, which means that we need to implement - * a new protocol, or a new kludge. - * - from RFC2461 6.2.4, host MUST NOT send an unsolicited NA. - * we need to check ip6forwarding before sending it. - * (or should we allow proxy ND configuration only for - * routers? there's no mention about proxy ND from hosts) - */ - /* FALLTHROUGH */ - case RTM_RESOLVE: - if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) == 0) { - /* - * Address resolution isn't necessary for a point to - * point link, so we can skip this test for a p2p link. - */ - if (gate->sa_family != AF_LINK || - gate->sa_len < sizeof(null_sdl)) { - log(LOG_DEBUG, - "nd6_rtrequest: bad gateway value: %s\n", - if_name(ifp)); - break; - } - SDL(gate)->sdl_type = ifp->if_type; - SDL(gate)->sdl_index = ifp->if_index; - } - if (ln != NULL) - break; /* This happens on a route change */ - /* - * Case 2: This route may come from cloning, or a manual route - * add with a LL address. - */ - R_Malloc(ln, struct llinfo_nd6 *, sizeof(*ln)); - rt->rt_llinfo = (caddr_t)ln; - if (ln == NULL) { - log(LOG_DEBUG, "nd6_rtrequest: malloc failed\n"); - break; - } - V_nd6_inuse++; - V_nd6_allocated++; - bzero(ln, sizeof(*ln)); - RT_ADDREF(rt); - ln->ln_rt = rt; - callout_init(&ln->ln_timer_ch, 0); - - /* this is required for "ndp" command. - shin */ - if (req == RTM_ADD) { - /* - * gate should have some valid AF_LINK entry, - * and ln->ln_expire should have some lifetime - * which is specified by ndp command. - */ - ln->ln_state = ND6_LLINFO_REACHABLE; - ln->ln_byhint = 0; - } else { - /* - * When req == RTM_RESOLVE, rt is created and - * initialized in rtrequest(), so rt_expire is 0. - */ - ln->ln_state = ND6_LLINFO_NOSTATE; - nd6_llinfo_settimer(ln, 0); - } - rt->rt_flags |= RTF_LLINFO; - ln->ln_next = V_llinfo_nd6.ln_next; - V_llinfo_nd6.ln_next = ln; - ln->ln_prev = &V_llinfo_nd6; - ln->ln_next->ln_prev = ln; - - /* - * check if rt_key(rt) is one of my address assigned - * to the interface. - */ - ifa = (struct ifaddr *)in6ifa_ifpwithaddr(rt->rt_ifp, - &SIN6(rt_key(rt))->sin6_addr); - if (ifa) { - caddr_t macp = nd6_ifptomac(ifp); - nd6_llinfo_settimer(ln, -1); - ln->ln_state = ND6_LLINFO_REACHABLE; - ln->ln_byhint = 0; - if (macp) { - bcopy(macp, LLADDR(SDL(gate)), ifp->if_addrlen); - SDL(gate)->sdl_alen = ifp->if_addrlen; - } - if (V_nd6_useloopback) { - rt->rt_ifp = &V_loif[0]; /* XXX */ - /* - * Make sure rt_ifa be equal to the ifaddr - * corresponding to the address. - * We need this because when we refer - * rt_ifa->ia6_flags in ip6_input, we assume - * that the rt_ifa points to the address instead - * of the loopback address. - */ - if (ifa != rt->rt_ifa) { - IFAFREE(rt->rt_ifa); - IFAREF(ifa); - rt->rt_ifa = ifa; - } - } - } else if (rt->rt_flags & RTF_ANNOUNCE) { - nd6_llinfo_settimer(ln, -1); - ln->ln_state = ND6_LLINFO_REACHABLE; - ln->ln_byhint = 0; - - /* join solicited node multicast for proxy ND */ - if (ifp->if_flags & IFF_MULTICAST) { - struct in6_addr llsol; - int error; - - llsol = SIN6(rt_key(rt))->sin6_addr; - llsol.s6_addr32[0] = IPV6_ADDR_INT32_MLL; - llsol.s6_addr32[1] = 0; - llsol.s6_addr32[2] = htonl(1); - llsol.s6_addr8[12] = 0xff; - if (in6_setscope(&llsol, ifp, NULL)) - break; - if (in6_addmulti(&llsol, ifp, - &error, 0) == NULL) { - char ip6buf[INET6_ADDRSTRLEN]; - nd6log((LOG_ERR, "%s: failed to join " - "%s (errno=%d)\n", if_name(ifp), - ip6_sprintf(ip6buf, &llsol), - error)); - } - } - } - break; - - case RTM_DELETE: - if (ln == NULL) - break; - /* leave from solicited node multicast for proxy ND */ - if ((rt->rt_flags & RTF_ANNOUNCE) != 0 && - (ifp->if_flags & IFF_MULTICAST) != 0) { - struct in6_addr llsol; - struct in6_multi *in6m; - - llsol = SIN6(rt_key(rt))->sin6_addr; - llsol.s6_addr32[0] = IPV6_ADDR_INT32_MLL; - llsol.s6_addr32[1] = 0; - llsol.s6_addr32[2] = htonl(1); - llsol.s6_addr8[12] = 0xff; - if (in6_setscope(&llsol, ifp, NULL) == 0) { - IN6_LOOKUP_MULTI(llsol, ifp, in6m); - if (in6m) - in6_delmulti(in6m); - } else - ; /* XXX: should not happen. bark here? */ - } - V_nd6_inuse--; - ln->ln_next->ln_prev = ln->ln_prev; - ln->ln_prev->ln_next = ln->ln_next; - ln->ln_prev = NULL; - nd6_llinfo_settimer(ln, -1); - RT_REMREF(rt); - rt->rt_llinfo = 0; - rt->rt_flags &= ~RTF_LLINFO; - clear_llinfo_pqueue(ln); - Free((caddr_t)ln); - } -} int nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp) @@ -1477,7 +1163,6 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp) struct in6_ndifreq *ndif = (struct in6_ndifreq *)data; struct nd_defrouter *dr; struct nd_prefix *pr; - struct rtentry *rt; int i = 0, error = 0; int s; @@ -1667,25 +1352,25 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp) } case SIOCGNBRINFO_IN6: { - struct llinfo_nd6 *ln; + struct llentry *ln; struct in6_addr nb_addr = nbi->addr; /* make local for safety */ if ((error = in6_setscope(&nb_addr, ifp, NULL)) != 0) return (error); - s = splnet(); - if ((rt = nd6_lookup(&nb_addr, 0, ifp)) == NULL) { + IF_AFDATA_LOCK(ifp); + ln = nd6_lookup(&nb_addr, 0, ifp); + IF_AFDATA_UNLOCK(ifp); + + if (ln == NULL) { error = EINVAL; - splx(s); break; } - ln = (struct llinfo_nd6 *)rt->rt_llinfo; nbi->state = ln->ln_state; - nbi->asked = ln->ln_asked; + nbi->asked = ln->la_asked; nbi->isrouter = ln->ln_router; - nbi->expire = ln->ln_expire; - splx(s); - + nbi->expire = ln->la_expire; + LLE_RUNLOCK(ln); break; } case SIOCGDEFIFACE_IN6: /* XXX: should be implemented as a sysctl? */ @@ -1703,20 +1388,29 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp) * * type - ICMP6 type * code - type dependent information + * + * XXXXX + * The caller of this function already acquired the ndp + * cache table lock because the cache entry is returned. */ -struct rtentry * +struct llentry * nd6_cache_lladdr(struct ifnet *ifp, struct in6_addr *from, char *lladdr, int lladdrlen, int type, int code) { INIT_VNET_INET6(curvnet); - struct rtentry *rt = NULL; - struct llinfo_nd6 *ln = NULL; + struct llentry *ln = NULL; int is_newentry; - struct sockaddr_dl *sdl = NULL; int do_update; int olladdr; int llchange; + int flags = 0; int newstate = 0; + uint16_t router = 0; + struct sockaddr_in6 sin6; + struct mbuf *chain = NULL; + int static_route = 0; + + IF_AFDATA_UNLOCK_ASSERT(ifp); if (ifp == NULL) panic("ifp == NULL in nd6_cache_lladdr"); @@ -1736,40 +1430,31 @@ nd6_cache_lladdr(struct ifnet *ifp, struct in6_addr *from, char *lladdr, * Spec says nothing in sections for RA, RS and NA. There's small * description on it in NS section (RFC 2461 7.2.3). */ - - rt = nd6_lookup(from, 0, ifp); - if (rt == NULL) { - rt = nd6_lookup(from, 1, ifp); + flags |= lladdr ? ND6_EXCLUSIVE : 0; + IF_AFDATA_LOCK(ifp); + ln = nd6_lookup(from, flags, ifp); + + if (ln == NULL) { + flags |= LLE_EXCLUSIVE; + ln = nd6_lookup(from, flags |ND6_CREATE, ifp); + IF_AFDATA_UNLOCK(ifp); is_newentry = 1; } else { + IF_AFDATA_UNLOCK(ifp); /* do nothing if static ndp is set */ - if (rt->rt_flags & RTF_STATIC) - return NULL; + if (ln->la_flags & LLE_STATIC) { + static_route = 1; + goto done; + } is_newentry = 0; } - - if (rt == NULL) - return NULL; - if ((rt->rt_flags & (RTF_GATEWAY | RTF_LLINFO)) != RTF_LLINFO) { -fail: - (void)nd6_free(rt, 0); - return NULL; - } - ln = (struct llinfo_nd6 *)rt->rt_llinfo; if (ln == NULL) - goto fail; - if (rt->rt_gateway == NULL) - goto fail; - if (rt->rt_gateway->sa_family != AF_LINK) - goto fail; - sdl = SDL(rt->rt_gateway); - - olladdr = (sdl->sdl_alen) ? 1 : 0; + return (NULL); + + olladdr = (ln->la_flags & LLE_VALID) ? 1 : 0; if (olladdr && lladdr) { - if (bcmp(lladdr, LLADDR(sdl), ifp->if_addrlen)) - llchange = 1; - else - llchange = 0; + llchange = bcmp(lladdr, &ln->ll_addr, + ifp->if_addrlen); } else llchange = 0; @@ -1789,8 +1474,8 @@ fail: * Record source link-layer address * XXX is it dependent to ifp->if_type? */ - sdl->sdl_alen = ifp->if_addrlen; - bcopy(lladdr, LLADDR(sdl), ifp->if_addrlen); + bcopy(lladdr, &ln->ll_addr, ifp->if_addrlen); + ln->la_flags |= LLE_VALID; } if (!is_newentry) { @@ -1821,17 +1506,17 @@ fail: * we must set the timer now, although it is actually * meaningless. */ - nd6_llinfo_settimer(ln, (long)V_nd6_gctimer * hz); + nd6_llinfo_settimer_locked(ln, (long)V_nd6_gctimer * hz); - if (ln->ln_hold) { + if (ln->la_hold) { struct mbuf *m_hold, *m_hold_next; /* - * reset the ln_hold in advance, to explicitly - * prevent a ln_hold lookup in nd6_output() + * reset the la_hold in advance, to explicitly + * prevent a la_hold lookup in nd6_output() * (wouldn't happen, though...) */ - for (m_hold = ln->ln_hold, ln->ln_hold = NULL; + for (m_hold = ln->la_hold, ln->la_hold = NULL; m_hold; m_hold = m_hold_next) { m_hold_next = m_hold->m_nextpkt; m_hold->m_nextpkt = NULL; @@ -1841,14 +1526,19 @@ fail: * just set the 2nd argument as the * 1st one. */ - nd6_output(ifp, ifp, m_hold, - (struct sockaddr_in6 *)rt_key(rt), - rt); + nd6_output_lle(ifp, ifp, m_hold, L3_ADDR_SIN6(ln), NULL, ln, &chain); } + /* + * If we have mbufs in the chain we need to do + * deferred transmit. Copy the address from the + * llentry before dropping the lock down below. + */ + if (chain != NULL) + memcpy(&sin6, L3_ADDR_SIN6(ln), sizeof(sin6)); } } else if (ln->ln_state == ND6_LLINFO_INCOMPLETE) { /* probe right away */ - nd6_llinfo_settimer((void *)ln, 0); + nd6_llinfo_settimer_locked((void *)ln, 0); } } @@ -1917,6 +1607,20 @@ fail: break; } + if (ln != NULL) { + static_route = (ln->la_flags & LLE_STATIC); + router = ln->ln_router; + + if (flags & ND6_EXCLUSIVE) + LLE_WUNLOCK(ln); + else + LLE_RUNLOCK(ln); + if (static_route) + ln = NULL; + } + if (chain) + nd6_output_flush(ifp, ifp, chain, &sin6, NULL); + /* * When the link-layer address of a router changes, select the * best router again. In particular, when the neighbor entry is newly @@ -1932,10 +1636,24 @@ fail: * for those are not autoconfigured hosts, we explicitly avoid such * cases for safety. */ - if (do_update && ln->ln_router && !V_ip6_forwarding && V_ip6_accept_rtadv) + if (do_update && router && !V_ip6_forwarding && V_ip6_accept_rtadv) { + /* + * guaranteed recursion + */ defrouter_select(); - - return rt; + } + + return (ln); +done: + if (ln != NULL) { + if (flags & ND6_EXCLUSIVE) + LLE_WUNLOCK(ln); + else + LLE_RUNLOCK(ln); + if (static_route) + ln = NULL; + } + return (ln); } static void @@ -1969,18 +1687,44 @@ nd6_slowtimo(void *arg) CURVNET_RESTORE(); } -#define senderr(e) { error = (e); goto bad;} int nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m0, struct sockaddr_in6 *dst, struct rtentry *rt0) { + + return (nd6_output_lle(ifp, origifp, m0, dst, rt0, NULL, NULL)); +} + + +/* + * Note that I'm not enforcing any global serialization + * lle state or asked changes here as the logic is too + * complicated to avoid having to always acquire an exclusive + * lock + * KMM + * + */ +#define senderr(e) { error = (e); goto bad;} + +int +nd6_output_lle(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m0, + struct sockaddr_in6 *dst, struct rtentry *rt0, struct llentry *lle, + struct mbuf **chain) +{ INIT_VNET_INET6(curvnet); struct mbuf *m = m0; - struct rtentry *rt = rt0; - struct sockaddr_in6 *gw6 = NULL; - struct llinfo_nd6 *ln = NULL; + struct llentry *ln = lle; int error = 0; + int flags = 0; +#ifdef INVARIANTS + if (lle != NULL) { + + LLE_WLOCK_ASSERT(lle); + + KASSERT(chain != NULL, (" lle locked but no mbuf chain pointer passed")); + } +#endif if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr)) goto sendpkt; @@ -1990,81 +1734,6 @@ nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m0, /* * next hop determination. This routine is derived from ether_output. */ - /* NB: the locking here is tortuous... */ - if (rt != NULL) - RT_LOCK(rt); -again: - if (rt != NULL) { - if ((rt->rt_flags & RTF_UP) == 0) { - RT_UNLOCK(rt); - rt0 = rt = rtalloc1((struct sockaddr *)dst, 1, 0UL); - if (rt != NULL) { - RT_REMREF(rt); - if (rt->rt_ifp != ifp) - /* - * XXX maybe we should update ifp too, - * but the original code didn't and I - * don't know what is correct here. - */ - goto again; - } else - senderr(EHOSTUNREACH); - } - - if (rt->rt_flags & RTF_GATEWAY) { - gw6 = (struct sockaddr_in6 *)rt->rt_gateway; - - /* - * We skip link-layer address resolution and NUD - * if the gateway is not a neighbor from ND point - * of view, regardless of the value of nd_ifinfo.flags. - * The second condition is a bit tricky; we skip - * if the gateway is our own address, which is - * sometimes used to install a route to a p2p link. - */ - if (!nd6_is_addr_neighbor(gw6, ifp) || - in6ifa_ifpwithaddr(ifp, &gw6->sin6_addr)) { - RT_UNLOCK(rt); - /* - * We allow this kind of tricky route only - * when the outgoing interface is p2p. - * XXX: we may need a more generic rule here. - */ - if ((ifp->if_flags & IFF_POINTOPOINT) == 0) - senderr(EHOSTUNREACH); - - goto sendpkt; - } - - if (rt->rt_gwroute == NULL) - goto lookup; - rt = rt->rt_gwroute; - RT_LOCK(rt); /* NB: gwroute */ - if ((rt->rt_flags & RTF_UP) == 0) { - RTFREE_LOCKED(rt); /* unlock gwroute */ - rt = rt0; - rt0->rt_gwroute = NULL; - lookup: - RT_UNLOCK(rt0); - rt = rtalloc1(rt->rt_gateway, 1, 0UL); - if (rt == rt0) { - RT_REMREF(rt0); - RT_UNLOCK(rt0); - senderr(EHOSTUNREACH); - } - RT_LOCK(rt0); - if (rt0->rt_gwroute != NULL) - RTFREE(rt0->rt_gwroute); - rt0->rt_gwroute = rt; - if (rt == NULL) { - RT_UNLOCK(rt0); - senderr(EHOSTUNREACH); - } - } - RT_UNLOCK(rt0); - } - RT_UNLOCK(rt); - } /* * Address resolution or Neighbor Unreachability Detection @@ -2073,38 +1742,46 @@ again: * or an anycast address(i.e. not a multicast). */ - /* Look up the neighbor cache for the nexthop */ - if (rt && (rt->rt_flags & RTF_LLINFO) != 0) - ln = (struct llinfo_nd6 *)rt->rt_llinfo; - else { - /* - * Since nd6_is_addr_neighbor() internally calls nd6_lookup(), - * the condition below is not very efficient. But we believe - * it is tolerable, because this should be a rare case. - */ - if (nd6_is_addr_neighbor(dst, ifp) && - (rt = nd6_lookup(&dst->sin6_addr, 1, ifp)) != NULL) - ln = (struct llinfo_nd6 *)rt->rt_llinfo; - } - if (ln == NULL || rt == NULL) { + flags = ((m != NULL) || (lle != NULL)) ? LLE_EXCLUSIVE : 0; + if (ln == NULL) { + retry: + IF_AFDATA_LOCK(ifp); + ln = lla_lookup(LLTABLE6(ifp), flags, (struct sockaddr *)dst); + IF_AFDATA_UNLOCK(ifp); + if ((ln == NULL) && nd6_is_addr_neighbor(dst, ifp)) { + /* + * Since nd6_is_addr_neighbor() internally calls nd6_lookup(), + * the condition below is not very efficient. But we believe + * it is tolerable, because this should be a rare case. + */ + flags = ND6_CREATE | (m ? ND6_EXCLUSIVE : 0); + IF_AFDATA_LOCK(ifp); + ln = nd6_lookup(&dst->sin6_addr, flags, ifp); + IF_AFDATA_UNLOCK(ifp); + } + } + if (ln == NULL) { if ((ifp->if_flags & IFF_POINTOPOINT) == 0 && !(ND_IFINFO(ifp)->flags & ND6_IFF_PERFORMNUD)) { char ip6buf[INET6_ADDRSTRLEN]; log(LOG_DEBUG, "nd6_output: can't allocate llinfo for %s " - "(ln=%p, rt=%p)\n", - ip6_sprintf(ip6buf, &dst->sin6_addr), ln, rt); + "(ln=%p)\n", + ip6_sprintf(ip6buf, &dst->sin6_addr), ln); senderr(EIO); /* XXX: good error? */ } - goto sendpkt; /* send anyway */ } /* We don't have to do link-layer address resolution on a p2p link. */ if ((ifp->if_flags & IFF_POINTOPOINT) != 0 && ln->ln_state < ND6_LLINFO_REACHABLE) { + if ((flags & LLE_EXCLUSIVE) == 0) { + flags |= LLE_EXCLUSIVE; + goto retry; + } ln->ln_state = ND6_LLINFO_STALE; - nd6_llinfo_settimer(ln, (long)V_nd6_gctimer * hz); + nd6_llinfo_settimer_locked(ln, (long)V_nd6_gctimer * hz); } /* @@ -2115,9 +1792,14 @@ again: * (RFC 2461 7.3.3) */ if (ln->ln_state == ND6_LLINFO_STALE) { - ln->ln_asked = 0; + if ((flags & LLE_EXCLUSIVE) == 0) { + flags |= LLE_EXCLUSIVE; + LLE_RUNLOCK(ln); + goto retry; + } + ln->la_asked = 0; ln->ln_state = ND6_LLINFO_DELAY; - nd6_llinfo_settimer(ln, (long)V_nd6_delay * hz); + nd6_llinfo_settimer_locked(ln, (long)V_nd6_delay * hz); } /* @@ -2137,12 +1819,18 @@ again: */ if (ln->ln_state == ND6_LLINFO_NOSTATE) ln->ln_state = ND6_LLINFO_INCOMPLETE; - if (ln->ln_hold) { + + if ((flags & LLE_EXCLUSIVE) == 0) { + flags |= LLE_EXCLUSIVE; + LLE_RUNLOCK(ln); + goto retry; + } + if (ln->la_hold) { struct mbuf *m_hold; int i; - + i = 0; - for (m_hold = ln->ln_hold; m_hold; m_hold = m_hold->m_nextpkt) { + for (m_hold = ln->la_hold; m_hold; m_hold = m_hold->m_nextpkt) { i++; if (m_hold->m_nextpkt == NULL) { m_hold->m_nextpkt = m; @@ -2150,21 +1838,32 @@ again: } } while (i >= V_nd6_maxqueuelen) { - m_hold = ln->ln_hold; - ln->ln_hold = ln->ln_hold->m_nextpkt; + m_hold = ln->la_hold; + ln->la_hold = ln->la_hold->m_nextpkt; m_freem(m_hold); i--; } } else { - ln->ln_hold = m; + ln->la_hold = m; } - + /* + * We did the lookup (no lle arg) so we + * need to do the unlock here + */ + if (lle == NULL) { + if (flags & LLE_EXCLUSIVE) + LLE_WUNLOCK(ln); + else + LLE_RUNLOCK(ln); + } + /* * If there has been no NS for the neighbor after entering the * INCOMPLETE state, send the first solicitation. */ - if (!ND6_LLINFO_PERMANENT(ln) && ln->ln_asked == 0) { - ln->ln_asked++; + if (!ND6_LLINFO_PERMANENT(ln) && ln->la_asked == 0) { + ln->la_asked++; + nd6_llinfo_settimer(ln, (long)ND_IFINFO(ifp)->retrans * hz / 1000); nd6_ns_output(ifp, NULL, &dst->sin6_addr, ln, 0); @@ -2177,23 +1876,97 @@ again: error = ENETDOWN; /* better error? */ goto bad; } + /* + * ln is valid and the caller did not pass in + * an llentry + */ + if ((ln != NULL) && (lle == NULL)) { + if (flags & LLE_EXCLUSIVE) + LLE_WUNLOCK(ln); + else + LLE_RUNLOCK(ln); + } #ifdef MAC mac_netinet6_nd6_send(ifp, m); #endif + /* + * We were passed in a pointer to an lle with the lock held + * this means that we can't call if_output as we will + * recurse on the lle lock - so what we do is we create + * a list of mbufs to send and transmit them in the caller + * after the lock is dropped + */ + if (lle != NULL) { + if (*chain == NULL) + *chain = m; + else { + struct mbuf *m = *chain; + + /* + * append mbuf to end of deferred chain + */ + while (m->m_nextpkt != NULL) + m = m->m_nextpkt; + m->m_nextpkt = m; + } + return (error); + } if ((ifp->if_flags & IFF_LOOPBACK) != 0) { return ((*ifp->if_output)(origifp, m, (struct sockaddr *)dst, - rt)); + NULL)); } - return ((*ifp->if_output)(ifp, m, (struct sockaddr *)dst, rt)); + error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst, NULL); + return (error); bad: + /* + * ln is valid and the caller did not pass in + * an llentry + */ + if ((ln != NULL) && (lle == NULL)) { + if (flags & LLE_EXCLUSIVE) + LLE_WUNLOCK(ln); + else + LLE_RUNLOCK(ln); + } if (m) m_freem(m); return (error); } #undef senderr + +int +nd6_output_flush(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *chain, + struct sockaddr_in6 *dst, struct rtentry *rt) +{ + struct mbuf *m, *m_head; + struct ifnet *outifp; + int error = 0; + + m_head = chain; + if ((ifp->if_flags & IFF_LOOPBACK) != 0) + outifp = origifp; + else + outifp = ifp; + + while (m_head) { + m = m_head; + m_head = m_head->m_nextpkt; + error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst, rt); + } + + /* + * XXX + * note that intermediate errors are blindly ignored - but this is + * the same convention as used with nd6_output when called by + * nd6_cache_lladdr + */ + return (error); +} + + int nd6_need_cache(struct ifnet *ifp) { @@ -2229,14 +2002,18 @@ nd6_need_cache(struct ifnet *ifp) } } +/* + * the callers of this function need to be re-worked to drop + * the lle lock, drop here for now + */ int -nd6_storelladdr(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m, - struct sockaddr *dst, u_char *desten) +nd6_storelladdr(struct ifnet *ifp, struct mbuf *m, + struct sockaddr *dst, u_char *desten, struct llentry **lle) { - struct sockaddr_dl *sdl; - struct rtentry *rt; - int error; + struct llentry *ln; + *lle = NULL; + IF_AFDATA_UNLOCK_ASSERT(ifp); if (m->m_flags & M_MCAST) { int i; @@ -2271,48 +2048,42 @@ nd6_storelladdr(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m, } } - if (rt0 == NULL) { - /* this could happen, if we could not allocate memory */ - m_freem(m); - return (ENOMEM); - } - - error = rt_check(&rt, &rt0, dst); - if (error) { - m_freem(m); - return (error); - } - RT_UNLOCK(rt); - if (rt->rt_gateway->sa_family != AF_LINK) { - printf("nd6_storelladdr: something odd happens\n"); - m_freem(m); - return (EINVAL); - } - sdl = SDL(rt->rt_gateway); - if (sdl->sdl_alen == 0) { - /* this should be impossible, but we bark here for debugging */ - printf("nd6_storelladdr: sdl_alen == 0\n"); + /* + * the entry should have been created in nd6_store_lladdr + */ + IF_AFDATA_LOCK(ifp); + ln = lla_lookup(LLTABLE6(ifp), 0, dst); + IF_AFDATA_UNLOCK(ifp); + if ((ln == NULL) || !(ln->la_flags & LLE_VALID)) { + if (ln != NULL) + LLE_RUNLOCK(ln); + /* this could happen, if we could not allocate memory */ m_freem(m); - return (EINVAL); + return (1); } - bcopy(LLADDR(sdl), desten, sdl->sdl_alen); + bcopy(&ln->ll_addr, desten, ifp->if_addrlen); + *lle = ln; + LLE_RUNLOCK(ln); + /* + * A *small* use after free race exists here + */ return (0); } -static void -clear_llinfo_pqueue(struct llinfo_nd6 *ln) +static void +clear_llinfo_pqueue(struct llentry *ln) { struct mbuf *m_hold, *m_hold_next; - for (m_hold = ln->ln_hold; m_hold; m_hold = m_hold_next) { + for (m_hold = ln->la_hold; m_hold; m_hold = m_hold_next) { m_hold_next = m_hold->m_nextpkt; m_hold->m_nextpkt = NULL; m_freem(m_hold); } - ln->ln_hold = NULL; + ln->la_hold = NULL; return; } diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h index 4d3c06b..e2007f7 100644 --- a/sys/netinet6/nd6.h +++ b/sys/netinet6/nd6.h @@ -41,20 +41,7 @@ #include <sys/queue.h> #include <sys/callout.h> -struct llinfo_nd6 { - struct llinfo_nd6 *ln_next; - struct llinfo_nd6 *ln_prev; - struct rtentry *ln_rt; - struct mbuf *ln_hold; /* last packet until resolved/timeout */ - long ln_asked; /* number of queries already sent for this addr */ - u_long ln_expire; /* lifetime for NDP state transition */ - short ln_state; /* reachability state */ - short ln_router; /* 2^0: ND6 router bit */ - int ln_byhint; /* # of times we made it reachable by UL hint */ - - long ln_ntick; - struct callout ln_timer_ch; -}; +struct llentry; #define ND6_LLINFO_NOSTATE -2 /* @@ -72,7 +59,7 @@ struct llinfo_nd6 { #define ND6_LLINFO_PROBE 4 #define ND6_IS_LLINFO_PROBREACH(n) ((n)->ln_state > ND6_LLINFO_INCOMPLETE) -#define ND6_LLINFO_PERMANENT(n) (((n)->ln_expire == 0) && ((n)->ln_state > ND6_LLINFO_INCOMPLETE)) +#define ND6_LLINFO_PERMANENT(n) (((n)->la_expire == 0) && ((n)->ln_state > ND6_LLINFO_INCOMPLETE)) struct nd_ifinfo { u_int32_t linkmtu; /* LinkMTU */ @@ -98,6 +85,9 @@ struct nd_ifinfo { */ #define ND6_IFF_DONT_SET_IFROUTE 0x10 +#define ND6_CREATE LLE_CREATE +#define ND6_EXCLUSIVE LLE_EXCLUSIVE + #ifdef _KERNEL #define ND_IFINFO(ifp) \ (((struct in6_ifextra *)(ifp)->if_afdata[AF_INET6])->nd_ifinfo) @@ -336,7 +326,6 @@ extern int nd6_mmaxtries; extern int nd6_useloopback; extern int nd6_maxnudhint; extern int nd6_gctimer; -extern struct llinfo_nd6 llinfo_nd6; extern struct nd_drhead nd_defrouter; extern struct nd_prhead nd_prefix; extern int nd6_debug; @@ -388,23 +377,28 @@ int nd6_is_addr_neighbor __P((struct sockaddr_in6 *, struct ifnet *)); void nd6_option_init __P((void *, int, union nd_opts *)); struct nd_opt_hdr *nd6_option __P((union nd_opts *)); int nd6_options __P((union nd_opts *)); -struct rtentry *nd6_lookup __P((struct in6_addr *, int, struct ifnet *)); +struct llentry *nd6_lookup __P((struct in6_addr *, int, struct ifnet *)); void nd6_setmtu __P((struct ifnet *)); -void nd6_llinfo_settimer __P((struct llinfo_nd6 *, long)); +void nd6_llinfo_settimer __P((struct llentry *, long)); +void nd6_llinfo_settimer_locked __P((struct llentry *, long)); void nd6_timer __P((void *)); void nd6_purge __P((struct ifnet *)); void nd6_nud_hint __P((struct rtentry *, struct in6_addr *, int)); int nd6_resolve __P((struct ifnet *, struct rtentry *, struct mbuf *, struct sockaddr *, u_char *)); -void nd6_rtrequest __P((int, struct rtentry *, struct rt_addrinfo *)); int nd6_ioctl __P((u_long, caddr_t, struct ifnet *)); -struct rtentry *nd6_cache_lladdr __P((struct ifnet *, struct in6_addr *, +struct llentry *nd6_cache_lladdr __P((struct ifnet *, struct in6_addr *, char *, int, int, int)); int nd6_output __P((struct ifnet *, struct ifnet *, struct mbuf *, struct sockaddr_in6 *, struct rtentry *)); +int nd6_output_lle __P((struct ifnet *, struct ifnet *, struct mbuf *, + struct sockaddr_in6 *, struct rtentry *, struct llentry *, + struct mbuf **)); +int nd6_output_flush __P((struct ifnet *, struct ifnet *, struct mbuf *, + struct sockaddr_in6 *, struct rtentry *)); int nd6_need_cache __P((struct ifnet *)); -int nd6_storelladdr __P((struct ifnet *, struct rtentry *, struct mbuf *, - struct sockaddr *, u_char *)); +int nd6_storelladdr __P((struct ifnet *, struct mbuf *, + struct sockaddr *, u_char *, struct llentry **)); /* nd6_nbr.c */ void nd6_na_input __P((struct mbuf *, int, int)); @@ -412,7 +406,7 @@ void nd6_na_output __P((struct ifnet *, const struct in6_addr *, const struct in6_addr *, u_long, int, struct sockaddr *)); void nd6_ns_input __P((struct mbuf *, int, int)); void nd6_ns_output __P((struct ifnet *, const struct in6_addr *, - const struct in6_addr *, struct llinfo_nd6 *, int)); + const struct in6_addr *, struct llentry *, int)); caddr_t nd6_ifptomac __P((struct ifnet *)); void nd6_dad_start __P((struct ifaddr *, int)); void nd6_dad_stop __P((struct ifaddr *)); diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c index ecfad0e..c1cb423 100644 --- a/sys/netinet6/nd6_nbr.c +++ b/sys/netinet6/nd6_nbr.c @@ -41,6 +41,8 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> #include <sys/malloc.h> +#include <sys/lock.h> +#include <sys/rwlock.h> #include <sys/mbuf.h> #include <sys/socket.h> #include <sys/sockio.h> @@ -63,6 +65,8 @@ __FBSDID("$FreeBSD$"); #include <netinet/in.h> #include <netinet/in_var.h> +#include <net/if_llatbl.h> +#define L3_ADDR_SIN6(le) ((struct sockaddr_in6 *) L3_ADDR(le)) #include <netinet6/in6_var.h> #include <netinet6/in6_ifattach.h> #include <netinet/ip6.h> @@ -167,7 +171,7 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len) src_sa6.sin6_family = AF_INET6; src_sa6.sin6_len = sizeof(src_sa6); src_sa6.sin6_addr = saddr6; - if (!nd6_is_addr_neighbor(&src_sa6, ifp)) { + if (nd6_is_addr_neighbor(&src_sa6, ifp) == 0) { nd6log((LOG_INFO, "nd6_ns_input: " "NS packet from non-neighbor\n")); goto bad; @@ -378,8 +382,8 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len) * dad - duplicate address detection */ void -nd6_ns_output(struct ifnet *ifp, const struct in6_addr *daddr6, - const struct in6_addr *taddr6, struct llinfo_nd6 *ln, int dad) +nd6_ns_output(struct ifnet *ifp, const struct in6_addr *daddr6, + const struct in6_addr *taddr6, struct llentry *ln, int dad) { INIT_VNET_INET6(ifp->if_vnet); struct mbuf *m; @@ -470,14 +474,14 @@ nd6_ns_output(struct ifnet *ifp, const struct in6_addr *daddr6, struct ip6_hdr *hip6; /* hold ip6 */ struct in6_addr *hsrc = NULL; - if (ln && ln->ln_hold) { + if ((ln != NULL) && ln->la_hold) { /* - * assuming every packet in ln_hold has the same IP + * assuming every packet in la_hold has the same IP * header */ - hip6 = mtod(ln->ln_hold, struct ip6_hdr *); + hip6 = mtod(ln->la_hold, struct ip6_hdr *); /* XXX pullup? */ - if (sizeof(*hip6) < ln->ln_hold->m_len) + if (sizeof(*hip6) < ln->la_hold->m_len) hsrc = &hip6->ip6_src; else hsrc = NULL; @@ -600,10 +604,10 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len) char *lladdr = NULL; int lladdrlen = 0; struct ifaddr *ifa; - struct llinfo_nd6 *ln; - struct rtentry *rt; - struct sockaddr_dl *sdl; + struct llentry *ln = NULL; union nd_opts ndopts; + struct mbuf *chain = NULL; + struct sockaddr_in6 sin6; char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; if (ip6->ip6_hlim != 255) { @@ -697,35 +701,37 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len) * If no neighbor cache entry is found, NA SHOULD silently be * discarded. */ - rt = nd6_lookup(&taddr6, 0, ifp); - if ((rt == NULL) || - ((ln = (struct llinfo_nd6 *)rt->rt_llinfo) == NULL) || - ((sdl = SDL(rt->rt_gateway)) == NULL)) + IF_AFDATA_LOCK(ifp); + ln = nd6_lookup(&taddr6, LLE_EXCLUSIVE, ifp); + IF_AFDATA_UNLOCK(ifp); + if (ln == NULL) { goto freeit; + } if (ln->ln_state == ND6_LLINFO_INCOMPLETE) { /* * If the link-layer has address, and no lladdr option came, * discard the packet. */ - if (ifp->if_addrlen && lladdr == NULL) + if (ifp->if_addrlen && lladdr == NULL) { goto freeit; + } /* * Record link-layer address, and update the state. */ - sdl->sdl_alen = ifp->if_addrlen; - bcopy(lladdr, LLADDR(sdl), ifp->if_addrlen); + bcopy(lladdr, &ln->ll_addr, ifp->if_addrlen); + ln->la_flags |= LLE_VALID; if (is_solicited) { ln->ln_state = ND6_LLINFO_REACHABLE; ln->ln_byhint = 0; if (!ND6_LLINFO_PERMANENT(ln)) { - nd6_llinfo_settimer(ln, - (long)ND_IFINFO(rt->rt_ifp)->reachable * hz); + nd6_llinfo_settimer_locked(ln, + (long)ND_IFINFO(ln->lle_tbl->llt_ifp)->reachable * hz); } } else { ln->ln_state = ND6_LLINFO_STALE; - nd6_llinfo_settimer(ln, (long)V_nd6_gctimer * hz); + nd6_llinfo_settimer_locked(ln, (long)V_nd6_gctimer * hz); } if ((ln->ln_router = is_router) != 0) { /* @@ -744,8 +750,8 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len) if (lladdr == NULL) llchange = 0; else { - if (sdl->sdl_alen) { - if (bcmp(lladdr, LLADDR(sdl), ifp->if_addrlen)) + if (ln->la_flags & LLE_VALID) { + if (bcmp(lladdr, &ln->ll_addr, ifp->if_addrlen)) llchange = 1; else llchange = 0; @@ -779,7 +785,7 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len) */ if (ln->ln_state == ND6_LLINFO_REACHABLE) { ln->ln_state = ND6_LLINFO_STALE; - nd6_llinfo_settimer(ln, (long)V_nd6_gctimer * hz); + nd6_llinfo_settimer_locked(ln, (long)V_nd6_gctimer * hz); } goto freeit; } else if (is_override /* (2a) */ @@ -789,8 +795,8 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len) * Update link-local address, if any. */ if (lladdr != NULL) { - sdl->sdl_alen = ifp->if_addrlen; - bcopy(lladdr, LLADDR(sdl), ifp->if_addrlen); + bcopy(lladdr, &ln->ll_addr, ifp->if_addrlen); + ln->la_flags |= LLE_VALID; } /* @@ -802,13 +808,13 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len) ln->ln_state = ND6_LLINFO_REACHABLE; ln->ln_byhint = 0; if (!ND6_LLINFO_PERMANENT(ln)) { - nd6_llinfo_settimer(ln, + nd6_llinfo_settimer_locked(ln, (long)ND_IFINFO(ifp)->reachable * hz); } } else { if (lladdr != NULL && llchange) { ln->ln_state = ND6_LLINFO_STALE; - nd6_llinfo_settimer(ln, + nd6_llinfo_settimer_locked(ln, (long)V_nd6_gctimer * hz); } } @@ -822,9 +828,8 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len) */ struct nd_defrouter *dr; struct in6_addr *in6; - int s; - in6 = &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr; + in6 = &L3_ADDR_SIN6(ln)->sin6_addr; /* * Lock to protect the default router list. @@ -832,8 +837,7 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len) * is only called under the network software interrupt * context. However, we keep it just for safety. */ - s = splnet(); - dr = defrouter_lookup(in6, ifp); + dr = defrouter_lookup(in6, ln->lle_tbl->llt_ifp); if (dr) defrtrlist_del(dr); else if (!V_ip6_forwarding) { @@ -846,21 +850,23 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len) */ rt6_flush(&ip6->ip6_src, ifp); } - splx(s); } ln->ln_router = is_router; } - rt->rt_flags &= ~RTF_REJECT; - ln->ln_asked = 0; - if (ln->ln_hold) { + /* XXX - QL + * Does this matter? + * rt->rt_flags &= ~RTF_REJECT; + */ + ln->la_asked = 0; + if (ln->la_hold) { struct mbuf *m_hold, *m_hold_next; /* - * reset the ln_hold in advance, to explicitly - * prevent a ln_hold lookup in nd6_output() + * reset the la_hold in advance, to explicitly + * prevent a la_hold lookup in nd6_output() * (wouldn't happen, though...) */ - for (m_hold = ln->ln_hold; + for (m_hold = ln->la_hold, ln->la_hold = NULL; m_hold; m_hold = m_hold_next) { m_hold_next = m_hold->m_nextpkt; m_hold->m_nextpkt = NULL; @@ -868,17 +874,25 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len) * we assume ifp is not a loopback here, so just set * the 2nd argument as the 1st one. */ - nd6_output(ifp, ifp, m_hold, - (struct sockaddr_in6 *)rt_key(rt), rt); + nd6_output_lle(ifp, ifp, m_hold, L3_ADDR_SIN6(ln), NULL, ln, &chain); } - ln->ln_hold = NULL; } - freeit: + if (ln != NULL) { + if (chain) + memcpy(&sin6, L3_ADDR_SIN6(ln), sizeof(sin6)); + LLE_WUNLOCK(ln); + + if (chain) + nd6_output_flush(ifp, ifp, chain, &sin6, NULL); + } m_freem(m); return; bad: + if (ln != NULL) + LLE_WUNLOCK(ln); + V_icmp6stat.icp6s_badna++; m_freem(m); } diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c index c9ed36d..7df364e 100644 --- a/sys/netinet6/nd6_rtr.c +++ b/sys/netinet6/nd6_rtr.c @@ -58,6 +58,7 @@ __FBSDID("$FreeBSD$"); #include <net/vnet.h> #include <netinet/in.h> +#include <net/if_llatbl.h> #include <netinet6/in6_var.h> #include <netinet6/in6_ifattach.h> #include <netinet/ip6.h> @@ -471,10 +472,8 @@ defrouter_addreq(struct nd_defrouter *new) (struct sockaddr *)&gate, (struct sockaddr *)&mask, RTF_GATEWAY, &newrt); if (newrt) { - RT_LOCK(newrt); nd6_rtmsg(RTM_ADD, newrt); /* tell user process */ - RT_REMREF(newrt); - RT_UNLOCK(newrt); + RTFREE(newrt); } if (error == 0) new->installed = 1; @@ -615,8 +614,7 @@ defrouter_select(void) INIT_VNET_INET6(curvnet); int s = splnet(); struct nd_defrouter *dr, *selected_dr = NULL, *installed_dr = NULL; - struct rtentry *rt = NULL; - struct llinfo_nd6 *ln = NULL; + struct llentry *ln = NULL; /* * This function should be called only when acting as an autoconfigured @@ -648,12 +646,15 @@ defrouter_select(void) */ for (dr = TAILQ_FIRST(&V_nd_defrouter); dr; dr = TAILQ_NEXT(dr, dr_entry)) { + IF_AFDATA_LOCK(dr->ifp); if (selected_dr == NULL && - (rt = nd6_lookup(&dr->rtaddr, 0, dr->ifp)) && - (ln = (struct llinfo_nd6 *)rt->rt_llinfo) && + (ln = nd6_lookup(&dr->rtaddr, 0, dr->ifp)) && ND6_IS_LLINFO_PROBREACH(ln)) { selected_dr = dr; } + IF_AFDATA_UNLOCK(dr->ifp); + if (ln != NULL) + LLE_RUNLOCK(ln); if (dr->installed && installed_dr == NULL) installed_dr = dr; @@ -676,12 +677,16 @@ defrouter_select(void) selected_dr = TAILQ_FIRST(&V_nd_defrouter); else selected_dr = TAILQ_NEXT(installed_dr, dr_entry); - } else if (installed_dr && - (rt = nd6_lookup(&installed_dr->rtaddr, 0, installed_dr->ifp)) && - (ln = (struct llinfo_nd6 *)rt->rt_llinfo) && - ND6_IS_LLINFO_PROBREACH(ln) && - rtpref(selected_dr) <= rtpref(installed_dr)) { - selected_dr = installed_dr; + } else if (installed_dr) { + IF_AFDATA_LOCK(installed_dr->ifp); + if ((ln = nd6_lookup(&installed_dr->rtaddr, 0, installed_dr->ifp)) && + ND6_IS_LLINFO_PROBREACH(ln) && + rtpref(selected_dr) <= rtpref(installed_dr)) { + selected_dr = installed_dr; + } + IF_AFDATA_UNLOCK(installed_dr->ifp); + if (ln != NULL) + LLE_RUNLOCK(ln); } /* @@ -1323,18 +1328,21 @@ static struct nd_pfxrouter * find_pfxlist_reachable_router(struct nd_prefix *pr) { struct nd_pfxrouter *pfxrtr; - struct rtentry *rt; - struct llinfo_nd6 *ln; + struct llentry *ln; + int canreach; - for (pfxrtr = LIST_FIRST(&pr->ndpr_advrtrs); pfxrtr; + for (pfxrtr = LIST_FIRST(&pr->ndpr_advrtrs); pfxrtr != NULL; pfxrtr = LIST_NEXT(pfxrtr, pfr_entry)) { - if ((rt = nd6_lookup(&pfxrtr->router->rtaddr, 0, - pfxrtr->router->ifp)) && - (ln = (struct llinfo_nd6 *)rt->rt_llinfo) && - ND6_IS_LLINFO_PROBREACH(ln)) - break; /* found */ + IF_AFDATA_LOCK(pfxrtr->router->ifp); + ln = nd6_lookup(&pfxrtr->router->rtaddr, 0, pfxrtr->router->ifp); + IF_AFDATA_UNLOCK(pfxrtr->router->ifp); + if (ln == NULL) + continue; + canreach = ND6_IS_LLINFO_PROBREACH(ln); + LLE_RUNLOCK(ln); + if (canreach) + break; } - return (pfxrtr); } @@ -1541,8 +1549,10 @@ nd6_prefix_onlink(struct nd_prefix *pr) struct nd_prefix *opr; u_long rtflags; int error = 0; + struct radix_node_head *rnh; struct rtentry *rt = NULL; char ip6buf[INET6_ADDRSTRLEN]; + struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; /* sanity check */ if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0) { @@ -1609,21 +1619,24 @@ nd6_prefix_onlink(struct nd_prefix *pr) bzero(&mask6, sizeof(mask6)); mask6.sin6_len = sizeof(mask6); mask6.sin6_addr = pr->ndpr_mask; - rtflags = ifa->ifa_flags | RTF_CLONING | RTF_UP; - if (nd6_need_cache(ifp)) { - /* explicitly set in case ifa_flags does not set the flag. */ - rtflags |= RTF_CLONING; - } else { - /* - * explicitly clear the cloning bit in case ifa_flags sets it. - */ - rtflags &= ~RTF_CLONING; - } + rtflags = ifa->ifa_flags | RTF_UP; error = rtrequest(RTM_ADD, (struct sockaddr *)&pr->ndpr_prefix, ifa->ifa_addr, (struct sockaddr *)&mask6, rtflags, &rt); if (error == 0) { - if (rt != NULL) /* this should be non NULL, though */ + if (rt != NULL) /* this should be non NULL, though */ { + rnh = V_rt_tables[rt->rt_fibnum][AF_INET6]; + RADIX_NODE_HEAD_LOCK(rnh); + RT_LOCK(rt); + if (!rt_setgate(rt, rt_key(rt), (struct sockaddr *)&null_sdl)) { + ((struct sockaddr_dl *)rt->rt_gateway)->sdl_type = + rt->rt_ifp->if_type; + ((struct sockaddr_dl *)rt->rt_gateway)->sdl_index = + rt->rt_ifp->if_index; + } + RADIX_NODE_HEAD_UNLOCK(rnh); nd6_rtmsg(RTM_ADD, rt); + RT_UNLOCK(rt); + } pr->ndpr_stateflags |= NDPRF_ONLINK; } else { char ip6bufg[INET6_ADDRSTRLEN], ip6bufm[INET6_ADDRSTRLEN]; diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c index b132751..d342bc8 100644 --- a/sys/netinet6/raw_ip6.c +++ b/sys/netinet6/raw_ip6.c @@ -168,10 +168,10 @@ rip6_input(struct mbuf **mp, int *offp, int proto) INP_INFO_RLOCK(&V_ripcbinfo); LIST_FOREACH(in6p, &V_ripcb, inp_list) { /* XXX inp locking */ - if ((in6p->in6p_vflag & INP_IPV6) == 0) + if ((in6p->inp_vflag & INP_IPV6) == 0) continue; - if (in6p->in6p_ip6_nxt && - in6p->in6p_ip6_nxt != proto) + if (in6p->inp_ip_p && + in6p->inp_ip_p != proto) continue; if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) && !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst)) @@ -193,7 +193,7 @@ rip6_input(struct mbuf **mp, int *offp, int proto) continue; } } - if (last) { + if (last != NULL) { struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); #ifdef IPSEC @@ -207,12 +207,12 @@ rip6_input(struct mbuf **mp, int *offp, int proto) } else #endif /* IPSEC */ if (n) { - if (last->in6p_flags & IN6P_CONTROLOPTS || - last->in6p_socket->so_options & SO_TIMESTAMP) + if (last->inp_flags & INP_CONTROLOPTS || + last->inp_socket->so_options & SO_TIMESTAMP) ip6_savecontrol(last, n, &opts); /* strip intermediate headers */ m_adj(n, *offp); - if (sbappendaddr(&last->in6p_socket->so_rcv, + if (sbappendaddr(&last->inp_socket->so_rcv, (struct sockaddr *)&fromsa, n, opts) == 0) { m_freem(n); @@ -220,7 +220,7 @@ rip6_input(struct mbuf **mp, int *offp, int proto) m_freem(opts); V_rip6stat.rip6s_fullsock++; } else - sorwakeup(last->in6p_socket); + sorwakeup(last->inp_socket); opts = NULL; } INP_RUNLOCK(last); @@ -232,7 +232,7 @@ rip6_input(struct mbuf **mp, int *offp, int proto) /* * Check AH/ESP integrity. */ - if (last && ipsec6_in_reject(m, last)) { + if ((last != NULL) && ipsec6_in_reject(m, last)) { m_freem(m); V_ipsec6stat.in_polvio++; V_ip6stat.ip6s_delivered--; @@ -240,20 +240,20 @@ rip6_input(struct mbuf **mp, int *offp, int proto) INP_RUNLOCK(last); } else #endif /* IPSEC */ - if (last) { - if (last->in6p_flags & IN6P_CONTROLOPTS || - last->in6p_socket->so_options & SO_TIMESTAMP) + if (last != NULL) { + if (last->inp_flags & INP_CONTROLOPTS || + last->inp_socket->so_options & SO_TIMESTAMP) ip6_savecontrol(last, m, &opts); /* Strip intermediate headers. */ m_adj(m, *offp); - if (sbappendaddr(&last->in6p_socket->so_rcv, + if (sbappendaddr(&last->inp_socket->so_rcv, (struct sockaddr *)&fromsa, m, opts) == 0) { m_freem(m); if (opts) m_freem(opts); V_rip6stat.rip6s_fullsock++; } else - sorwakeup(last->in6p_socket); + sorwakeup(last->inp_socket); INP_RUNLOCK(last); } else { V_rip6stat.rip6s_nosock++; @@ -353,11 +353,11 @@ rip6_output(m, va_alist) control = va_arg(ap, struct mbuf *); va_end(ap); - in6p = sotoin6pcb(so); + in6p = sotoinpcb(so); INP_WLOCK(in6p); dst = &dstsock->sin6_addr; - if (control) { + if (control != NULL) { if ((error = ip6_setpktopts(control, &opt, in6p->in6p_outputopts, so->so_cred, so->so_proto->pr_protocol)) != 0) { @@ -437,14 +437,14 @@ rip6_output(m, va_alist) * Fill in the rest of the IPv6 header fields. */ ip6->ip6_flow = (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) | - (in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK); + (in6p->inp_flow & IPV6_FLOWINFO_MASK); ip6->ip6_vfc = (ip6->ip6_vfc & ~IPV6_VERSION_MASK) | (IPV6_VERSION & IPV6_VERSION_MASK); /* * ip6_plen will be filled in ip6_output, so not fill it here. */ - ip6->ip6_nxt = in6p->in6p_ip6_nxt; + ip6->ip6_nxt = in6p->inp_ip_p; ip6->ip6_hlim = in6_selecthlim(in6p, oifp); if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 || @@ -491,7 +491,7 @@ rip6_output(m, va_alist) m_freem(m); freectl: - if (control) { + if (control != NULL) { ip6_clearpktopts(&opt, -1); m_freem(control); } @@ -595,7 +595,7 @@ rip6_attach(struct socket *so, int proto, struct thread *td) inp = (struct inpcb *)so->so_pcb; INP_INFO_WUNLOCK(&V_ripcbinfo); inp->inp_vflag |= INP_IPV6; - inp->in6p_ip6_nxt = (long)proto; + inp->inp_ip_p = (long)proto; inp->in6p_hops = -1; /* use kernel default */ inp->in6p_cksum = -1; inp->in6p_icmp6filt = filter; diff --git a/sys/netinet6/raw_ip6.h b/sys/netinet6/raw_ip6.h index 9ebd823..a57253e 100644 --- a/sys/netinet6/raw_ip6.h +++ b/sys/netinet6/raw_ip6.h @@ -48,7 +48,9 @@ struct rip6stat { }; #ifdef _KERNEL +#ifdef VIMAGE_GLOBALS extern struct rip6stat rip6stat; #endif +#endif #endif diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c index cfb0ad6..f1634cb 100644 --- a/sys/netinet6/udp6_usrreq.c +++ b/sys/netinet6/udp6_usrreq.c @@ -153,7 +153,7 @@ udp6_append(struct inpcb *inp, struct mbuf *n, int off, } #endif opts = NULL; - if (inp->in6p_flags & IN6P_CONTROLOPTS || + if (inp->inp_flags & INP_CONTROLOPTS || inp->inp_socket->so_options & SO_TIMESTAMP) ip6_savecontrol(inp, n, &opts); m_adj(n, off + sizeof(struct udphdr)); @@ -259,7 +259,7 @@ udp6_input(struct mbuf **mp, int *offp, int proto) LIST_FOREACH(inp, &V_udb, inp_list) { if ((inp->inp_vflag & INP_IPV6) == 0) continue; - if (inp->in6p_lport != uh->uh_dport) + if (inp->inp_lport != uh->uh_dport) continue; /* * XXX: Do not check source port of incoming datagram @@ -278,7 +278,7 @@ udp6_input(struct mbuf **mp, int *offp, int proto) if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { if (!IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, &ip6->ip6_src) || - inp->in6p_fport != uh->uh_sport) + inp->inp_fport != uh->uh_sport) continue; } @@ -562,7 +562,7 @@ udp6_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr6, fport = sin6->sin6_port; /* allow 0 port */ if (IN6_IS_ADDR_V4MAPPED(faddr)) { - if ((inp->in6p_flags & IN6P_IPV6_V6ONLY)) { + if ((inp->inp_flags & IN6P_IPV6_V6ONLY)) { /* * I believe we should explicitly discard the * packet when mapped addresses are disabled, @@ -606,7 +606,7 @@ udp6_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr6, error = EADDRNOTAVAIL; goto release; } - if (inp->in6p_lport == 0 && + if (inp->inp_lport == 0 && (error = in6_pcbsetport(laddr, inp, td->td_ucred)) != 0) goto release; } else { @@ -615,7 +615,7 @@ udp6_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr6, goto release; } if (IN6_IS_ADDR_V4MAPPED(&inp->in6p_faddr)) { - if ((inp->in6p_flags & IN6P_IPV6_V6ONLY)) { + if ((inp->inp_flags & IN6P_IPV6_V6ONLY)) { /* * XXX: this case would happen when the * application sets the V6ONLY flag after @@ -632,7 +632,7 @@ udp6_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr6, } laddr = &inp->in6p_laddr; faddr = &inp->in6p_faddr; - fport = inp->in6p_fport; + fport = inp->inp_fport; } if (af == AF_INET) @@ -652,7 +652,7 @@ udp6_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr6, * Stuff checksum and output datagram. */ udp6 = (struct udphdr *)(mtod(m, caddr_t) + hlen); - udp6->uh_sport = inp->in6p_lport; /* lport is always set in the PCB */ + udp6->uh_sport = inp->inp_lport; /* lport is always set in the PCB */ udp6->uh_dport = fport; if (plen <= 0xffff) udp6->uh_ulen = htons((u_short)plen); @@ -663,7 +663,7 @@ udp6_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr6, switch (af) { case AF_INET6: ip6 = mtod(m, struct ip6_hdr *); - ip6->ip6_flow = inp->in6p_flowinfo & IPV6_FLOWINFO_MASK; + ip6->ip6_flow = inp->inp_flow & IPV6_FLOWINFO_MASK; ip6->ip6_vfc &= ~IPV6_VERSION_MASK; ip6->ip6_vfc |= IPV6_VERSION; #if 0 /* ip6_plen will be filled in ip6_output. */ diff --git a/sys/netinet6/vinet6.h b/sys/netinet6/vinet6.h index d6c3f33..e271d4f 100644 --- a/sys/netinet6/vinet6.h +++ b/sys/netinet6/vinet6.h @@ -78,7 +78,6 @@ struct vnet_inet6 { int _nd6_inuse; int _nd6_allocated; int _nd6_onlink_ns_rfc4861; - struct llinfo_nd6 _llinfo_nd6; struct nd_drhead _nd_defrouter; struct nd_prhead _nd_prefix; struct ifnet * _nd6_defifp; diff --git a/sys/netipsec/ipip_var.h b/sys/netipsec/ipip_var.h index 7fbc643..3d4ee15 100644 --- a/sys/netipsec/ipip_var.h +++ b/sys/netipsec/ipip_var.h @@ -60,6 +60,8 @@ struct ipipstat #ifdef _KERNEL extern int ipip_allow; +#ifdef VIMAGE_GLOBALS extern struct ipipstat ipipstat; +#endif #endif /* _KERNEL */ #endif /* _NETINET_IPIP_H_ */ diff --git a/sys/netipsec/ipsec.c b/sys/netipsec/ipsec.c index 541e42e..108614f 100644 --- a/sys/netipsec/ipsec.c +++ b/sys/netipsec/ipsec.c @@ -230,7 +230,7 @@ SYSCTL_V_STRUCT(V_NET, vnet_ipsec, _net_inet6_ipsec6, IPSECCTL_STATS, static int ipsec4_setspidx_inpcb __P((struct mbuf *, struct inpcb *pcb)); #ifdef INET6 -static int ipsec6_setspidx_in6pcb __P((struct mbuf *, struct in6pcb *pcb)); +static int ipsec6_setspidx_in6pcb __P((struct mbuf *, struct inpcb *pcb)); #endif static int ipsec_setspidx __P((struct mbuf *, struct secpolicyindex *, int)); static void ipsec4_get_ulp __P((struct mbuf *m, struct secpolicyindex *, int)); @@ -376,7 +376,7 @@ ipsec_getpolicybysock(m, dir, inp, error) if (inp->inp_vflag & INP_IPV6PROTO) { #ifdef INET6 *error = ipsec6_setspidx_in6pcb(m, inp); - pcbsp = inp->in6p_sp; + pcbsp = inp->inp_sp; #else *error = EINVAL; /* should not happen */ #endif @@ -578,27 +578,27 @@ ipsec4_setspidx_inpcb(m, pcb) static int ipsec6_setspidx_in6pcb(m, pcb) struct mbuf *m; - struct in6pcb *pcb; + struct inpcb *pcb; { //INIT_VNET_IPSEC(curvnet); struct secpolicyindex *spidx; int error; IPSEC_ASSERT(pcb != NULL, ("null pcb")); - IPSEC_ASSERT(pcb->in6p_sp != NULL, ("null inp_sp")); - IPSEC_ASSERT(pcb->in6p_sp->sp_out != NULL && pcb->in6p_sp->sp_in != NULL, + IPSEC_ASSERT(pcb->inp_sp != NULL, ("null inp_sp")); + IPSEC_ASSERT(pcb->inp_sp->sp_out != NULL && pcb->inp_sp->sp_in != NULL, ("null sp_in || sp_out")); - bzero(&pcb->in6p_sp->sp_in->spidx, sizeof(*spidx)); - bzero(&pcb->in6p_sp->sp_out->spidx, sizeof(*spidx)); + bzero(&pcb->inp_sp->sp_in->spidx, sizeof(*spidx)); + bzero(&pcb->inp_sp->sp_out->spidx, sizeof(*spidx)); - spidx = &pcb->in6p_sp->sp_in->spidx; + spidx = &pcb->inp_sp->sp_in->spidx; error = ipsec_setspidx(m, spidx, 1); if (error) goto bad; spidx->dir = IPSEC_DIR_INBOUND; - spidx = &pcb->in6p_sp->sp_out->spidx; + spidx = &pcb->inp_sp->sp_out->spidx; error = ipsec_setspidx(m, spidx, 1); if (error) goto bad; @@ -607,8 +607,8 @@ ipsec6_setspidx_in6pcb(m, pcb) return 0; bad: - bzero(&pcb->in6p_sp->sp_in->spidx, sizeof(*spidx)); - bzero(&pcb->in6p_sp->sp_out->spidx, sizeof(*spidx)); + bzero(&pcb->inp_sp->sp_in->spidx, sizeof(*spidx)); + bzero(&pcb->inp_sp->sp_out->spidx, sizeof(*spidx)); return error; } #endif @@ -1245,7 +1245,7 @@ ipsec_delete_pcbpolicy(inp) #ifdef INET6 int ipsec6_set_policy(in6p, optname, request, len, cred) - struct in6pcb *in6p; + struct inpcb *in6p; int optname; caddr_t request; size_t len; @@ -1265,10 +1265,10 @@ ipsec6_set_policy(in6p, optname, request, len, cred) /* select direction */ switch (xpl->sadb_x_policy_dir) { case IPSEC_DIR_INBOUND: - pcb_sp = &in6p->in6p_sp->sp_in; + pcb_sp = &in6p->inp_sp->sp_in; break; case IPSEC_DIR_OUTBOUND: - pcb_sp = &in6p->in6p_sp->sp_out; + pcb_sp = &in6p->inp_sp->sp_out; break; default: ipseclog((LOG_ERR, "%s: invalid direction=%u\n", __func__, @@ -1281,7 +1281,7 @@ ipsec6_set_policy(in6p, optname, request, len, cred) int ipsec6_get_policy(in6p, request, len, mp) - struct in6pcb *in6p; + struct inpcb *in6p; caddr_t request; size_t len; struct mbuf **mp; @@ -1293,7 +1293,7 @@ ipsec6_get_policy(in6p, request, len, mp) /* sanity check. */ if (in6p == NULL || request == NULL || mp == NULL) return EINVAL; - IPSEC_ASSERT(in6p->in6p_sp != NULL, ("null in6p_sp")); + IPSEC_ASSERT(in6p->inp_sp != NULL, ("null inp_sp")); if (len < sizeof(*xpl)) return EINVAL; xpl = (struct sadb_x_policy *)request; @@ -1301,10 +1301,10 @@ ipsec6_get_policy(in6p, request, len, mp) /* select direction */ switch (xpl->sadb_x_policy_dir) { case IPSEC_DIR_INBOUND: - pcb_sp = in6p->in6p_sp->sp_in; + pcb_sp = in6p->inp_sp->sp_in; break; case IPSEC_DIR_OUTBOUND: - pcb_sp = in6p->in6p_sp->sp_out; + pcb_sp = in6p->inp_sp->sp_out; break; default: ipseclog((LOG_ERR, "%s: invalid direction=%u\n", __func__, @@ -1684,7 +1684,7 @@ size_t ipsec6_hdrsiz(m, dir, in6p) struct mbuf *m; u_int dir; - struct in6pcb *in6p; + struct inpcb *in6p; { INIT_VNET_IPSEC(curvnet); struct secpolicy *sp; @@ -1692,7 +1692,7 @@ ipsec6_hdrsiz(m, dir, in6p) size_t size; IPSEC_ASSERT(m != NULL, ("null mbuf")); - IPSEC_ASSERT(in6p == NULL || in6p->in6p_socket != NULL, + IPSEC_ASSERT(in6p == NULL || in6p->inp_socket != NULL, ("socket w/o inpcb")); /* get SP for this packet */ diff --git a/sys/netipsec/key.c b/sys/netipsec/key.c index f65d1f1..4906999 100644 --- a/sys/netipsec/key.c +++ b/sys/netipsec/key.c @@ -1160,42 +1160,24 @@ key_freeso(struct socket *so) IPSEC_ASSERT(so != NULL, ("null so")); switch (so->so_proto->pr_domain->dom_family) { +#if defined(INET) || defined(INET6) #ifdef INET case PF_INET: - { - struct inpcb *pcb = sotoinpcb(so); - - /* Does it have a PCB ? */ - if (pcb == NULL) - return; - key_freesp_so(&pcb->inp_sp->sp_in); - key_freesp_so(&pcb->inp_sp->sp_out); - } - break; #endif #ifdef INET6 case PF_INET6: +#endif { -#ifdef HAVE_NRL_INPCB - struct inpcb *pcb = sotoinpcb(so); + struct inpcb *pcb = sotoinpcb(so); /* Does it have a PCB ? */ if (pcb == NULL) return; key_freesp_so(&pcb->inp_sp->sp_in); key_freesp_so(&pcb->inp_sp->sp_out); -#else - struct in6pcb *pcb = sotoin6pcb(so); - - /* Does it have a PCB ? */ - if (pcb == NULL) - return; - key_freesp_so(&pcb->in6p_sp->sp_in); - key_freesp_so(&pcb->in6p_sp->sp_out); -#endif } break; -#endif /* INET6 */ +#endif /* INET || INET6 */ default: ipseclog((LOG_DEBUG, "%s: unknown address family=%d.\n", __func__, so->so_proto->pr_domain->dom_family)); diff --git a/sys/nfsserver/nfs_serv.c b/sys/nfsserver/nfs_serv.c index 3b860ac..ab09421 100644 --- a/sys/nfsserver/nfs_serv.c +++ b/sys/nfsserver/nfs_serv.c @@ -3615,9 +3615,12 @@ again: * Probe one of the directory entries to see if the filesystem * supports VGET. */ - if (VFS_VGET(vp->v_mount, dp->d_fileno, LK_EXCLUSIVE, &nvp) == - EOPNOTSUPP) { - error = NFSERR_NOTSUPP; + error = VFS_VGET(vp->v_mount, dp->d_fileno, LK_EXCLUSIVE, &nvp); + if (error) { + if (error == EOPNOTSUPP) + error = NFSERR_NOTSUPP; + else + error = NFSERR_SERVERFAULT; vrele(vp); vp = NULL; free((caddr_t)cookies, M_TEMP); diff --git a/sys/pc98/conf/DEFAULTS b/sys/pc98/conf/DEFAULTS index 962c099..c16a29b 100644 --- a/sys/pc98/conf/DEFAULTS +++ b/sys/pc98/conf/DEFAULTS @@ -22,5 +22,5 @@ device uart_ns8250 #device uart_i8251 # Default partitioning schemes -options GEOM_BSD -options GEOM_PC98 +options GEOM_PART_BSD +options GEOM_PART_PC98 diff --git a/sys/pci/if_rl.c b/sys/pci/if_rl.c index 71866ce..d11d5d9 100644 --- a/sys/pci/if_rl.c +++ b/sys/pci/if_rl.c @@ -901,9 +901,15 @@ rl_attach(device_t dev) } if (sc->rl_type == 0) { - device_printf(dev, "unknown device ID: %x\n", rl_did); - error = ENXIO; - goto fail; + device_printf(dev, "unknown device ID: %x assuming 8139\n", + rl_did); + sc->rl_type = RL_8139; + /* + * Read RL_IDR register to get ethernet address as accessing + * EEPROM may not extract correct address. + */ + for (i = 0; i < ETHER_ADDR_LEN; i++) + eaddr[i] = CSR_READ_1(sc, RL_IDR0 + i); } if ((error = rl_dma_alloc(sc)) != 0) diff --git a/sys/pci/if_rlreg.h b/sys/pci/if_rlreg.h index d9df78c..b3569e8 100644 --- a/sys/pci/if_rlreg.h +++ b/sys/pci/if_rlreg.h @@ -131,6 +131,8 @@ #define RL_TBI_ANAR 0x0068 #define RL_TBI_LPAR 0x006A #define RL_GMEDIASTAT 0x006C /* 8 bits */ +#define RL_MACDBG 0x006D /* 8 bits, 8168C SPIN2 only */ +#define RL_GPIO 0x006E /* 8 bits, 8168C SPIN2 only */ #define RL_MAXRXPKTLEN 0x00DA /* 16 bits, chip multiplies by 8 */ #define RL_GTXSTART 0x0038 /* 8 bits */ @@ -888,6 +890,8 @@ struct rl_softc { #define RL_FLAG_PHY8169 0x0400 #define RL_FLAG_PHY8110S 0x0800 #define RL_FLAG_WOLRXENB 0x1000 +#define RL_FLAG_MACSLEEP 0x2000 +#define RL_FLAG_PCIE 0x4000 #define RL_FLAG_LINK 0x8000 }; diff --git a/sys/powerpc/aim/locore.S b/sys/powerpc/aim/locore.S index cfe75d9..60e5e9d 100644 --- a/sys/powerpc/aim/locore.S +++ b/sys/powerpc/aim/locore.S @@ -129,14 +129,6 @@ kernel_text: .text .globl __start __start: -#ifdef FIRMWORKSBUGS - mfmsr 0 - andi. 0,0,PSL_IR|PSL_DR - beq 1f - - bl ofwr_init -1: -#endif li 8,0 li 9,0x100 mtctr 9 @@ -154,7 +146,6 @@ __start: lis 8,openfirmware_entry@ha stw 5,openfirmware_entry@l(8) /* save client interface handler */ - mr 3,5 lis 1,(tmpstk+TMPSTKSZ-16)@ha addi 1,1,(tmpstk+TMPSTKSZ-16)@l @@ -172,7 +163,7 @@ __start: mfsprg3 0 stw 0,16(9) /* ofmsr[4] = sprg3 */ - bl OF_init + bl OF_initial_setup lis 4,end@ha addi 4,4,end@l diff --git a/sys/powerpc/aim/machdep.c b/sys/powerpc/aim/machdep.c index 13fc2a7..2199cb1 100644 --- a/sys/powerpc/aim/machdep.c +++ b/sys/powerpc/aim/machdep.c @@ -291,9 +291,19 @@ powerpc_init(u_int startkernel, u_int endkernel, u_int basekernel, void *mdp) __asm __volatile("mtsprg 0, %0" :: "r"(pc)); + /* + * Init mutexes, which we use heavily in PMAP + */ + mutex_init(); /* + * Install the OF client interface + */ + + OF_bootstrap(); + + /* * Initialize the console before printing anything. */ cninit(); @@ -307,8 +317,6 @@ powerpc_init(u_int startkernel, u_int endkernel, u_int basekernel, void *mdp) kdb_init(); - kobj_machdep_init(); - /* * XXX: Initialize the interrupt tables. * Disable translation in case the vector area diff --git a/sys/powerpc/aim/ofw_machdep.c b/sys/powerpc/aim/ofw_machdep.c index 2755819..0d5f03b 100644 --- a/sys/powerpc/aim/ofw_machdep.c +++ b/sys/powerpc/aim/ofw_machdep.c @@ -65,6 +65,10 @@ static struct mem_region OFfree[OFMEM_REGIONS + 3]; extern register_t ofmsr[5]; extern struct pmap ofw_pmap; static int (*ofwcall)(void *); +static void *fdt; +int ofw_real_mode; + +static int openfirmware(void *args); /* * Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback. @@ -192,13 +196,45 @@ mem_regions(struct mem_region **memp, int *memsz, } void -set_openfirm_callback(int (*openfirm)(void *)) +OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *)) { + if (ofmsr[0] & PSL_DR) + ofw_real_mode = 0; + else + ofw_real_mode = 1; ofwcall = openfirm; + fdt = fdt_ptr; } -int +boolean_t +OF_bootstrap() +{ + boolean_t status = FALSE; + + if (ofwcall != NULL) { + if (ofw_real_mode) + status = OF_install(OFW_STD_REAL, 0); + else + status = OF_install(OFW_STD_DIRECT, 0); + + if (status != TRUE) + return status; + + OF_init(openfirmware); + } else { + status = OF_install(OFW_FDT, 0); + + if (status != TRUE) + return status; + + OF_init(fdt); + } + + return (status); +} + +static int openfirmware(void *args) { long oldmsr; @@ -206,6 +242,9 @@ openfirmware(void *args) u_int srsave[16]; u_int i; + if (pmap_bootstrapped && ofw_real_mode) + args = (void *)pmap_kextract((vm_offset_t)args); + __asm __volatile( "\t" "sync\n\t" "mfmsr %0\n\t" @@ -217,7 +256,7 @@ openfirmware(void *args) ofw_sprg_prepare(); - if (pmap_bootstrapped) { + if (pmap_bootstrapped && !ofw_real_mode) { /* * Swap the kernel's address space with Open Firmware's */ @@ -236,7 +275,7 @@ openfirmware(void *args) result = ofwcall(args); - if (pmap_bootstrapped) { + if (pmap_bootstrapped && !ofw_real_mode) { /* * Restore the kernel's addr space. The isync() doesn;t * work outside the loop unless mtsrin() is open-coded diff --git a/sys/powerpc/booke/interrupt.c b/sys/powerpc/booke/interrupt.c index 1d20772..01ee3d9 100644 --- a/sys/powerpc/booke/interrupt.c +++ b/sys/powerpc/booke/interrupt.c @@ -93,7 +93,6 @@ dump_frame(struct trapframe *frame) printf("\n"); } - void powerpc_crit_interrupt(struct trapframe *framep) { diff --git a/sys/powerpc/booke/locore.S b/sys/powerpc/booke/locore.S index a6335e6..e4df6af 100644 --- a/sys/powerpc/booke/locore.S +++ b/sys/powerpc/booke/locore.S @@ -1,4 +1,5 @@ /*- + * Copyright (C) 2007-2008 Semihalf, Rafal Jaworowski <raj@semihalf.com> * Copyright (C) 2006 Semihalf, Marian Balakowicz <m8@semihalf.com> * All rights reserved. * @@ -10,8 +11,6 @@ * 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. - * 3. 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 @@ -29,8 +28,8 @@ #include "assym.s" -#include <machine/param.h> #include <machine/asm.h> +#include <machine/param.h> #include <machine/spr.h> #include <machine/psl.h> #include <machine/pte.h> @@ -60,207 +59,140 @@ kernel_text: __start: /* - * Assumption on a boot loader: + * Assumptions on the boot loader: * - system memory starts from physical address 0 - * - kernel is loaded at 16MB boundary * - it's mapped by a single TBL1 entry * - TLB1 mapping is 1:1 pa to va + * - kernel is loaded at 16MB boundary * - all PID registers are set to the same value + * - CPU is running in AS=0 * - * Loader register use: + * Registers contents provided by the loader(8): * r1 : stack pointer * r3 : metadata pointer * * We rearrange the TLB1 layout as follows: - * - find AS and entry kernel started in + * - find TLB1 entry we started in * - make sure it's protected, ivalidate other entries - * - create temp entry in the second AS (make sure it's not TLB[15]) + * - create temp entry in the second AS (make sure it's not TLB[1]) * - switch to temp mapping - * - map 16MB of RAM in TLB1[15] + * - map 16MB of RAM in TLB1[1] * - use AS=1, set EPN to KERNBASE and RPN to kernel load address - * - switch to to TLB1[15] mapping + * - switch to to TLB1[1] mapping * - invalidate temp mapping * - * locore register use: + * locore registers use: * r1 : stack pointer - * r2 : unused - * r3 : kernel_text - * r4 : _end - * r5 : metadata pointer - * r6-r9 : unused - * r10 : entry we started in - * r11 : temp entry - * r12 : AS we started in - * r13-r31 : auxiliary registers + * r2 : trace pointer (AP only, for early diagnostics) + * r3-r27 : scratch registers + * r28 : kernload + * r29 : temp TLB1 entry + * r30 : initial TLB1 entry we started in + * r31 : metadata pointer */ /* - * Move metadata ptr to r5 + * Keep metadata ptr in r31 for later use. */ - mr %r5, %r3 + mr %r31, %r3 /* * Initial cleanup */ - li %r16, 0x200 /* Keep debug exceptions for CodeWarrior. */ - mtmsr %r16 - isync -#if 0 - mtspr SPR_HID0, %r16 - isync - msync - mtspr SPR_HID1, %r16 + li %r3, PSL_DE /* Keep debug exceptions for CodeWarrior. */ + mtmsr %r3 isync -#endif - /* Issue INV_ALL Invalidate on TLB0 */ - li %r16, 0x04 - tlbivax 0, %r16 - isync - msync + /* Invalidate all entries in TLB0 */ + li %r3, 0 + bl tlb_inval_all /* - * Use tblsx to locate the TLB1 entry that maps kernel code + * Locate the TLB1 entry that maps this code */ - bl 1f /* Current address */ -1: mflr %r15 - - /* Find entry that maps current address */ - mfspr %r17, SPR_PID0 - slwi %r17, %r17, MAS6_SPID0_SHIFT - mtspr SPR_MAS6, %r17 - isync - tlbsx 0, %r15 - - /* Copy entry number to r10 */ - mfspr %r17, SPR_MAS0 - rlwinm %r10, %r17, 16, 28, 31 - - /* Invalidate TLB1, skipping our entry. */ - mfspr %r17, SPR_TLB1CFG /* Get number of entries */ - andi. %r17, %r17, TLBCFG_NENTRY_MASK@l - li %r16, 0 /* Start from Entry 0 */ - -2: lis %r15, MAS0_TLBSEL1@h /* Select TLB1 */ - rlwimi %r15, %r16, 16, 12, 15 - mtspr SPR_MAS0, %r15 - isync - tlbre - mfspr %r15, SPR_MAS1 - cmpw %r16, %r10 - beq 3f - /* Clear VALID and IPROT bits for other entries */ - rlwinm %r15, %r15, 0, 2, 31 - mtspr SPR_MAS1, %r15 - isync - tlbwe - isync - msync -3: addi %r16, %r16, 1 - cmpw %r16, %r17 /* Check if this is the last entry */ - bne 2b + bl 1f +1: mflr %r3 + bl tlb1_find_current /* the entry number found is returned in r30 */ + bl tlb1_inval_all_but_current /* - * Create temporary mapping in the other Address Space + * Create temporary mapping in AS=1 and switch to it */ - lis %r17, MAS0_TLBSEL1@h /* Select TLB1 */ - rlwimi %r17, %r10, 16, 12, 15 /* Select our entry */ - mtspr SPR_MAS0, %r17 - isync - tlbre /* Read it in */ - - /* Prepare and write temp entry */ - lis %r17, MAS0_TLBSEL1@h /* Select TLB1 */ - addi %r11, %r10, 0x1 /* Use next entry. */ - rlwimi %r17, %r11, 16, 12, 15 /* Select temp entry */ - mtspr SPR_MAS0, %r17 - isync - - mfspr %r16, SPR_MAS1 - li %r15, 1 /* AS 1 */ - rlwimi %r16, %r15, 12, 19, 19 - mtspr SPR_MAS1, %r16 - li %r17, 0 - rlwimi %r16, %r17, 0, 8, 15 /* Global mapping, TID=0 */ - isync - - tlbwe - isync - msync - - mfmsr %r16 - ori %r16, %r16, 0x30 /* Switch to AS 1. */ - - bl 4f /* Find current execution address */ -4: mflr %r15 - addi %r15, %r15, 20 /* Increment to instruction after rfi */ - mtspr SPR_SRR0, %r15 - mtspr SPR_SRR1, %r16 + bl tlb1_temp_mapping_as1 + + mfmsr %r3 + ori %r3, %r3, (PSL_IS | PSL_DS) + bl 2f +2: mflr %r4 + addi %r4, %r4, 20 + mtspr SPR_SRR0, %r4 + mtspr SPR_SRR1, %r3 rfi /* Switch context */ /* * Invalidate initial entry */ - mr %r22, %r10 + mr %r3, %r30 bl tlb1_inval_entry /* * Setup final mapping in TLB1[1] and switch to it */ /* Final kernel mapping, map in 16 MB of RAM */ - lis %r16, MAS0_TLBSEL1@h /* Select TLB1 */ - li %r17, 1 /* Entry 1 */ - rlwimi %r16, %r17, 16, 12, 15 - mtspr SPR_MAS0, %r16 + lis %r3, MAS0_TLBSEL1@h /* Select TLB1 */ + li %r4, 1 /* Entry 1 */ + rlwimi %r3, %r4, 16, 12, 15 + mtspr SPR_MAS0, %r3 isync - li %r16, (TLB_SIZE_16M << MAS1_TSIZE_SHIFT)@l - oris %r16, %r16, (MAS1_VALID | MAS1_IPROT)@h - mtspr SPR_MAS1, %r16 + li %r3, (TLB_SIZE_16M << MAS1_TSIZE_SHIFT)@l + oris %r3, %r3, (MAS1_VALID | MAS1_IPROT)@h + mtspr SPR_MAS1, %r3 /* note TS was not filled, so it's TS=0 */ isync - lis %r19, KERNBASE@h - ori %r19, %r19, KERNBASE@l - mtspr SPR_MAS2, %r19 /* Set final EPN, clear WIMG */ + lis %r3, KERNBASE@h + ori %r3, %r3, KERNBASE@l /* EPN = KERNBASE */ + mtspr SPR_MAS2, %r3 isync - bl 5f -5: mflr %r16 /* Use current address */ - lis %r18, 0xff00 /* 16MB alignment mask */ - and %r16, %r16, %r18 - mr %r25, %r16 /* Copy kernel load address */ - ori %r16, %r16, (MAS3_SX | MAS3_SW | MAS3_SR)@l - mtspr SPR_MAS3, %r16 /* Set RPN and protection */ + /* Discover phys load address */ + bl 3f +3: mflr %r4 /* Use current address */ + rlwinm %r4, %r4, 0, 0, 7 /* 16MB alignment mask */ + mr %r28, %r4 /* Keep kernel load address */ + ori %r4, %r4, (MAS3_SX | MAS3_SW | MAS3_SR)@l + mtspr SPR_MAS3, %r4 /* Set RPN and protection */ isync tlbwe isync msync /* Switch to the above TLB1[1] mapping */ - lis %r18, 0x00ff /* 16MB offset mask */ - ori %r18, %r18, 0xffff - bl 6f -6: mflr %r20 /* Use current address */ - and %r20, %r20, %r18 /* Offset from kernel load address */ - add %r20, %r20, %r19 /* Move to kernel virtual address */ - addi %r20, %r20, 32 /* Increment to instr. after rfi */ - li %r21, 0x200 - mtspr SPR_SRR0, %r20 - mtspr SPR_SRR1, %r21 + bl 4f +4: mflr %r4 + rlwinm %r4, %r4, 0, 8, 31 /* Current offset from kernel load address */ + rlwinm %r3, %r3, 0, 0, 19 + add %r4, %r4, %r3 /* Convert to kernel virtual address */ + addi %r4, %r4, 36 + li %r3, PSL_DE /* Note AS=0 */ + mtspr SPR_SRR0, %r4 + mtspr SPR_SRR1, %r3 rfi - /* Save kernel load address for later use */ - lis %r24, kernload@ha - addi %r24, %r24, kernload@l - stw %r25, 0(%r24) - /* * Invalidate temp mapping */ - mr %r22, %r11 + mr %r3, %r29 bl tlb1_inval_entry /* + * Save kernel load address for later use. + */ + lis %r3, kernload@ha + addi %r3, %r3, kernload@l + stw %r28, 0(%r3) + +/* * Setup a temporary stack */ lis %r1, tmpstack@ha @@ -268,119 +200,203 @@ __start: addi %r1, %r1, (TMPSTACKSZ - 8) /* - * Intialise exception vector offsets + * Initialise exception vector offsets */ bl ivor_setup /* - * Jump to system initialization code - * - * Setup first two arguments for e500_init, metadata (r5) is already in place. + * Set up arguments and jump to system initialization code */ lis %r3, kernel_text@ha addi %r3, %r3, kernel_text@l lis %r4, _end@ha addi %r4, %r4, _end@l + mr %r5, %r31 /* metadata ptr */ + /* Prepare e500 core */ bl e500_init - /* Switch to thread0.td_kstack */ + /* Switch to thread0.td_kstack now */ mr %r1, %r3 li %r3, 0 stw %r3, 0(%r1) - bl mi_startup /* Machine independet part, does not return */ + /* Machine independet part, does not return */ + bl mi_startup + /* NOT REACHED */ +5: b 5b -/************************************************************************/ -/* locore subroutines */ -/************************************************************************/ +/* + * Invalidate all entries in the given TLB. + * + * r3 TLBSEL + */ +tlb_inval_all: + rlwinm %r3, %r3, 3, 0x18 /* TLBSEL */ + ori %r3, %r3, 0x4 /* INVALL */ + tlbivax 0, %r3 + isync + msync -tlb1_inval_entry: - lis %r17, MAS0_TLBSEL1@h /* Select TLB1 */ - rlwimi %r17, %r22, 16, 12, 15 /* Select our entry */ - mtspr SPR_MAS0, %r17 + tlbsync + msync + blr + +/* + * expects address to look up in r3, returns entry number in r30 + * + * FIXME: the hidden assumption is we are now running in AS=0, but we should + * retrieve actual AS from MSR[IS|DS] and put it in MAS6[SAS] + */ +tlb1_find_current: + mfspr %r17, SPR_PID0 + slwi %r17, %r17, MAS6_SPID0_SHIFT + mtspr SPR_MAS6, %r17 isync - tlbre /* Read it in */ + tlbsx 0, %r3 + mfspr %r17, SPR_MAS0 + rlwinm %r30, %r17, 16, 20, 31 /* MAS0[ESEL] -> r30 */ - li %r16, 0 - mtspr SPR_MAS1, %r16 + /* Make sure we have IPROT set on the entry */ + mfspr %r17, SPR_MAS1 + oris %r17, %r17, MAS1_IPROT@h + mtspr SPR_MAS1, %r17 isync tlbwe isync msync blr -ivor_setup: - /* Set base address of interrupt handler routines */ - lis %r21, interrupt_vector_base@h - mtspr SPR_IVPR, %r21 - - /* Assign interrupt handler routines offsets */ - li %r21, int_critical_input@l - mtspr SPR_IVOR0, %r21 - li %r21, int_machine_check@l - mtspr SPR_IVOR1, %r21 - li %r21, int_data_storage@l - mtspr SPR_IVOR2, %r21 - li %r21, int_instr_storage@l - mtspr SPR_IVOR3, %r21 - li %r21, int_external_input@l - mtspr SPR_IVOR4, %r21 - li %r21, int_alignment@l - mtspr SPR_IVOR5, %r21 - li %r21, int_program@l - mtspr SPR_IVOR6, %r21 - li %r21, int_syscall@l - mtspr SPR_IVOR8, %r21 - li %r21, int_decrementer@l - mtspr SPR_IVOR10, %r21 - li %r21, int_fixed_interval_timer@l - mtspr SPR_IVOR11, %r21 - li %r21, int_watchdog@l - mtspr SPR_IVOR12, %r21 - li %r21, int_data_tlb_error@l - mtspr SPR_IVOR13, %r21 - li %r21, int_inst_tlb_error@l - mtspr SPR_IVOR14, %r21 - li %r21, int_debug@l - mtspr SPR_IVOR15, %r21 - blr - /* - * void tlb1_inval_va(vm_offset_t va) + * Invalidates a single entry in TLB1. * - * r3 - va to invalidate + * r3 ESEL + * r4-r5 scratched */ -ENTRY(tlb1_inval_va) - /* EA mask */ - lis %r6, 0xffff - ori %r6, %r6, 0xf000 - and %r3, %r3, %r6 +tlb1_inval_entry: + lis %r4, MAS0_TLBSEL1@h /* Select TLB1 */ + rlwimi %r4, %r3, 16, 12, 15 /* Select our entry */ + mtspr SPR_MAS0, %r4 + isync + tlbre + li %r5, 0 /* MAS1[V] = 0 */ + mtspr SPR_MAS1, %r5 + isync + tlbwe + isync + msync + blr - /* Select TLB1 */ - ori %r3, %r3, 0x08 +/* + * r30 current entry number + * r29 returned temp entry + * r3-r5 scratched + */ +tlb1_temp_mapping_as1: + /* Read our current translation */ + lis %r3, MAS0_TLBSEL1@h /* Select TLB1 */ + rlwimi %r3, %r30, 16, 12, 15 /* Select our current entry */ + mtspr SPR_MAS0, %r3 + isync + tlbre + /* + * Prepare and write temp entry + * + * FIXME this is not robust against overflow i.e. when the current + * entry is the last in TLB1 + */ + lis %r3, MAS0_TLBSEL1@h /* Select TLB1 */ + addi %r29, %r30, 1 /* Use next entry. */ + li %r4, 1 + cmpw %r4, %r29 + bne 1f + addi %r29, %r29, 1 +1: rlwimi %r3, %r29, 16, 12, 15 /* Select temp entry */ + mtspr SPR_MAS0, %r3 + isync + mfspr %r5, SPR_MAS1 + li %r4, 1 /* AS=1 */ + rlwimi %r5, %r4, 12, 19, 19 + li %r4, 0 /* Global mapping, TID=0 */ + rlwimi %r5, %r4, 16, 8, 15 + oris %r5, %r5, (MAS1_VALID | MAS1_IPROT)@h + mtspr SPR_MAS1, %r5 isync - tlbivax 0, %r3 + tlbwe isync msync blr /* - * void tlb0_inval_va(vm_offset_t va) + * Loops over TLB1, invalidates all entries skipping the one which currently + * maps this code. * - * r3 - va to invalidate + * r30 current entry + * r3-r5 scratched */ -ENTRY(tlb0_inval_va) - /* EA mask, this also clears TLBSEL, selecting TLB0 */ - lis %r6, 0xffff - ori %r6, %r6, 0xf000 - and %r3, %r3, %r6 - +tlb1_inval_all_but_current: + mr %r6, %r3 + mfspr %r3, SPR_TLB1CFG /* Get number of entries */ + andi. %r3, %r3, TLBCFG_NENTRY_MASK@l + li %r4, 0 /* Start from Entry 0 */ +1: lis %r5, MAS0_TLBSEL1@h + rlwimi %r5, %r4, 16, 12, 15 + mtspr SPR_MAS0, %r5 isync - tlbivax 0, %r3 + tlbre + mfspr %r5, SPR_MAS1 + cmpw %r4, %r30 /* our current entry? */ + beq 2f + rlwinm %r5, %r5, 0, 2, 31 /* clear VALID and IPROT bits */ + mtspr SPR_MAS1, %r5 + isync + tlbwe isync msync +2: addi %r4, %r4, 1 + cmpw %r4, %r3 /* Check if this is the last entry */ + bne 1b + blr + +/************************************************************************/ +/* locore subroutines */ +/************************************************************************/ + +ivor_setup: + /* Set base address of interrupt handler routines */ + lis %r3, interrupt_vector_base@h + mtspr SPR_IVPR, %r3 + + /* Assign interrupt handler routines offsets */ + li %r3, int_critical_input@l + mtspr SPR_IVOR0, %r3 + li %r3, int_machine_check@l + mtspr SPR_IVOR1, %r3 + li %r3, int_data_storage@l + mtspr SPR_IVOR2, %r3 + li %r3, int_instr_storage@l + mtspr SPR_IVOR3, %r3 + li %r3, int_external_input@l + mtspr SPR_IVOR4, %r3 + li %r3, int_alignment@l + mtspr SPR_IVOR5, %r3 + li %r3, int_program@l + mtspr SPR_IVOR6, %r3 + li %r3, int_syscall@l + mtspr SPR_IVOR8, %r3 + li %r3, int_decrementer@l + mtspr SPR_IVOR10, %r3 + li %r3, int_fixed_interval_timer@l + mtspr SPR_IVOR11, %r3 + li %r3, int_watchdog@l + mtspr SPR_IVOR12, %r3 + li %r3, int_data_tlb_error@l + mtspr SPR_IVOR13, %r3 + li %r3, int_inst_tlb_error@l + mtspr SPR_IVOR14, %r3 + li %r3, int_debug@l + mtspr SPR_IVOR15, %r3 blr /* @@ -395,6 +411,9 @@ ENTRY(dcache_inval) isync mtspr SPR_L1CSR0, %r3 isync +1: mfspr %r3, SPR_L1CSR0 + andi. %r3, %r3, L1CSR0_DCFI + bne 1b blr ENTRY(dcache_disable) @@ -427,6 +446,9 @@ ENTRY(icache_inval) isync mtspr SPR_L1CSR1, %r3 isync +1: mfspr %r3, SPR_L1CSR1 + andi. %r3, %r3, L1CSR1_ICFI + bne 1b blr ENTRY(icache_disable) @@ -495,7 +517,7 @@ tmpstack: #define INTRCNT_COUNT 256 /* max(HROWPIC_IRQMAX,OPENPIC_IRQMAX) */ GLOBAL(kernload) - .long + .long 0 GLOBAL(intrnames) .space INTRCNT_COUNT * (MAXCOMLEN + 1) * 2 GLOBAL(eintrnames) diff --git a/sys/powerpc/booke/machdep.c b/sys/powerpc/booke/machdep.c index 218127d..a48ece1 100644 --- a/sys/powerpc/booke/machdep.c +++ b/sys/powerpc/booke/machdep.c @@ -10,8 +10,6 @@ * 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. - * 3. 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 @@ -88,7 +86,6 @@ __FBSDID("$FreeBSD$"); #include <sys/cdefs.h> #include <sys/types.h> - #include <sys/param.h> #include <sys/proc.h> #include <sys/systm.h> @@ -137,6 +134,9 @@ __FBSDID("$FreeBSD$"); #include <sys/linker.h> #include <sys/reboot.h> +#include <powerpc/mpc85xx/ocpbus.h> +#include <powerpc/mpc85xx/mpc85xx.h> + #ifdef DEBUG #define debugf(fmt, args...) printf(fmt, ##args) #else @@ -180,8 +180,8 @@ static void cpu_e500_startup(void *); SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_e500_startup, NULL); void print_kernel_section_addr(void); -void dump_bootinfo(void); -void dump_kenv(void); +void print_bootinfo(void); +void print_kenv(void); u_int e500_init(u_int32_t, u_int32_t, void *); static void @@ -204,16 +204,17 @@ cpu_e500_startup(void *dummy) printf("Physical memory chunk(s):\n"); for (indx = 0; phys_avail[indx + 1] != 0; indx += 2) { size = phys_avail[indx + 1] - phys_avail[indx]; + printf("0x%08x - 0x%08x, %d bytes (%d pages)\n", - phys_avail[indx], phys_avail[indx + 1] - 1, size, - size / PAGE_SIZE); + phys_avail[indx], phys_avail[indx + 1] - 1, + size, size / PAGE_SIZE); } } vm_ksubmap_init(&kmi); printf("avail memory = %ld (%ld MB)\n", ptoa(cnt.v_free_count), - ptoa(cnt.v_free_count) / 1048576); + ptoa(cnt.v_free_count) / 1048576); /* Set up buffers, so they can be used to read disk labels. */ bufinit(); @@ -235,7 +236,7 @@ kenv_next(char *cp) } void -dump_kenv(void) +print_kenv(void) { int len; char *cp; @@ -253,7 +254,7 @@ dump_kenv(void) } void -dump_bootinfo(void) +print_bootinfo(void) { struct bi_mem_region *mr; struct bi_eth_addr *eth; @@ -291,20 +292,20 @@ print_kernel_section_addr(void) { debugf("kernel image addresses:\n"); - debugf(" kernel_text = 0x%08x\n", (u_int32_t)kernel_text); - debugf(" _etext (sdata) = 0x%08x\n", (u_int32_t)_etext); - debugf(" _edata = 0x%08x\n", (u_int32_t)_edata); - debugf(" __sbss_start = 0x%08x\n", (u_int32_t)__sbss_start); - debugf(" __sbss_end = 0x%08x\n", (u_int32_t)__sbss_end); - debugf(" __sbss_start = 0x%08x\n", (u_int32_t)__bss_start); - debugf(" _end = 0x%08x\n", (u_int32_t)_end); + debugf(" kernel_text = 0x%08x\n", (uint32_t)kernel_text); + debugf(" _etext (sdata) = 0x%08x\n", (uint32_t)_etext); + debugf(" _edata = 0x%08x\n", (uint32_t)_edata); + debugf(" __sbss_start = 0x%08x\n", (uint32_t)__sbss_start); + debugf(" __sbss_end = 0x%08x\n", (uint32_t)__sbss_end); + debugf(" __sbss_start = 0x%08x\n", (uint32_t)__bss_start); + debugf(" _end = 0x%08x\n", (uint32_t)_end); } struct bi_mem_region * bootinfo_mr(void) { - return((struct bi_mem_region *)bootinfo->bi_data); + return ((struct bi_mem_region *)bootinfo->bi_data); } struct bi_eth_addr * @@ -346,7 +347,7 @@ e500_init(u_int32_t startkernel, u_int32_t endkernel, void *mdp) kmdp = preload_search_by_type("elf kernel"); if (kmdp != NULL) { bootinfo = (struct bootinfo *)preload_search_info(kmdp, - MODINFO_METADATA|MODINFOMD_BOOTINFO); + MODINFO_METADATA | MODINFOMD_BOOTINFO); boothowto = MD_FETCH(kmdp, MODINFOMD_HOWTO, int); kern_envp = MD_FETCH(kmdp, MODINFOMD_ENVP, char *); @@ -384,7 +385,7 @@ e500_init(u_int32_t startkernel, u_int32_t endkernel, void *mdp) * Time Base and Decrementer are updated every 8 CCB bus clocks. * HID0[SEL_TBCLK] = 0 */ - decr_config(bootinfo->bi_bus_clk/8); + decr_config(bootinfo->bi_bus_clk / 8); /* Init params/tunables that can be overridden by the loader. */ init_param1(); @@ -397,7 +398,6 @@ e500_init(u_int32_t startkernel, u_int32_t endkernel, void *mdp) pc = &__pcpu[0]; pcpu_init(pc, 0, sizeof(struct pcpu)); pc->pc_curthread = &thread0; - pc->pc_cpuid = 0; __asm __volatile("mtsprg 0, %0" :: "r"(pc)); /* Initialize system mutexes. */ @@ -410,14 +410,17 @@ e500_init(u_int32_t startkernel, u_int32_t endkernel, void *mdp) debugf("e500_init: console initialized\n"); debugf(" arg1 startkernel = 0x%08x\n", startkernel); debugf(" arg2 endkernel = 0x%08x\n", endkernel); - debugf(" arg3 midp = 0x%08x\n", (u_int32_t)mdp); + debugf(" arg3 mdp = 0x%08x\n", (u_int32_t)mdp); debugf(" end = 0x%08x\n", (u_int32_t)end); debugf(" boothowto = 0x%08x\n", boothowto); debugf(" kernel ccsrbar = 0x%08x\n", CCSRBAR_VA); debugf(" MSR = 0x%08x\n", mfmsr()); - dump_bootinfo(); + debugf(" HID0 = 0x%08x\n", mfspr(SPR_HID0)); + debugf(" HID1 = 0x%08x\n", mfspr(SPR_HID1)); + + print_bootinfo(); print_kernel_section_addr(); - dump_kenv(); + print_kenv(); //tlb1_print_entries(); //tlb1_print_tlbentries(); @@ -427,7 +430,6 @@ e500_init(u_int32_t startkernel, u_int32_t endkernel, void *mdp) if (boothowto & RB_KDB) kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); #endif - kobj_machdep_init(); /* Initialise virtual memory. */ pmap_mmu_install(MMU_TYPE_BOOKE, 0); @@ -459,6 +461,7 @@ e500_init(u_int32_t startkernel, u_int32_t endkernel, void *mdp) dcache_inval(); dcache_enable(); } + csr = mfspr(SPR_L1CSR0); if ((boothowto & RB_VERBOSE) != 0 || (csr & L1CSR0_DCE) == 0) printf("L1 D-cache %sabled\n", @@ -470,6 +473,7 @@ e500_init(u_int32_t startkernel, u_int32_t endkernel, void *mdp) icache_inval(); icache_enable(); } + csr = mfspr(SPR_L1CSR1); if ((boothowto & RB_VERBOSE) != 0 || (csr & L1CSR1_ICE) == 0) printf("L1 I-cache %sabled\n", diff --git a/sys/powerpc/include/elf.h b/sys/powerpc/include/elf.h index d2b8e12..422a86a 100644 --- a/sys/powerpc/include/elf.h +++ b/sys/powerpc/include/elf.h @@ -80,9 +80,6 @@ __ElfType(Auxinfo); #define AT_COUNT 13 /* Count of defined aux entry types. */ -/* Used in John Polstra's testbed stuff. */ -#define AT_DEBUG 14 /* Debugging level. */ - /* * Relocation types. */ diff --git a/sys/powerpc/include/ofw_machdep.h b/sys/powerpc/include/ofw_machdep.h index a4b601e..1dd2027 100644 --- a/sys/powerpc/include/ofw_machdep.h +++ b/sys/powerpc/include/ofw_machdep.h @@ -28,9 +28,18 @@ #ifndef _MACHINE_OFW_MACHDEP_H_ #define _MACHINE_OFW_MACHDEP_H_ +#include <sys/cdefs.h> +#include <sys/types.h> +#include <sys/rman.h> #include <sys/bus.h> +#include <dev/ofw/openfirm.h> + +typedef uint32_t cell_t; int OF_decode_addr(phandle_t, int, bus_space_tag_t *, bus_space_handle_t *); void OF_getetheraddr(device_t dev, u_char *addr); +void OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *)); +boolean_t OF_bootstrap(void); + #endif /* _MACHINE_OFW_MACHDEP_H_ */ diff --git a/sys/powerpc/include/param.h b/sys/powerpc/include/param.h index 1b58db9..1a910ba 100644 --- a/sys/powerpc/include/param.h +++ b/sys/powerpc/include/param.h @@ -56,6 +56,9 @@ #ifndef _NO_NAMESPACE_POLLUTION +/* Needed to display interrupts on OFW PCI */ +#define __PCI_REROUTE_INTERRUPT + #ifndef _MACHINE_PARAM_H_ #define _MACHINE_PARAM_H_ diff --git a/sys/powerpc/include/spr.h b/sys/powerpc/include/spr.h index 1662add..70a0012 100644 --- a/sys/powerpc/include/spr.h +++ b/sys/powerpc/include/spr.h @@ -560,14 +560,15 @@ #define SPR_MCSRR1 0x23b /* ..8 571 Machine check SRR1 */ #define SPR_SVR 0x3ff /* ..8 1023 System Version Register */ -#define SVR_MPC8533 0x803c0010 -#define SVR_MPC8533E 0x80340010 -#define SVR_MPC8541 0x80720011 -#define SVR_MPC8541E 0x807a0011 -#define SVR_MPC8555 0x80710011 -#define SVR_MPC8555E 0x80790011 -#define SVR_MPC8572 0x80e00010 -#define SVR_MPC8572E 0x80e80010 +#define SVR_MPC8533 0x803c +#define SVR_MPC8533E 0x8034 +#define SVR_MPC8541 0x8072 +#define SVR_MPC8541E 0x807a +#define SVR_MPC8555 0x8071 +#define SVR_MPC8555E 0x8079 +#define SVR_MPC8572 0x80e0 +#define SVR_MPC8572E 0x80e8 +#define SVR_VER(svr) (((svr) >> 16) & 0xffff) #define SPR_PID0 0x030 /* ..8 Process ID Register 0 */ #define SPR_PID1 0x279 /* ..8 Process ID Register 1 */ @@ -623,5 +624,4 @@ #endif /* #elif defined(E500) */ - #endif /* !_POWERPC_SPR_H_ */ diff --git a/sys/powerpc/mpc85xx/lbc.c b/sys/powerpc/mpc85xx/lbc.c index 4b168b8..2267245 100644 --- a/sys/powerpc/mpc85xx/lbc.c +++ b/sys/powerpc/mpc85xx/lbc.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2006-2008, Juniper Networks, Inc. + * Copyright (c) 2008 Semihalf, Rafal Czubak * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -44,6 +45,8 @@ __FBSDID("$FreeBSD$"); #include <vm/pmap.h> #include <powerpc/mpc85xx/lbc.h> +#include <powerpc/mpc85xx/mpc85xx.h> +#include <powerpc/mpc85xx/ocpbus.h> struct lbc_softc { device_t sc_dev; @@ -54,16 +57,41 @@ struct lbc_softc { int sc_rid; struct rman sc_rman; - uintptr_t sc_kva; + vm_offset_t sc_kva[LBC_DEV_MAX]; }; struct lbc_devinfo { int lbc_devtype; - int lbc_memtype; - /* Also the BAR number */ + /* LBC child unit. It also represents resource table entry number */ int lbc_unit; }; +/* Resources for MPC8555CDS system */ +const struct lbc_resource mpc85xx_lbc_resources[] = { + /* Boot flash bank */ + { + LBC_DEVTYPE_CFI, 0, 0xff800000, 0x00800000, 16, + LBCRES_MSEL_GPCM, LBCRES_DECC_DISABLED, + LBCRES_ATOM_DISABLED, 0 + }, + + /* Second flash bank */ + { + LBC_DEVTYPE_CFI, 1, 0xff000000, 0x00800000, 16, + LBCRES_MSEL_GPCM, LBCRES_DECC_DISABLED, + LBCRES_ATOM_DISABLED, 0 + }, + + /* DS1553 RTC/NVRAM */ + { + LBC_DEVTYPE_RTC, 2, 0xf8000000, 0x8000, 8, + LBCRES_MSEL_GPCM, LBCRES_DECC_DISABLED, + LBCRES_ATOM_DISABLED, 0 + }, + + {0} +}; + static int lbc_probe(device_t); static int lbc_attach(device_t); static int lbc_shutdown(device_t); @@ -108,26 +136,170 @@ static driver_t lbc_driver = { devclass_t lbc_devclass; DRIVER_MODULE(lbc, ocpbus, lbc_driver, lbc_devclass, 0, 0); +static __inline void +lbc_write_reg(struct lbc_softc *sc, bus_size_t off, uint32_t val) +{ + + bus_space_write_4(sc->sc_bst, sc->sc_bsh, off, val); +} + +static __inline uint32_t +lbc_read_reg(struct lbc_softc *sc, bus_size_t off) +{ + + return (bus_space_read_4(sc->sc_bst, sc->sc_bsh, off)); +} + +/* + * Calculate address mask used by OR(n) registers. Use memory region size to + * determine mask value. The size must be a power of two and within the range + * of 32KB - 4GB. Otherwise error code is returned. Value representing + * 4GB size can be passed as 0xffffffff. + */ +static uint32_t +lbc_address_mask(uint32_t size) +{ + int n = 15; + + if (size == ~0UL) + return (0); + + while (n < 32) { + if (size == (1UL << n)) + break; + n++; + } + + if (n == 32) + return (EINVAL); + + return (0xffff8000 << (n - 15)); +} + static device_t -lbc_mk_child(device_t dev, int type, int mtype, int unit) +lbc_mk_child(device_t dev, const struct lbc_resource *lbcres) { struct lbc_devinfo *dinfo; device_t child; + if (lbcres->lbr_unit > LBC_DEV_MAX - 1) + return (NULL); + child = device_add_child(dev, NULL, -1); if (child == NULL) { - device_printf(dev, "could not add child device\n"); + device_printf(dev, "could not add LBC child device\n"); return (NULL); } dinfo = malloc(sizeof(struct lbc_devinfo), M_DEVBUF, M_WAITOK | M_ZERO); - dinfo->lbc_devtype = type; - dinfo->lbc_memtype = mtype; - dinfo->lbc_unit = unit; + dinfo->lbc_devtype = lbcres->lbr_devtype; + dinfo->lbc_unit = lbcres->lbr_unit; device_set_ivars(child, dinfo); return (child); } static int +lbc_init_child(device_t dev, device_t child) +{ + struct lbc_softc *sc; + struct lbc_devinfo *dinfo; + const struct lbc_resource *res; + u_long start, size; + uint32_t regbuff; + int error, unit; + + sc = device_get_softc(dev); + dinfo = device_get_ivars(child); + + res = mpc85xx_lbc_resources; + + regbuff = 0; + unit = -1; + for (; res->lbr_devtype; res++) { + if (res->lbr_unit != dinfo->lbc_unit) + continue; + + start = res->lbr_base_addr; + size = res->lbr_size; + unit = res->lbr_unit; + + /* + * Configure LAW for this LBC device and map its physical + * memory region into KVA + */ + error = law_enable(OCP85XX_TGTIF_LBC, start, size); + if (error) + return (error); + + sc->sc_kva[unit] = (vm_offset_t)pmap_mapdev(start, size); + if (sc->sc_kva[unit] == 0) { + law_disable(OCP85XX_TGTIF_LBC, start, size); + return (ENOSPC); + } + + /* + * Compute and program BR value + */ + regbuff |= start; + + switch (res->lbr_port_size) { + case 8: + regbuff |= (1 << 11); + break; + case 16: + regbuff |= (2 << 11); + break; + case 32: + regbuff |= (3 << 11); + break; + default: + error = EINVAL; + goto fail; + } + regbuff |= (res->lbr_decc << 9); + regbuff |= (res->lbr_wp << 8); + regbuff |= (res->lbr_msel << 5); + regbuff |= (res->lbr_atom << 2); + regbuff |= 1; + + lbc_write_reg(sc, LBC85XX_BR(unit), regbuff); + + /* + * Compute and program OR value + */ + regbuff = 0; + regbuff |= lbc_address_mask(size); + + switch (res->lbr_msel) { + case LBCRES_MSEL_GPCM: + /* TODO Add flag support for option registers */ + regbuff |= 0x00000ff7; + break; + case LBCRES_MSEL_FCM: + printf("FCM mode not supported yet!"); + error = ENOSYS; + goto fail; + case LBCRES_MSEL_UPMA: + case LBCRES_MSEL_UPMB: + case LBCRES_MSEL_UPMC: + printf("UPM mode not supported yet!"); + error = ENOSYS; + goto fail; + } + + lbc_write_reg(sc, LBC85XX_OR(unit), regbuff); + + return (0); + } +fail: + if (unit != -1) { + law_disable(OCP85XX_TGTIF_LBC, start, size); + pmap_unmapdev(sc->sc_kva[unit], size); + return (error); + } else + return (ENOENT); +} + +static int lbc_probe(device_t dev) { device_t parent; @@ -150,7 +322,7 @@ lbc_attach(device_t dev) { struct lbc_softc *sc; struct rman *rm; - u_long start, size; + const struct lbc_resource *lbcres; int error; sc = device_get_softc(dev); @@ -165,15 +337,11 @@ lbc_attach(device_t dev) sc->sc_bst = rman_get_bustag(sc->sc_res); sc->sc_bsh = rman_get_bushandle(sc->sc_res); - error = bus_get_resource(dev, SYS_RES_MEMORY, 1, &start, &size); - if (error) - goto fail; - rm = &sc->sc_rman; rm->rm_type = RMAN_ARRAY; rm->rm_descr = "MPC85XX Local Bus Space"; - rm->rm_start = start; - rm->rm_end = start + size - 1; + rm->rm_start = 0UL; + rm->rm_end = ~0UL; error = rman_init(rm); if (error) goto fail; @@ -184,13 +352,35 @@ lbc_attach(device_t dev) goto fail; } - sc->sc_kva = (uintptr_t)pmap_mapdev(start, size); - - lbc_mk_child(dev, LBC_DEVTYPE_CFI, 0, 0); + /* + * Initialize configuration register: + * - enable Local Bus + * - set data buffer control signal function + * - disable parity byte select + * - set ECC parity type + * - set bus monitor timing and timer prescale + */ + lbc_write_reg(sc, LBC85XX_LBCR, 0x00000000); + + /* + * Initialize clock ratio register: + * - disable PLL bypass mode + * - configure LCLK delay cycles for the assertion of LALE + * - set system clock divider + */ + lbc_write_reg(sc, LBC85XX_LCRR, 0x00030008); + + lbcres = mpc85xx_lbc_resources; + + for (; lbcres->lbr_devtype; lbcres++) + if (!lbc_mk_child(dev, lbcres)) { + error = ENXIO; + goto fail; + } return (bus_generic_attach(dev)); - fail: +fail: bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rid, sc->sc_res); return (error); } @@ -208,11 +398,13 @@ lbc_alloc_resource(device_t dev, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { struct lbc_softc *sc; + struct lbc_devinfo *dinfo; struct resource *rv; struct rman *rm; int error; sc = device_get_softc(dev); + dinfo = device_get_ivars(child); if (type != SYS_RES_MEMORY && type != SYS_RES_IRQ) return (NULL); @@ -225,6 +417,12 @@ lbc_alloc_resource(device_t dev, device_t child, int type, int *rid, return (bus_alloc_resource(dev, type, rid, start, end, count, flags)); + if (!sc->sc_kva[dinfo->lbc_unit]) { + error = lbc_init_child(dev, child); + if (error) + return (NULL); + } + error = lbc_get_resource(dev, child, type, *rid, &start, &count); if (error) return (NULL); @@ -234,8 +432,7 @@ lbc_alloc_resource(device_t dev, device_t child, int type, int *rid, rv = rman_reserve_resource(rm, start, end, count, flags, child); if (rv != NULL) { rman_set_bustag(rv, &bs_be_tag); - rman_set_bushandle(rv, sc->sc_kva + rman_get_start(rv) - - rm->rm_start); + rman_set_bushandle(rv, rman_get_start(rv)); } return (rv); } @@ -279,12 +476,6 @@ lbc_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) case LBC_IVAR_DEVTYPE: *result = dinfo->lbc_devtype; return (0); - case LBC_IVAR_CLOCK: - *result = 1843200; - return (0); - case LBC_IVAR_REGSHIFT: - *result = 0; - return (0); default: break; } @@ -305,24 +496,35 @@ lbc_get_resource(device_t dev, device_t child, int type, int rid, { struct lbc_softc *sc; struct lbc_devinfo *dinfo; + const struct lbc_resource *lbcres; if (type != SYS_RES_MEMORY) return (ENOENT); - /* Currently all devices have a single RID per type. */ + /* Currently all LBC devices have a single RID per type. */ if (rid != 0) return (ENOENT); sc = device_get_softc(dev); dinfo = device_get_ivars(child); + if ((dinfo->lbc_unit < 0) || (dinfo->lbc_unit > (LBC_DEV_MAX - 1))) + return (EINVAL); + + lbcres = mpc85xx_lbc_resources; + switch (dinfo->lbc_devtype) { case LBC_DEVTYPE_CFI: - *startp = sc->sc_rman.rm_start; - *countp = sc->sc_rman.rm_end - sc->sc_rman.rm_start + 1; - break; + case LBC_DEVTYPE_RTC: + for (; lbcres->lbr_devtype; lbcres++) { + if (dinfo->lbc_unit == lbcres->lbr_unit) { + *startp = sc->sc_kva[lbcres->lbr_unit]; + *countp = lbcres->lbr_size; + return (0); + } + } default: - return(EDOOFUS); + return (EDOOFUS); } - return(0); + return (0); } diff --git a/sys/powerpc/mpc85xx/lbc.h b/sys/powerpc/mpc85xx/lbc.h index 8bc7843..24e741a 100644 --- a/sys/powerpc/mpc85xx/lbc.h +++ b/sys/powerpc/mpc85xx/lbc.h @@ -30,11 +30,49 @@ #define _MACHINE_LBC_H_ #define LBC_IVAR_DEVTYPE 1 -#define LBC_IVAR_CLOCK 2 -#define LBC_IVAR_REGSHIFT 3 + +/* Maximum number of devices on Local Bus */ +#define LBC_DEV_MAX 8 /* Device types. */ #define LBC_DEVTYPE_CFI 1 -#define LBC_DEVTYPE_UART 2 +#define LBC_DEVTYPE_RTC 2 + +/* Local access registers */ +#define LBC85XX_BR(n) (OCP85XX_LBC_OFF + (8 * n)) +#define LBC85XX_OR(n) (OCP85XX_LBC_OFF + 4 + (8 * n)) +#define LBC85XX_LBCR (OCP85XX_LBC_OFF + 0xd0) +#define LBC85XX_LCRR (OCP85XX_LBC_OFF + 0xd4) + +/* LBC machine select */ +#define LBCRES_MSEL_GPCM 0 +#define LBCRES_MSEL_FCM 1 +#define LBCRES_MSEL_UPMA 8 +#define LBCRES_MSEL_UPMB 9 +#define LBCRES_MSEL_UPMC 10 + +/* LBC data error checking modes */ +#define LBCRES_DECC_DISABLED 0 +#define LBCRES_DECC_NORMAL 1 +#define LBCRES_DECC_RMW 2 + +/* LBC atomic operation modes */ +#define LBCRES_ATOM_DISABLED 0 +#define LBCRES_ATOM_RAWA 1 +#define LBCRES_ATOM_WARA 2 + +struct lbc_resource { + int lbr_devtype; /* LBC device type */ + int lbr_unit; /* Resource table entry number */ + vm_paddr_t lbr_base_addr; /* Device mem region base address */ + size_t lbr_size; /* Device mem region size */ + int lbr_port_size; /* Data bus width */ + uint8_t lbr_msel; /* LBC machine select */ + uint8_t lbr_decc; /* Data error checking mode */ + uint8_t lbr_atom; /* Atomic operation mode */ + uint8_t lbr_wp; /* Write protect */ +}; + +extern const struct lbc_resource mpc85xx_lbc_resources[]; #endif /* _MACHINE_LBC_H_ */ diff --git a/sys/powerpc/mpc85xx/mpc85xx.c b/sys/powerpc/mpc85xx/mpc85xx.c index 62a47a6..de9c771 100644 --- a/sys/powerpc/mpc85xx/mpc85xx.c +++ b/sys/powerpc/mpc85xx/mpc85xx.c @@ -10,9 +10,6 @@ * 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. - * 3. Neither the name of the author nor the names of contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -38,33 +35,117 @@ __FBSDID("$FreeBSD$"); #include <machine/cpu.h> #include <machine/cpufunc.h> -#include <machine/pio.h> #include <machine/spr.h> #include <powerpc/mpc85xx/ocpbus.h> +#include <powerpc/mpc85xx/mpc85xx.h> /* * MPC85xx system specific routines */ +uint32_t +ccsr_read4(uintptr_t addr) +{ + volatile uint32_t *ptr = (void *)addr; + + return (*ptr); +} + +void +ccsr_write4(uintptr_t addr, uint32_t val) +{ + volatile uint32_t *ptr = (void *)addr; + + *ptr = val; + __asm __volatile("eieio; sync"); +} + +static __inline int +law_getmax(void) +{ + uint32_t ver; + + ver = SVR_VER(mfspr(SPR_SVR)); + if (ver == SVR_MPC8572E || ver == SVR_MPC8572) + return (12); + else + return (8); +} + +#define _LAW_SR(trgt,size) (0x80000000 | (trgt << 20) | (ffsl(size) - 2)) +#define _LAW_BAR(addr) (addr >> 12) + +int +law_enable(int trgt, u_long addr, u_long size) +{ + uint32_t bar, sr; + int i, law_max; + + law_max = law_getmax(); + bar = _LAW_BAR(addr); + sr = _LAW_SR(trgt, size); + + /* Bail if already programmed. */ + for (i = 0; i < law_max; i++) + if (sr == ccsr_read4(OCP85XX_LAWSR(i)) && + bar == ccsr_read4(OCP85XX_LAWBAR(i))) + return (0); + + /* Find an unused access window. */ + for (i = 0; i < law_max; i++) + if ((ccsr_read4(OCP85XX_LAWSR(i)) & 0x80000000) == 0) + break; + + if (i == law_max) + return (ENOSPC); + + ccsr_write4(OCP85XX_LAWBAR(i), bar); + ccsr_write4(OCP85XX_LAWSR(i), sr); + return (0); +} + +int +law_disable(int trgt, u_long addr, u_long size) +{ + uint32_t bar, sr; + int i, law_max; + + law_max = law_getmax(); + bar = _LAW_BAR(addr); + sr = _LAW_SR(trgt, size); + + /* Find and disable requested LAW. */ + for (i = 0; i < law_max; i++) + if (sr == ccsr_read4(OCP85XX_LAWSR(i)) && + bar == ccsr_read4(OCP85XX_LAWBAR(i))) { + ccsr_write4(OCP85XX_LAWBAR(i), 0); + ccsr_write4(OCP85XX_LAWSR(i), 0); + return (0); + } + + return (ENOENT); +} + void -cpu_reset() +cpu_reset(void) { - uint32_t svr = mfspr(SPR_SVR); + uint32_t ver = SVR_VER(mfspr(SPR_SVR)); - if (svr == SVR_MPC8572E || svr == SVR_MPC8572) + if (ver == SVR_MPC8572E || ver == SVR_MPC8572) /* Systems with dedicated reset register */ - out32(OCP85XX_RSTCR, 2); + ccsr_write4(OCP85XX_RSTCR, 2); else { /* Clear DBCR0, disables debug interrupts and events. */ mtspr(SPR_DBCR0, 0); - __asm volatile("isync"); + __asm __volatile("isync"); /* Enable Debug Interrupts in MSR. */ mtmsr(mfmsr() | PSL_DE); /* Enable debug interrupts and issue reset. */ - mtspr(SPR_DBCR0, mfspr(SPR_DBCR0) | DBCR0_IDM | DBCR0_RST_SYSTEM); + mtspr(SPR_DBCR0, mfspr(SPR_DBCR0) | DBCR0_IDM | + DBCR0_RST_SYSTEM); } printf("Reset failed...\n"); diff --git a/sys/powerpc/mpc85xx/mpc85xx.h b/sys/powerpc/mpc85xx/mpc85xx.h new file mode 100644 index 0000000..4d31b58 --- /dev/null +++ b/sys/powerpc/mpc85xx/mpc85xx.h @@ -0,0 +1,37 @@ +/*- + * Copyright (C) 2008 Semihalf, Rafal Jaworowski + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _MPC85XX_H_ +#define _MPC85XX_H_ + +uint32_t ccsr_read4(uintptr_t addr); +void ccsr_write4(uintptr_t addr, uint32_t val); +int law_enable(int trgt, u_long addr, u_long size); +int law_disable(int trgt, u_long addr, u_long size); + +#endif /* _MPC85XX_H_ */ diff --git a/sys/powerpc/mpc85xx/nexus.c b/sys/powerpc/mpc85xx/nexus.c index 01e0425..fa07247 100644 --- a/sys/powerpc/mpc85xx/nexus.c +++ b/sys/powerpc/mpc85xx/nexus.c @@ -70,13 +70,9 @@ __FBSDID("$FreeBSD$"); */ static int nexus_probe(device_t); static int nexus_activate_resource(device_t, device_t, int, int, - struct resource *); + struct resource *); static int nexus_deactivate_resource(device_t, device_t, int, int, - struct resource *); - -/* - * Local routines - */ + struct resource *); static device_method_t nexus_methods[] = { /* Device interface */ diff --git a/sys/powerpc/mpc85xx/ocpbus.c b/sys/powerpc/mpc85xx/ocpbus.c index a741849..ae56fb0 100644 --- a/sys/powerpc/mpc85xx/ocpbus.c +++ b/sys/powerpc/mpc85xx/ocpbus.c @@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$"); #include <machine/bootinfo.h> #include <powerpc/mpc85xx/ocpbus.h> +#include <powerpc/mpc85xx/mpc85xx.h> #include "pic_if.h" @@ -115,23 +116,6 @@ DRIVER_MODULE(ocpbus, nexus, ocpbus_driver, ocpbus_devclass, 0, 0); static int law_max = 0; -static __inline uint32_t -ccsr_read4(uintptr_t addr) -{ - volatile uint32_t *ptr = (void *)addr; - - return (*ptr); -} - -static __inline void -ccsr_write4(uintptr_t addr, uint32_t val) -{ - volatile uint32_t *ptr = (void *)addr; - - *ptr = val; - __asm __volatile("eieio; sync"); -} - static device_t ocpbus_mk_child(device_t dev, int type, int unit) { @@ -154,8 +138,6 @@ static int ocpbus_write_law(int trgt, int type, u_long *startp, u_long *countp) { u_long addr, size; - int i; - uint32_t bar, sr; switch (type) { case SYS_RES_MEMORY: @@ -172,10 +154,6 @@ ocpbus_write_law(int trgt, int type, u_long *startp, u_long *countp) addr = 0xA0000000; size = 0x10000000; break; - case OCP85XX_TGTIF_LBC: - addr = 0xff800000; - size = 0x00800000; - break; default: return (EINVAL); } @@ -205,40 +183,19 @@ ocpbus_write_law(int trgt, int type, u_long *startp, u_long *countp) *startp = addr; *countp = size; - /* Program the LAWs for this memory range. */ - bar = addr >> 12; - sr = 0x80000000 | (trgt << 20) | (ffsl(size) - 2); - - /* Check if already programmed. */ - for (i = 0; i < law_max; i++) { - if (sr == ccsr_read4(OCP85XX_LAWSR(i)) && - bar == ccsr_read4(OCP85XX_LAWBAR(i))) - return (0); - } - - /* Find an unused access window .*/ - for (i = 0; i < law_max; i++) { - if ((ccsr_read4(OCP85XX_LAWSR(i)) & 0x80000000) == 0) - break; - } - if (i == law_max) - return (ENOSPC); - - ccsr_write4(OCP85XX_LAWBAR(i), bar); - ccsr_write4(OCP85XX_LAWSR(i), sr); - return (0); + return (law_enable(trgt, *startp, *countp)); } static int -ocpbus_probe (device_t dev) +ocpbus_probe(device_t dev) { struct ocpbus_softc *sc; - uint32_t svr; + uint32_t ver; sc = device_get_softc(dev); - svr = mfspr(SPR_SVR); - if (svr == SVR_MPC8572E || svr == SVR_MPC8572) + ver = SVR_VER(mfspr(SPR_SVR)); + if (ver == SVR_MPC8572E || ver == SVR_MPC8572) law_max = 12; else law_max = 8; @@ -248,7 +205,7 @@ ocpbus_probe (device_t dev) } static int -ocpbus_attach (device_t dev) +ocpbus_attach(device_t dev) { struct ocpbus_softc *sc; int error, i, tgt; @@ -393,7 +350,6 @@ const struct ocp_resource mpc8555_resources[] = { {OCPBUS_DEVTYPE_LBC, 0, SYS_RES_MEMORY, 0, OCP85XX_LBC_OFF, OCP85XX_LBC_SIZE}, - {OCPBUS_DEVTYPE_LBC, 0, SYS_RES_MEMORY, 1, 0, OCP85XX_TGTIF_LBC}, {OCPBUS_DEVTYPE_I2C, 0, SYS_RES_MEMORY, 0, OCP85XX_I2C0_OFF, OCP85XX_I2C_SIZE}, diff --git a/sys/powerpc/ofw/ofw_pcib_pci.c b/sys/powerpc/ofw/ofw_pcib_pci.c index 5d6fba6..0b6e0ca 100644 --- a/sys/powerpc/ofw/ofw_pcib_pci.c +++ b/sys/powerpc/ofw/ofw_pcib_pci.c @@ -36,6 +36,7 @@ #include <dev/ofw/openfirm.h> #include <dev/ofw/ofw_pci.h> #include <dev/ofw/ofw_bus.h> +#include <dev/ofw/ofw_bus_subr.h> #include <dev/pci/pcivar.h> #include <dev/pci/pcireg.h> @@ -46,6 +47,8 @@ static int ofw_pcib_pci_probe(device_t bus); static int ofw_pcib_pci_attach(device_t bus); static phandle_t ofw_pcib_pci_get_node(device_t bus, device_t dev); +static int ofw_pcib_pci_route_interrupt(device_t bridge, device_t dev, + int intpin); static device_method_t ofw_pcib_pci_methods[] = { /* Device interface */ @@ -70,7 +73,7 @@ static device_method_t ofw_pcib_pci_methods[] = { DEVMETHOD(pcib_maxslots, pcib_maxslots), DEVMETHOD(pcib_read_config, pcib_read_config), DEVMETHOD(pcib_write_config, pcib_write_config), - DEVMETHOD(pcib_route_interrupt, pcib_route_interrupt), + DEVMETHOD(pcib_route_interrupt, ofw_pcib_pci_route_interrupt), /* ofw_bus interface */ DEVMETHOD(ofw_bus_get_node, ofw_pcib_pci_get_node), @@ -80,8 +83,20 @@ static device_method_t ofw_pcib_pci_methods[] = { static devclass_t pcib_devclass; +struct ofw_pcib_softc { + /* + * This is here so that we can use pci bridge methods, too - the + * generic routines only need the dev, secbus and subbus members + * filled. + */ + struct pcib_softc ops_pcib_sc; + phandle_t ops_node; + struct ofw_bus_iinfo ops_iinfo; +}; + + DEFINE_CLASS_0(pcib, ofw_pcib_pci_driver, ofw_pcib_pci_methods, - sizeof(struct pcib_softc)); + sizeof(struct ofw_pcib_softc)); DRIVER_MODULE(ofw_pcib, pci, ofw_pcib_pci_driver, pcib_devclass, 0, 0); static int @@ -103,6 +118,15 @@ ofw_pcib_pci_probe(device_t dev) static int ofw_pcib_pci_attach(device_t dev) { + struct ofw_pcib_softc *sc; + + sc = device_get_softc(dev); + sc->ops_pcib_sc.dev = dev; + sc->ops_node = ofw_bus_get_node(dev); + + ofw_bus_setup_iinfo(sc->ops_node, &sc->ops_iinfo, + sizeof(cell_t)); + pcib_attach_common(dev); device_add_child(dev, "pci", -1); @@ -110,7 +134,7 @@ ofw_pcib_pci_attach(device_t dev) return (bus_generic_attach(dev)); } -phandle_t +static phandle_t ofw_pcib_pci_get_node(device_t bridge, device_t dev) { /* We have only one child, the PCI bus, so pass it our node */ @@ -118,3 +142,37 @@ ofw_pcib_pci_get_node(device_t bridge, device_t dev) return (ofw_bus_get_node(bridge)); } +static int +ofw_pcib_pci_route_interrupt(device_t bridge, device_t dev, int intpin) +{ + struct ofw_pcib_softc *sc; + struct ofw_bus_iinfo *ii; + struct ofw_pci_register reg; + cell_t pintr, mintr; + uint8_t maskbuf[sizeof(reg) + sizeof(pintr)]; + + sc = device_get_softc(bridge); + ii = &sc->ops_iinfo; + if (ii->opi_imapsz > 0) { + pintr = intpin; + if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), ii, ®, + sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr), + maskbuf)) { + /* + * If we've found a mapping, return it and don't map + * it again on higher levels - that causes problems + * in some cases, and never seems to be required. + */ + return (mintr); + } + } else if (intpin >= 1 && intpin <= 4) { + /* + * When an interrupt map is missing, we need to do the + * standard PCI swizzle and continue mapping at the parent. + */ + return (pcib_route_interrupt(bridge, dev, intpin)); + } + return (PCIB_ROUTE_INTERRUPT(device_get_parent(device_get_parent( + bridge)), bridge, intpin)); +} + diff --git a/sys/powerpc/ofw/ofw_pcibus.c b/sys/powerpc/ofw/ofw_pcibus.c index 916d98b..6ec2da6 100644 --- a/sys/powerpc/ofw/ofw_pcibus.c +++ b/sys/powerpc/ofw/ofw_pcibus.c @@ -1,6 +1,4 @@ /*- - * Copyright (c) 1994 Charles M. Hannum. All rights reserved. - * Copyright (c) 1996 Christopher G. Demetriou. All rights reserved. * Copyright (c) 1997, Stefan Esser <se@freebsd.org> * Copyright (c) 2000, Michael Smith <msmith@freebsd.org> * Copyright (c) 2000, BSDi @@ -54,22 +52,27 @@ __FBSDID("$FreeBSD$"); #include "pcib_if.h" #include "pci_if.h" -/* Helper functions */ -static int find_node_intr(phandle_t, u_int32_t *, u_int32_t *); -static int ofw_pci_find_intline(phandle_t node, uint32_t *irqs); -static void ofw_pci_fixup_node(device_t dev, phandle_t node); +typedef uint32_t ofw_pci_intr_t; /* Methods */ static device_probe_t ofw_pcibus_probe; static device_attach_t ofw_pcibus_attach; static pci_assign_interrupt_t ofw_pcibus_assign_interrupt; static ofw_bus_get_devinfo_t ofw_pcibus_get_devinfo; +static int ofw_pcibus_child_pnpinfo_str_method(device_t cbdev, device_t child, + char *buf, size_t buflen); + +static void ofw_pcibus_enum_devtree(device_t dev, u_int domain, u_int busno); +static void ofw_pcibus_enum_bus(device_t dev, u_int domain, u_int busno); static device_method_t ofw_pcibus_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ofw_pcibus_probe), DEVMETHOD(device_attach, ofw_pcibus_attach), + /* Bus interface */ + DEVMETHOD(bus_child_pnpinfo_str, ofw_pcibus_child_pnpinfo_str_method), + /* PCI interface */ DEVMETHOD(pci_assign_interrupt, ofw_pcibus_assign_interrupt), @@ -100,6 +103,7 @@ MODULE_DEPEND(ofw_pcibus, pci, 1, 1, 1); static int ofw_pcibus_probe(device_t dev) { + if (ofw_bus_get_node(dev) == 0) return (ENXIO); device_set_desc(dev, "OFW PCI bus"); @@ -110,18 +114,43 @@ ofw_pcibus_probe(device_t dev) static int ofw_pcibus_attach(device_t dev) { - device_t pcib; - struct ofw_pci_register pcir; - struct ofw_pcibus_devinfo *dinfo; - phandle_t node, child; - u_int busno, domain, func, slot; + u_int busno, domain; - pcib = device_get_parent(dev); domain = pcib_get_domain(dev); busno = pcib_get_bus(dev); if (bootverbose) device_printf(dev, "domain=%d, physical bus=%d\n", domain, busno); + + /* + * Attach those children represented in the device tree. + */ + + ofw_pcibus_enum_devtree(dev, domain, busno); + + /* + * We now attach any laggard devices. FDT, for instance, allows + * the device tree to enumerate only some PCI devices. Apple's + * OF device tree on some Grackle-based hardware can also miss + * functions on multi-function cards. + */ + + ofw_pcibus_enum_bus(dev, domain, busno); + + return (bus_generic_attach(dev)); +} + +static void +ofw_pcibus_enum_devtree(device_t dev, u_int domain, u_int busno) +{ + device_t pcib; + struct ofw_pci_register pcir; + struct ofw_pcibus_devinfo *dinfo; + phandle_t node, child; + u_int func, slot; + int intline; + + pcib = device_get_parent(dev); node = ofw_bus_get_node(dev); for (child = OF_child(node); child != 0; child = OF_peer(child)) { @@ -134,226 +163,178 @@ ofw_pcibus_attach(device_t dev) if (pci_find_dbsf(domain, busno, slot, func) != NULL) continue; - ofw_pci_fixup_node(pcib, child); + /* + * The preset in the intline register is usually bogus. Reset + * it such that the PCI code will reroute the interrupt if + * needed. + */ + + intline = PCI_INVALID_IRQ; + if (OF_getproplen(child, "interrupts") > 0) + intline = 0; + PCIB_WRITE_CONFIG(pcib, busno, slot, func, PCIR_INTLINE, + intline, 1); + + /* + * Now set up the PCI and OFW bus layer devinfo and add it + * to the PCI bus. + */ dinfo = (struct ofw_pcibus_devinfo *)pci_read_device(pcib, domain, busno, slot, func, sizeof(*dinfo)); - if (dinfo == NULL) continue; - - /* Set up OFW devinfo */ if (ofw_bus_gen_setup_devinfo(&dinfo->opd_obdinfo, child) != 0) { pci_freecfg((struct pci_devinfo *)dinfo); continue; } - pci_add_child(dev, (struct pci_devinfo *)dinfo); /* - * Some devices don't have an intpin set, but do have - * interrupts. Add them to the appropriate resource list. - */ - if (dinfo->opd_dinfo.cfg.intpin == 0) { - uint32_t irqs[4]; - - if (ofw_pci_find_intline(child, irqs) > 0) - resource_list_add(&dinfo->opd_dinfo.resources, - SYS_RES_IRQ, 0, irqs[0], irqs[0], 1); - } + * Some devices don't have an intpin set, but do have + * interrupts. These are fully specified, and set in the + * interrupts property, so add that value to the device's + * resource list. + */ + if (dinfo->opd_dinfo.cfg.intpin == 0) { + ofw_pci_intr_t intr; + + if (OF_getprop(child, "interrupts", &intr, + sizeof(intr)) > 0) { + resource_list_add(&dinfo->opd_dinfo.resources, + SYS_RES_IRQ, 0, intr, intr, 1); + } + } } - - return (bus_generic_attach(dev)); } -static int -ofw_pcibus_assign_interrupt(device_t dev, device_t child) -{ - uint32_t irqs[4]; - - device_printf(child,"Assigning interrupt\n"); - - if (ofw_pci_find_intline(ofw_bus_get_node(child), irqs) < 0) - return PCI_INVALID_IRQ; - - device_printf(child,"IRQ %d\n",irqs[0]); - - return irqs[0]; - -// return (PCIB_ROUTE_INTERRUPT(device_get_parent(dev), child, intr)); -} - -static const struct ofw_bus_devinfo * -ofw_pcibus_get_devinfo(device_t bus, device_t dev) -{ - struct ofw_pcibus_devinfo *dinfo; - - dinfo = device_get_ivars(dev); - return (&dinfo->opd_obdinfo); -} +/* + * The following is an almost exact clone of pci_add_children(), with the + * addition that it (a) will not add children that have already been added, + * and (b) will set up the OFW devinfo to point to invalid values. This is + * to handle non-enumerated PCI children as exist in FDT and on the second + * function of the Rage 128 in my Blue & White G3. + */ static void -ofw_pci_fixup_node(device_t dev, phandle_t node) +ofw_pcibus_enum_bus(device_t dev, u_int domain, u_int busno) { - uint32_t csr, intr, irqs[4]; - struct ofw_pci_register addr[8]; - int len, i; + device_t pcib; + struct ofw_pcibus_devinfo *dinfo; + int maxslots; + int s, f, pcifunchigh; + uint8_t hdrtype; - len = OF_getprop(node, "assigned-addresses", addr, sizeof(addr)); - if (len < (int)sizeof(struct ofw_pci_register)) { - return; - } + pcib = device_get_parent(dev); - csr = PCIB_READ_CONFIG(dev, OFW_PCI_PHYS_HI_BUS(addr[0].phys_hi), - OFW_PCI_PHYS_HI_DEVICE(addr[0].phys_hi), - OFW_PCI_PHYS_HI_FUNCTION(addr[0].phys_hi), PCIR_COMMAND, 4); - csr &= ~(PCIM_CMD_PORTEN | PCIM_CMD_MEMEN); - - for (i = 0; i < len / sizeof(struct ofw_pci_register); i++) { - switch (addr[i].phys_hi & OFW_PCI_PHYS_HI_SPACEMASK) { - case OFW_PCI_PHYS_HI_SPACE_IO: - csr |= PCIM_CMD_PORTEN; - break; - case OFW_PCI_PHYS_HI_SPACE_MEM32: - csr |= PCIM_CMD_MEMEN; - break; + maxslots = PCIB_MAXSLOTS(pcib); + for (s = 0; s <= maxslots; s++) { + pcifunchigh = 0; + f = 0; + DELAY(1); + hdrtype = PCIB_READ_CONFIG(pcib, busno, s, f, PCIR_HDRTYPE, 1); + if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE) + continue; + if (hdrtype & PCIM_MFDEV) + pcifunchigh = PCI_FUNCMAX; + for (f = 0; f <= pcifunchigh; f++) { + /* Filter devices we have already added */ + if (pci_find_dbsf(domain, busno, s, f) != NULL) + continue; + + dinfo = (struct ofw_pcibus_devinfo *)pci_read_device( + pcib, domain, busno, s, f, sizeof(*dinfo)); + if (dinfo != NULL) { + dinfo->opd_obdinfo.obd_node = -1; + + dinfo->opd_obdinfo.obd_name = NULL; + dinfo->opd_obdinfo.obd_compat = NULL; + dinfo->opd_obdinfo.obd_type = NULL; + dinfo->opd_obdinfo.obd_model = NULL; + pci_add_child(dev, (struct pci_devinfo *)dinfo); + } } } - - PCIB_WRITE_CONFIG(dev, OFW_PCI_PHYS_HI_BUS(addr[0].phys_hi), - OFW_PCI_PHYS_HI_DEVICE(addr[0].phys_hi), - OFW_PCI_PHYS_HI_FUNCTION(addr[0].phys_hi), PCIR_COMMAND, csr, 4); - - if (ofw_pci_find_intline(node, irqs) != -1) { - intr = PCIB_READ_CONFIG(dev, - OFW_PCI_PHYS_HI_BUS(addr[0].phys_hi), - OFW_PCI_PHYS_HI_DEVICE(addr[0].phys_hi), - OFW_PCI_PHYS_HI_FUNCTION(addr[0].phys_hi), PCIR_INTLINE, 2); - intr &= ~(0xff); - intr |= irqs[0] & 0xff; - PCIB_WRITE_CONFIG(dev, - OFW_PCI_PHYS_HI_BUS(addr[0].phys_hi), - OFW_PCI_PHYS_HI_DEVICE(addr[0].phys_hi), - OFW_PCI_PHYS_HI_FUNCTION(addr[0].phys_hi), PCIR_INTLINE, - intr, 2); - } } static int -ofw_pci_find_intline(phandle_t node, uint32_t *irqs) +ofw_pcibus_child_pnpinfo_str_method(device_t cbdev, device_t child, char *buf, + size_t buflen) { - uint32_t npintr, paddr[4]; - struct ofw_pci_register addr[8]; - int len; + pci_child_pnpinfo_str_method(cbdev, child, buf, buflen); - len = OF_getprop(node, "assigned-addresses", addr, sizeof(addr)); - if (len < (int)sizeof(struct ofw_pci_register)) - return -1; - /* - * Create PCI interrupt-map array element. pci-mid/pci-lo - * aren't required, but the 'interrupts' property needs - * to be appended - */ - npintr = 0; - OF_getprop(node, "interrupts", &npintr, 4); - paddr[0] = addr[0].phys_hi; - paddr[1] = 0; - paddr[2] = 0; - paddr[3] = npintr; - - return find_node_intr(node, paddr, irqs); -} + if (ofw_bus_get_node(child) != -1) { + strlcat(buf, " ", buflen); /* Separate info */ + ofw_bus_gen_child_pnpinfo_str(cbdev, child, buf, buflen); + } + return (0); +} + static int -find_node_intr(phandle_t node, u_int32_t *addr, u_int32_t *intr) +ofw_pcibus_assign_interrupt(device_t dev, device_t child) { - phandle_t parent, iparent; - int len, mlen, match, i; - u_int32_t map[160], *mp, imask[8], maskedaddr[8], icells; - char name[32]; - - len = OF_getprop(node, "AAPL,interrupts", intr, 4); - if (len == 4) { - return (len); - } - - parent = OF_parent(node); - len = OF_getprop(parent, "interrupt-map", map, sizeof(map)); - mlen = OF_getprop(parent, "interrupt-map-mask", imask, sizeof(imask)); + ofw_pci_intr_t intr; + phandle_t node; + int isz; - if (len == -1 || mlen == -1) - goto nomap; - - memcpy(maskedaddr, addr, mlen); - for (i = 0; i < mlen/4; i++) - maskedaddr[i] &= imask[i]; - - mp = map; - while (len > mlen) { - match = bcmp(maskedaddr, mp, mlen); - mp += mlen / 4; - len -= mlen; + node = ofw_bus_get_node(child); + if (node == -1) { + /* Non-firmware enumerated child, use standard routing */ + /* - * We must read "#interrupt-cells" for each time because - * interrupt-parent may be different. + * XXX: Right now we don't have anything sensible to do here, + * since the ofw_imap stuff relies on nodes have a reg + * property. There exists ways around this, so the ePAPR + * spec will need to be studied. */ - iparent = *mp++; - len -= 4; - if (OF_getprop(iparent, "#interrupt-cells", &icells, 4) != 4) - goto nomap; - - /* Found. */ - if (match == 0) { - bcopy(mp, intr, icells * 4); - return (icells * 4); - } - mp += icells; - len -= icells * 4; - } + return (0); -nomap: +#ifdef NOTYET + intr = pci_get_intpin(child); + return (PCIB_ROUTE_INTERRUPT(device_get_parent(dev), child, + intr)); +#endif + } + /* - * Check for local properties indicating interrupts + * Any AAPL,interrupts property gets priority and is + * fully specified (i.e. does not need routing) */ - len = OF_getprop(node, "interrupts", intr, 16); - if (OF_getprop(node, "interrupt-parent", &iparent, sizeof(iparent)) == - sizeof(iparent)) { - OF_getprop(iparent, "#interrupt-cells", &icells, sizeof(icells)); - for (i = 0; i < len/icells/4; i++) - intr[i] = intr[i*icells]; + isz = OF_getprop(node, "AAPL,interrupts", &intr, sizeof(intr)); + if (isz == sizeof(intr)) { + return (intr); + } - return (len); + isz = OF_getprop(node, "interrupts", &intr, sizeof(intr)); + if (isz != sizeof(intr)) { + /* No property; our best guess is the intpin. */ + intr = pci_get_intpin(child); } - /* - * If the node has no interrupt property and the parent is a PCI - * bridge, use the parent's interrupt. This occurs on a PCI slot. + * If we got intr from a property, it may or may not be an intpin. + * For on-board devices, it frequently is not, and is completely out + * of the valid intpin range. For PCI slots, it hopefully is, + * otherwise we will have trouble interfacing with non-OFW buses + * such as cardbus. + * Since we cannot tell which it is without violating layering, we + * will always use the route_interrupt method, and treat exceptions + * on the level they become apparent. */ - bzero(name, sizeof(name)); - OF_getprop(parent, "name", name, sizeof(name)); - if (strcmp(name, "pci-bridge") == 0) { - len = OF_getprop(parent, "AAPL,interrupts", intr, 4); - if (len == 4) { - return (len); - } + return (PCIB_ROUTE_INTERRUPT(device_get_parent(dev), child, intr)); +} - /* - * XXX I don't know what is the correct local address. - * XXX Use the first entry for now. - */ - len = OF_getprop(parent, "interrupt-map", map, sizeof(map)); - if (len >= 36) { - addr = &map[5]; - /* XXX Use 0 for 'interrupts' for compat */ - return (find_node_intr(parent, addr, intr)); - } - } +static const struct ofw_bus_devinfo * +ofw_pcibus_get_devinfo(device_t bus, device_t dev) +{ + struct ofw_pcibus_devinfo *dinfo; - return (-1); + dinfo = device_get_ivars(dev); + return (&dinfo->opd_obdinfo); } diff --git a/sys/powerpc/ofw/ofw_syscons.c b/sys/powerpc/ofw/ofw_syscons.c index 373ba11..1080dad 100644 --- a/sys/powerpc/ofw/ofw_syscons.c +++ b/sys/powerpc/ofw/ofw_syscons.c @@ -137,10 +137,12 @@ static video_switch_t ofwfbvidsw = { */ static vi_blank_display_t ofwfb_blank_display8; static vi_putc_t ofwfb_putc8; +static vi_putm_t ofwfb_putm8; static vi_set_border_t ofwfb_set_border8; static vi_blank_display_t ofwfb_blank_display32; static vi_putc_t ofwfb_putc32; +static vi_putm_t ofwfb_putm32; static vi_set_border_t ofwfb_set_border32; VIDEO_DRIVER(ofwfb, ofwfbvidsw, ofwfb_configure); @@ -250,10 +252,12 @@ ofwfb_configure(int flags) if (depth == 8) { sc->sc_blank = ofwfb_blank_display8; sc->sc_putc = ofwfb_putc8; + sc->sc_putm = ofwfb_putm8; sc->sc_set_border = ofwfb_set_border8; } else if (depth == 32) { sc->sc_blank = ofwfb_blank_display32; sc->sc_putc = ofwfb_putc32; + sc->sc_putm = ofwfb_putm32; sc->sc_set_border = ofwfb_set_border32; } else return (0); @@ -304,36 +308,14 @@ ofwfb_init(int unit, video_adapter_t *adp, int flags) { struct ofwfb_softc *sc; video_info_t *vi; - char name[64]; - ihandle_t ih; - int i; int cborder; int font_height; - int retval; sc = (struct ofwfb_softc *)adp; vi = &adp->va_info; vid_init_struct(adp, "ofwfb", -1, unit); - if (sc->sc_depth == 8) { - /* - * Install the ISO6429 colormap - older OFW systems - * don't do this by default - */ - memset(name, 0, sizeof(name)); - OF_package_to_path(sc->sc_node, name, sizeof(name)); - ih = OF_open(name); - for (i = 0; i < 16; i++) { - OF_call_method("color!", ih, 4, 1, - ofwfb_cmap[i].red, - ofwfb_cmap[i].green, - ofwfb_cmap[i].blue, - i, - &retval); - } - } - /* The default font size can be overridden by loader */ font_height = 16; TUNABLE_INT_FETCH("hw.syscons.fsize", &font_height); @@ -375,10 +357,13 @@ ofwfb_init(int unit, video_adapter_t *adp, int flags) */ adp->va_window = (vm_offset_t) ofwfb_static_window; - /* Enable future font-loading and flag color support */ - adp->va_flags |= V_ADP_FONT | V_ADP_COLOR; - - ofwfb_blank_display(&sc->sc_va, V_DISPLAY_ON); + /* + * Enable future font-loading and flag color support, as well as + * adding V_ADP_MODECHANGE so that we ofwfb_set_mode() gets called + * when the X server shuts down. This enables us to get the console + * back when X disappears. + */ + adp->va_flags |= V_ADP_FONT | V_ADP_COLOR | V_ADP_MODECHANGE; ofwfb_set_mode(&sc->sc_va, 0); @@ -404,6 +389,37 @@ ofwfb_query_mode(video_adapter_t *adp, video_info_t *info) static int ofwfb_set_mode(video_adapter_t *adp, int mode) { + struct ofwfb_softc *sc; + char name[64]; + ihandle_t ih; + int i, retval; + + sc = (struct ofwfb_softc *)adp; + + /* + * Open the display device, which will initialize it. + */ + + memset(name, 0, sizeof(name)); + OF_package_to_path(sc->sc_node, name, sizeof(name)); + ih = OF_open(name); + + if (sc->sc_depth == 8) { + /* + * Install the ISO6429 colormap - older OFW systems + * don't do this by default + */ + for (i = 0; i < 16; i++) { + OF_call_method("color!", ih, 4, 1, + ofwfb_cmap[i].red, + ofwfb_cmap[i].green, + ofwfb_cmap[i].blue, + i, + &retval); + } + } + + ofwfb_blank_display(&sc->sc_va, V_DISPLAY_ON); return (0); } @@ -823,7 +839,86 @@ ofwfb_putm(video_adapter_t *adp, int x, int y, uint8_t *pixel_image, sc = (struct ofwfb_softc *)adp; - /* put mouse */ + return ((*sc->sc_putm)(adp, x, y, pixel_image, pixel_mask, size, + width)); +} + +static int +ofwfb_putm8(video_adapter_t *adp, int x, int y, uint8_t *pixel_image, + uint32_t pixel_mask, int size, int width) +{ + struct ofwfb_softc *sc; + int i, j, k; + uint32_t *addr; + u_char fg, bg; + union { + uint32_t l[2]; + uint8_t c[8]; + } ch; + + + sc = (struct ofwfb_softc *)adp; + addr = (u_int32_t *)((int)sc->sc_addr + + (y + sc->sc_ymargin)*sc->sc_stride + + x + sc->sc_xmargin); + + fg = ofwfb_foreground(SC_NORM_ATTR); + bg = ofwfb_background(SC_NORM_ATTR); + + for (i = 0; i < size && i+y < sc->sc_height - 2*sc->sc_ymargin; i++) { + /* + * Use the current values for the line + */ + ch.l[0] = addr[0]; + ch.l[1] = addr[1]; + + /* + * Calculate 2 x 4-chars at a time, and then + * write these out. + */ + for (j = 0, k = width; j < 8; j++, k--) { + if (x + j >= sc->sc_width - 2*sc->sc_xmargin) + continue; + + if (pixel_image[i] & (1 << k)) + ch.c[j] = (ch.c[j] == fg) ? bg : fg; + } + + addr[0] = ch.l[0]; + addr[1] = ch.l[1]; + addr += (sc->sc_stride / sizeof(u_int32_t)); + } + + return (0); +} + +static int +ofwfb_putm32(video_adapter_t *adp, int x, int y, uint8_t *pixel_image, + uint32_t pixel_mask, int size, int width) +{ + struct ofwfb_softc *sc; + int i, j, k; + uint32_t fg, bg; + uint32_t *addr; + + sc = (struct ofwfb_softc *)adp; + addr = (uint32_t *)sc->sc_addr + + (y + sc->sc_ymargin)*(sc->sc_stride/4) + + x + sc->sc_xmargin; + + fg = ofwfb_pix32(ofwfb_foreground(SC_NORM_ATTR)); + bg = ofwfb_pix32(ofwfb_background(SC_NORM_ATTR)); + + for (i = 0; i < size && i+y < sc->sc_height - 2*sc->sc_ymargin; i++) { + for (j = 0, k = width; j < 8; j++, k--) { + if (x + j >= sc->sc_width - 2*sc->sc_xmargin) + continue; + + if (pixel_image[i] & (1 << k)) + *(addr + j) = (*(addr + j) == fg) ? bg : fg; + } + addr += (sc->sc_stride/4); + } return (0); } diff --git a/sys/powerpc/ofw/ofw_syscons.h b/sys/powerpc/ofw/ofw_syscons.h index af33c52..01b9727 100644 --- a/sys/powerpc/ofw/ofw_syscons.h +++ b/sys/powerpc/ofw/ofw_syscons.h @@ -51,6 +51,7 @@ struct ofwfb_softc { vi_blank_display_t *sc_blank; vi_putc_t *sc_putc; + vi_putm_t *sc_putm; vi_set_border_t *sc_set_border; #define OFWSC_MAXADDR 8 diff --git a/sys/powerpc/powermac/cuda.c b/sys/powerpc/powermac/cuda.c index 274bb98..e6c010c 100644 --- a/sys/powerpc/powermac/cuda.c +++ b/sys/powerpc/powermac/cuda.c @@ -104,8 +104,6 @@ static devclass_t cuda_devclass; DRIVER_MODULE(cuda, macio, cuda_driver, cuda_devclass, 0, 0); DRIVER_MODULE(adb, cuda, adb_driver, adb_devclass, 0, 0); -MALLOC_DEFINE(M_CUDA, "cuda", "CUDA packet queue"); - static void cuda_intr(void *arg); static uint8_t cuda_read_reg(struct cuda_softc *sc, u_int offset); static void cuda_write_reg(struct cuda_softc *sc, u_int offset, uint8_t value); @@ -178,6 +176,10 @@ cuda_attach(device_t dev) STAILQ_INIT(&sc->sc_inq); STAILQ_INIT(&sc->sc_outq); + STAILQ_INIT(&sc->sc_freeq); + + for (i = 0; i < CUDA_MAXPACKETS; i++) + STAILQ_INSERT_TAIL(&sc->sc_freeq, &sc->sc_pkts[i], pkt_q); /* Init CUDA */ @@ -348,11 +350,17 @@ cuda_send(void *cookie, int poll, int length, uint8_t *msg) mtx_lock(&sc->sc_mutex); - pkt = malloc(sizeof(struct cuda_packet), M_CUDA, M_WAITOK); + pkt = STAILQ_FIRST(&sc->sc_freeq); + if (pkt == NULL) { + mtx_unlock(&sc->sc_mutex); + return (-1); + } + pkt->len = length - 1; pkt->type = msg[0]; memcpy(pkt->data, &msg[1], pkt->len); + STAILQ_REMOVE_HEAD(&sc->sc_freeq, pkt_q); STAILQ_INSERT_TAIL(&sc->sc_outq, pkt, pkt_q); /* @@ -389,8 +397,8 @@ cuda_send_outbound(struct cuda_softc *sc) memcpy(sc->sc_out, &pkt->type, pkt->len + 1); sc->sc_sent = 0; - free(pkt, M_CUDA); STAILQ_REMOVE_HEAD(&sc->sc_outq, pkt_q); + STAILQ_INSERT_TAIL(&sc->sc_freeq, pkt, pkt_q); sc->sc_waiting = 1; @@ -455,9 +463,9 @@ cuda_send_inbound(struct cuda_softc *sc) break; } - free(pkt,M_CUDA); - mtx_lock(&sc->sc_mutex); + + STAILQ_INSERT_TAIL(&sc->sc_freeq, pkt, pkt_q); } mtx_unlock(&sc->sc_mutex); @@ -559,18 +567,22 @@ switch_start: cuda_idle(sc); /* Queue up the packet */ - pkt = malloc(sizeof(struct cuda_packet), M_CUDA, - M_WAITOK); + pkt = STAILQ_FIRST(&sc->sc_freeq); + if (pkt != NULL) { + /* If we have a free packet, process it */ - pkt->len = sc->sc_received - 2; - pkt->type = sc->sc_in[1]; - memcpy(pkt->data, &sc->sc_in[2], pkt->len); + pkt->len = sc->sc_received - 2; + pkt->type = sc->sc_in[1]; + memcpy(pkt->data, &sc->sc_in[2], pkt->len); - STAILQ_INSERT_TAIL(&sc->sc_inq, pkt, pkt_q); + STAILQ_REMOVE_HEAD(&sc->sc_freeq, pkt_q); + STAILQ_INSERT_TAIL(&sc->sc_inq, pkt, pkt_q); + + process_inbound = 1; + } sc->sc_state = CUDA_IDLE; sc->sc_received = 0; - process_inbound = 1; /* * If there is something waiting to be sent out, diff --git a/sys/powerpc/powermac/cudavar.h b/sys/powerpc/powermac/cudavar.h index b6f25fe..02791cb 100644 --- a/sys/powerpc/powermac/cudavar.h +++ b/sys/powerpc/powermac/cudavar.h @@ -35,6 +35,7 @@ #define _POWERPC_CUDAVAR_H_ #define CUDA_DEVSTR "Apple CUDA I/O Controller" +#define CUDA_MAXPACKETS 10 /* Cuda addresses */ #define CUDA_ADB 0 @@ -99,8 +100,10 @@ struct cuda_softc { int sc_out_length; int sc_received; + struct cuda_packet sc_pkts[CUDA_MAXPACKETS]; struct cuda_pktq sc_inq; struct cuda_pktq sc_outq; + struct cuda_pktq sc_freeq; }; #endif /* _POWERPC_CUDAVAR_H_ */ diff --git a/sys/powerpc/powermac/grackle.c b/sys/powerpc/powermac/grackle.c index 08e14ac..9dd796d 100644 --- a/sys/powerpc/powermac/grackle.c +++ b/sys/powerpc/powermac/grackle.c @@ -37,6 +37,7 @@ #include <dev/ofw/openfirm.h> #include <dev/ofw/ofw_pci.h> #include <dev/ofw/ofw_bus.h> +#include <dev/ofw/ofw_bus_subr.h> #include <dev/pci/pcivar.h> #include <dev/pci/pcireg.h> @@ -164,7 +165,7 @@ static int grackle_attach(device_t dev) { struct grackle_softc *sc; - phandle_t node; + phandle_t node, iparent; u_int32_t busrange[2]; struct grackle_range *rp, *io, *mem[2]; int nmem, i, error; @@ -251,6 +252,16 @@ grackle_attach(device_t dev) } } + ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(cell_t)); + + /* We need the number of interrupt cells to read the imap */ + if (OF_getprop(node, "interrupt-parent", &iparent,sizeof(iparent)) <= 0) + iparent = node; + + if (OF_getprop(iparent,"#interrupt-cells",&sc->sc_icells, + sizeof(sc->sc_icells)) <= 0) + sc->sc_icells = 1; + device_add_child(dev, "pci", device_get_unit(dev)); return (bus_generic_attach(dev)); } @@ -335,8 +346,25 @@ grackle_write_config(device_t dev, u_int bus, u_int slot, u_int func, static int grackle_route_interrupt(device_t bus, device_t dev, int pin) { + struct grackle_softc *sc; + struct ofw_pci_register reg; + uint32_t pintr, mintr[2]; + uint8_t maskbuf[sizeof(reg) + sizeof(pintr)]; - return (0); + sc = device_get_softc(bus); + pintr = pin; + if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo, ®, + sizeof(reg), &pintr, sizeof(pintr), &mintr, + sizeof(mintr[0])*sc->sc_icells, maskbuf)) + return (mintr[0]); + + /* Maybe it's a real interrupt, not an intpin */ + if (pin > 4) + return (pin); + + device_printf(bus, "could not route pin %d for device %d.%d\n", + pin, pci_get_slot(dev), pci_get_function(dev)); + return (PCI_INVALID_IRQ); } static int diff --git a/sys/powerpc/powermac/gracklevar.h b/sys/powerpc/powermac/gracklevar.h index bb5b150..78461d8 100644 --- a/sys/powerpc/powermac/gracklevar.h +++ b/sys/powerpc/powermac/gracklevar.h @@ -52,6 +52,9 @@ struct grackle_softc { struct rman sc_mem_rman; bus_space_tag_t sc_memt; bus_dma_tag_t sc_dmat; + int sc_icells; + + struct ofw_bus_iinfo sc_pci_iinfo; }; /* diff --git a/sys/powerpc/powermac/macio.c b/sys/powerpc/powermac/macio.c index 9a4b3ac..71be113 100644 --- a/sys/powerpc/powermac/macio.c +++ b/sys/powerpc/powermac/macio.c @@ -107,6 +107,8 @@ static device_method_t macio_methods[] = { DEVMETHOD(bus_deactivate_resource, macio_deactivate_resource), DEVMETHOD(bus_get_resource_list, macio_get_resource_list), + DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), + /* ofw_bus interface */ DEVMETHOD(ofw_bus_get_devinfo, macio_get_devinfo), DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), diff --git a/sys/powerpc/powermac/uninorth.c b/sys/powerpc/powermac/uninorth.c index 097532c..b0b55a4 100644 --- a/sys/powerpc/powermac/uninorth.c +++ b/sys/powerpc/powermac/uninorth.c @@ -35,6 +35,7 @@ #include <dev/ofw/openfirm.h> #include <dev/ofw/ofw_pci.h> #include <dev/ofw/ofw_bus.h> +#include <dev/ofw/ofw_bus_subr.h> #include <dev/pci/pcivar.h> #include <dev/pci/pcireg.h> @@ -163,8 +164,7 @@ uninorth_attach(device_t dev) { struct uninorth_softc *sc; const char *compatible; - phandle_t node; - phandle_t child; + phandle_t node, child, iparent; u_int32_t reg[2], busrange[2]; struct uninorth_range *rp, *io, *mem[2]; int nmem, i, error; @@ -294,6 +294,14 @@ uninorth_attach(device_t dev) } } + ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(cell_t)); + + /* We need the number of interrupt cells to read the imap */ + sc->sc_icells = 2; + if (OF_getprop(node, "interrupt-parent", &iparent,sizeof(iparent)) > 0) + OF_getprop(iparent,"#interrupt-cells",&sc->sc_icells, + sizeof(sc->sc_icells)); + device_add_child(dev, "pci", device_get_unit(dev)); return (bus_generic_attach(dev)); } @@ -360,8 +368,25 @@ uninorth_write_config(device_t dev, u_int bus, u_int slot, u_int func, static int uninorth_route_interrupt(device_t bus, device_t dev, int pin) { + struct uninorth_softc *sc; + struct ofw_pci_register reg; + uint32_t pintr, mintr[2]; + uint8_t maskbuf[sizeof(reg) + sizeof(pintr)]; - return (0); + sc = device_get_softc(bus); + pintr = pin; + if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo, ®, + sizeof(reg), &pintr, sizeof(pintr), mintr, + sizeof(mintr[0])*sc->sc_icells, maskbuf)) + return (mintr[0]); + + /* Maybe it's a real interrupt, not an intpin */ + if (pin > 4) + return (pin); + + device_printf(bus, "could not route pin %d for device %d.%d\n", + pin, pci_get_slot(dev), pci_get_function(dev)); + return (PCI_INVALID_IRQ); } static int diff --git a/sys/powerpc/powermac/uninorthvar.h b/sys/powerpc/powermac/uninorthvar.h index ff789ac..6bb4024 100644 --- a/sys/powerpc/powermac/uninorthvar.h +++ b/sys/powerpc/powermac/uninorthvar.h @@ -61,8 +61,10 @@ struct uninorth_softc { bus_space_tag_t sc_iot; bus_space_tag_t sc_memt; bus_dma_tag_t sc_dmat; + struct ofw_bus_iinfo sc_pci_iinfo; int sc_u3; + int sc_icells; }; struct unin_chip_softc { diff --git a/sys/powerpc/powerpc/pmap_dispatch.c b/sys/powerpc/powerpc/pmap_dispatch.c index 55112bb..33e94d1 100644 --- a/sys/powerpc/powerpc/pmap_dispatch.c +++ b/sys/powerpc/powerpc/pmap_dispatch.c @@ -37,9 +37,8 @@ __FBSDID("$FreeBSD$"); * the highest priority call will be installed as the default * MMU handler when pmap_bootstrap() is called. * - * It is required that kobj_machdep_init() be called before - * pmap_bootstrap() to allow the kobj subsystem to initialise. This - * in turn requires that mutex_init() has been called. + * It is required that mutex_init() be called before pmap_bootstrap(), + * as the PMAP layer makes extensive use of mutexes. */ #include <sys/param.h> diff --git a/sys/sparc64/conf/DEFAULTS b/sys/sparc64/conf/DEFAULTS index 910e61e..38b2408 100644 --- a/sys/sparc64/conf/DEFAULTS +++ b/sys/sparc64/conf/DEFAULTS @@ -14,8 +14,8 @@ device uart_sab82532 device uart_z8530 # Default partitioning schemes -options GEOM_BSD -options GEOM_SUNLABEL +options GEOM_PART_BSD +options GEOM_PART_VTOC8 # Let sunkbd emulate an AT keyboard by default. options SUNKBD_EMULATE_ATKBD diff --git a/sys/sparc64/ebus/ebus.c b/sys/sparc64/ebus/ebus.c index bcc92a2..9baa7a8 100644 --- a/sys/sparc64/ebus/ebus.c +++ b/sys/sparc64/ebus/ebus.c @@ -51,7 +51,6 @@ __FBSDID("$FreeBSD$"); #include <dev/ofw/ofw_bus_subr.h> #include <dev/ofw/openfirm.h> -#include <machine/ofw_bus.h> #include <machine/resource.h> #include <dev/pci/pcireg.h> @@ -118,6 +117,7 @@ static device_method_t ebus_methods[] = { DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_release_resource, ebus_release_resource), DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), + DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), /* ofw_bus interface */ DEVMETHOD(ofw_bus_get_devinfo, ebus_get_devinfo), diff --git a/sys/sparc64/include/elf.h b/sys/sparc64/include/elf.h index 76e3a76..108ade1 100644 --- a/sys/sparc64/include/elf.h +++ b/sys/sparc64/include/elf.h @@ -78,18 +78,6 @@ __ElfType(Auxinfo); #define AT_BASE 7 /* Interpreter's base address. */ #define AT_FLAGS 8 /* Flags (unused). */ #define AT_ENTRY 9 /* Where interpreter should transfer control. */ - -/* - * The following non-standard values are used for passing information - * from John Polstra's testbed program to the dynamic linker. These - * are expected to go away soon. - * - * Unfortunately, these overlap the Linux non-standard values, so they - * must not be used in the same context. - */ -#define T_BRK 10 /* Starting point for sbrk and brk. */ -#define AT_DEBUG 11 /* Debugging level. */ - /* * The following non-standard values are used in Linux ELF binaries. */ diff --git a/sys/sparc64/include/ofw_bus.h b/sys/sparc64/include/ofw_bus.h deleted file mode 100644 index 1e9004e..0000000 --- a/sys/sparc64/include/ofw_bus.h +++ /dev/null @@ -1,53 +0,0 @@ -/*- - * Copyright (c) 2001 - 2003 by Thomas Moestl <tmm@FreeBSD.org>. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE 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 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 _MACHINE_OFW_BUS_H_ -#define _MACHINE_OFW_BUS_H_ - -#define ORIP_NOINT -1 -#define ORIR_NOTFOUND 0xffffffff - -/* - * Other than in Open Firmware calls, the size of a bus cell seems to be - * always the same. - */ -typedef u_int32_t pcell_t; - -struct ofw_bus_iinfo { - u_int8_t *opi_imap; - u_int8_t *opi_imapmsk; - int opi_imapsz; - pcell_t opi_addrc; -}; - -void ofw_bus_setup_iinfo(phandle_t, struct ofw_bus_iinfo *, int); -int ofw_bus_lookup_imap(phandle_t, struct ofw_bus_iinfo *, void *, int, - void *, int, void *, int, void *); -int ofw_bus_search_intrmap(void *, int, void *, int, void *, int, void *, - void *, void *, int); - -#endif /* !_MACHINE_OFW_BUS_H_ */ diff --git a/sys/sparc64/include/ofw_machdep.h b/sys/sparc64/include/ofw_machdep.h index ac1fcc1..625b131 100644 --- a/sys/sparc64/include/ofw_machdep.h +++ b/sys/sparc64/include/ofw_machdep.h @@ -29,10 +29,15 @@ #define _MACHINE_OFW_MACHDEP_H_ #include <sys/bus.h> +#include <machine/bus.h> +#include <dev/ofw/openfirm.h> + +typedef uint64_t cell_t; int OF_decode_addr(phandle_t, int, int *, bus_addr_t *); void OF_getetheraddr(device_t, u_char *); void cpu_shutdown(void *); -void openfirmware_exit(void *); +int ofw_entry(void *); +void ofw_exit(void *); #endif /* _MACHINE_OFW_MACHDEP_H_ */ diff --git a/sys/sparc64/isa/ofw_isa.c b/sys/sparc64/isa/ofw_isa.c index e1d7537..de90869 100644 --- a/sys/sparc64/isa/ofw_isa.c +++ b/sys/sparc64/isa/ofw_isa.c @@ -41,10 +41,10 @@ __FBSDID("$FreeBSD$"); #include <sys/bus.h> #include <dev/ofw/openfirm.h> +#include <dev/ofw/ofw_bus_subr.h> #include <machine/bus.h> #include <machine/resource.h> -#include <machine/ofw_bus.h> #include <sparc64/pci/ofw_pci.h> #include <sparc64/isa/ofw_isa.h> diff --git a/sys/sparc64/pci/apb.c b/sys/sparc64/pci/apb.c index d908c17..ba0698c 100644 --- a/sys/sparc64/pci/apb.c +++ b/sys/sparc64/pci/apb.c @@ -53,7 +53,6 @@ __FBSDID("$FreeBSD$"); #include <dev/ofw/openfirm.h> #include <machine/bus.h> -#include <machine/ofw_bus.h> #include <machine/resource.h> #include <dev/pci/pcireg.h> diff --git a/sys/sparc64/pci/ofw_pci.h b/sys/sparc64/pci/ofw_pci.h index 252f474..19c2fbe 100644 --- a/sys/sparc64/pci/ofw_pci.h +++ b/sys/sparc64/pci/ofw_pci.h @@ -34,7 +34,7 @@ #ifndef _SPARC64_PCI_OFW_PCI_H_ #define _SPARC64_PCI_OFW_PCI_H_ -#include <machine/ofw_bus.h> +#include <dev/ofw/ofw_bus_subr.h> typedef uint32_t ofw_pci_intr_t; diff --git a/sys/sparc64/pci/ofw_pcib.c b/sys/sparc64/pci/ofw_pcib.c index 966d77f..8a5b991 100644 --- a/sys/sparc64/pci/ofw_pcib.c +++ b/sys/sparc64/pci/ofw_pcib.c @@ -45,7 +45,6 @@ __FBSDID("$FreeBSD$"); #include <dev/ofw/openfirm.h> #include <machine/bus.h> -#include <machine/ofw_bus.h> #include <dev/pci/pcireg.h> #include <dev/pci/pcivar.h> diff --git a/sys/sparc64/pci/ofw_pcib_subr.c b/sys/sparc64/pci/ofw_pcib_subr.c index 9996b7e..6dd0990 100644 --- a/sys/sparc64/pci/ofw_pcib_subr.c +++ b/sys/sparc64/pci/ofw_pcib_subr.c @@ -37,7 +37,6 @@ __FBSDID("$FreeBSD$"); #include <dev/ofw/openfirm.h> #include <machine/bus.h> -#include <machine/ofw_bus.h> #include <dev/pci/pcireg.h> #include <dev/pci/pcivar.h> diff --git a/sys/sparc64/pci/ofw_pcibus.c b/sys/sparc64/pci/ofw_pcibus.c index 7918370..65a498a 100644 --- a/sys/sparc64/pci/ofw_pcibus.c +++ b/sys/sparc64/pci/ofw_pcibus.c @@ -40,7 +40,6 @@ __FBSDID("$FreeBSD$"); #include <sys/pciio.h> #include <dev/ofw/ofw_bus.h> -#include <dev/ofw/ofw_bus_subr.h> #include <dev/ofw/ofw_pci.h> #include <dev/ofw/openfirm.h> @@ -69,6 +68,8 @@ static device_probe_t ofw_pcibus_probe; static device_attach_t ofw_pcibus_attach; static pci_assign_interrupt_t ofw_pcibus_assign_interrupt; static ofw_bus_get_devinfo_t ofw_pcibus_get_devinfo; +static int ofw_pcibus_child_pnpinfo_str_method(device_t cbdev, device_t child, + char *buf, size_t buflen); static device_method_t ofw_pcibus_methods[] = { /* Device interface */ @@ -76,6 +77,7 @@ static device_method_t ofw_pcibus_methods[] = { DEVMETHOD(device_attach, ofw_pcibus_attach), /* Bus interface */ + DEVMETHOD(bus_child_pnpinfo_str, ofw_pcibus_child_pnpinfo_str_method), /* PCI interface */ DEVMETHOD(pci_assign_interrupt, ofw_pcibus_assign_interrupt), @@ -302,3 +304,18 @@ ofw_pcibus_get_devinfo(device_t bus, device_t dev) dinfo = device_get_ivars(dev); return (&dinfo->opd_obdinfo); } + +static int +ofw_pcibus_child_pnpinfo_str_method(device_t cbdev, device_t child, char *buf, + size_t buflen) +{ + pci_child_pnpinfo_str_method(cbdev, child, buf, buflen); + + if (ofw_bus_get_node(child) != -1) { + strlcat(buf, " ", buflen); /* Separate info */ + ofw_bus_gen_child_pnpinfo_str(cbdev, child, buf, buflen); + } + + return (0); +} + diff --git a/sys/sparc64/pci/psycho.c b/sys/sparc64/pci/psycho.c index d961191..505eec4 100644 --- a/sys/sparc64/pci/psycho.c +++ b/sys/sparc64/pci/psycho.c @@ -64,7 +64,6 @@ __FBSDID("$FreeBSD$"); #include <machine/bus_private.h> #include <machine/iommureg.h> #include <machine/iommuvar.h> -#include <machine/ofw_bus.h> #include <machine/resource.h> #include <machine/ver.h> diff --git a/sys/sparc64/pci/schizo.c b/sys/sparc64/pci/schizo.c index 8f01f9c..2425294 100644 --- a/sys/sparc64/pci/schizo.c +++ b/sys/sparc64/pci/schizo.c @@ -65,7 +65,6 @@ __FBSDID("$FreeBSD$"); #include <machine/fsr.h> #include <machine/iommureg.h> #include <machine/iommuvar.h> -#include <machine/ofw_bus.h> #include <machine/resource.h> #include <dev/pci/pcireg.h> @@ -395,9 +394,10 @@ schizo_attach(device_t dev) /* * Hunt through all the interrupt mapping regs and register - * the interrupt controller for our interrupt vectors. This - * is complicated by the fact that a pair of Schizo PBMs - * share one IGN. + * the interrupt controller for our interrupt vectors. We do + * this early in order to be able to catch stray interrupts. + * This is complicated by the fact that a pair of Schizo PBMs + * shares one IGN. */ n = OF_getprop(node, "ino-bitmap", (void *)prop_array, sizeof(prop_array)); @@ -412,8 +412,8 @@ schizo_attach(device_t dev) continue; i = schizo_intr_register(sc, n); if (i != 0) - panic("%s: could not register interrupt controller " - "for INO %d (%d)", __func__, n, i); + device_printf(dev, "could not register interrupt " + "controller for INO %d (%d)\n", n, i); } /* @@ -1128,16 +1128,40 @@ schizo_setup_intr(device_t dev, device_t child, struct resource *ires, sc = device_get_softc(dev); /* - * Make sure the vector is fully specified and we registered - * our interrupt controller for it. + * Make sure the vector is fully specified. */ vec = rman_get_start(ires); - if (INTIGN(vec) != sc->sc_ign || - intr_vectors[vec].iv_ic != &schizo_ic) { + if (INTIGN(vec) != sc->sc_ign) { device_printf(dev, "invalid interrupt vector 0x%lx\n", vec); return (EINVAL); } + if (intr_vectors[vec].iv_ic == &schizo_ic) { + /* + * Ensure we use the right softc in case the interrupt + * is routed to our companion PBM for some odd reason. + */ + sc = ((struct schizo_icarg *)intr_vectors[vec].iv_icarg)-> + sica_sc; + } else if (intr_vectors[vec].iv_ic == NULL) { + /* + * Work around broken firmware which misses entries in + * the ino-bitmap. + */ + error = schizo_intr_register(sc, INTINO(vec)); + if (error != 0) { + device_printf(dev, "could not register interrupt " + "controller for vector 0x%lx (%d)\n", vec, error); + return (error); + } + device_printf(dev, "belatedly registered as interrupt " + "controller for vector 0x%lx\n", vec); + } else { + device_printf(dev, + "invalid interrupt controller for vector 0x%lx\n", vec); + return (EINVAL); + } + /* * Install a a wrapper for CDMA flushing/syncing for devices * behind PCI-PCI bridges if possible. @@ -1206,7 +1230,7 @@ schizo_setup_intr(device_t dev, device_t child, struct resource *ires, return (error); } else if (found != 0) device_printf(dev, "WARNING: using devices behind PCI-PCI " - "bridges may cause data corruption"); + "bridges may cause data corruption\n"); return (bus_generic_setup_intr(dev, child, ires, flags, filt, intr, arg, cookiep)); } diff --git a/sys/sparc64/sbus/sbus.c b/sys/sparc64/sbus/sbus.c index a97fd10..d6b8393 100644 --- a/sys/sparc64/sbus/sbus.c +++ b/sys/sparc64/sbus/sbus.c @@ -226,6 +226,7 @@ static device_method_t sbus_methods[] = { DEVMETHOD(bus_get_resource_list, sbus_get_resource_list), DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), DEVMETHOD(bus_get_dma_tag, sbus_get_dma_tag), + DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), /* ofw_bus interface */ DEVMETHOD(ofw_bus_get_devinfo, sbus_get_devinfo), diff --git a/sys/sparc64/sparc64/machdep.c b/sys/sparc64/sparc64/machdep.c index 0be9af9..4e1e300 100644 --- a/sys/sparc64/sparc64/machdep.c +++ b/sys/sparc64/sparc64/machdep.c @@ -276,9 +276,10 @@ sparc64_init(caddr_t mdp, u_long o1, u_long o2, u_long o3, ofw_vec_t *vec) tick_stop(); /* - * Initialize Open Firmware (needed for console). + * Set up Open Firmware entry points */ - OF_init(vec); + ofw_tba = rdpr(tba); + ofw_vec = (u_long)vec; /* * Parse metadata if present and fetch parameters. Must be before the @@ -301,6 +302,12 @@ sparc64_init(caddr_t mdp, u_long o1, u_long o2, u_long o3, ofw_vec_t *vec) init_param1(); /* + * Initialize Open Firmware (needed for console). + */ + OF_install(OFW_STD_DIRECT, 0); + OF_init(ofw_entry); + + /* * Prime our per-CPU data page for use. Note, we are using it for * our stack, so don't pass the real size (PAGE_SIZE) to pcpu_init * or it'll zero it out from under us. @@ -481,14 +488,6 @@ sparc64_init(caddr_t mdp, u_long o1, u_long o2, u_long o3, ofw_vec_t *vec) } void -set_openfirm_callback(ofw_vec_t *vec) -{ - - ofw_tba = rdpr(tba); - ofw_vec = (u_long)vec; -} - -void sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) { struct trapframe *tf; @@ -725,7 +724,7 @@ cpu_shutdown(void *args) #ifdef SMP cpu_mp_shutdown(); #endif - openfirmware_exit(args); + ofw_exit(args); } /* Get current clock frequency for the given CPU ID. */ diff --git a/sys/sparc64/sparc64/mp_machdep.c b/sys/sparc64/sparc64/mp_machdep.c index 5cace48..bf79adf 100644 --- a/sys/sparc64/sparc64/mp_machdep.c +++ b/sys/sparc64/sparc64/mp_machdep.c @@ -221,7 +221,7 @@ sun4u_startcpu(phandle_t cpu, void *func, u_long arg) args.cpu = cpu; args.func = (cell_t)func; args.arg = (cell_t)arg; - openfirmware(&args); + ofw_entry(&args); } /* @@ -238,7 +238,7 @@ sun4u_stopself(void) (cell_t)SUNW_STOPSELF, }; - openfirmware_exit(&args); + ofw_exit(&args); panic("%s: failed.", __func__); } diff --git a/sys/sparc64/sparc64/ofw_bus.c b/sys/sparc64/sparc64/ofw_bus.c deleted file mode 100644 index f7458dc..0000000 --- a/sys/sparc64/sparc64/ofw_bus.c +++ /dev/null @@ -1,198 +0,0 @@ -/*- - * Copyright (C) 1996 Wolfgang Solfrank. - * Copyright (C) 1996 TooLs GmbH. - * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by TooLs GmbH. - * 4. The name of TooLs GmbH may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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. - */ -/*- - * Copyright (c) 2001 - 2003 by Thomas Moestl <tmm@FreeBSD.org>. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE 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 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. - * - * from: $NetBSD: ofw_machdep.c,v 1.16 2001/07/20 00:07:14 eeh Exp $ - * - * $FreeBSD$ - */ - -/* - * Open Firmware bus support code that is (hopefully) independent from the - * used hardware. - * Maybe this should go into dev/ofw/; there may however be sparc specific - * bits left. - */ - -#include <sys/param.h> -#include <sys/malloc.h> -#include <sys/systm.h> - -#include <dev/ofw/openfirm.h> - -#include <machine/ofw_bus.h> - -static int -ofw_bus_searchprop(phandle_t node, char *propname, void *buf, int buflen) -{ - int rv; - - for (; node != 0; node = OF_parent(node)) { - if ((rv = OF_getprop(node, propname, buf, buflen)) != -1) - return (rv); - } - return (-1); -} - -void -ofw_bus_setup_iinfo(phandle_t node, struct ofw_bus_iinfo *ii, int intrsz) -{ - pcell_t addrc; - int msksz; - - if (OF_getprop(node, "#address-cells", &addrc, sizeof(addrc)) == -1) - addrc = 2; - ii->opi_addrc = addrc * sizeof(pcell_t); - - ii->opi_imapsz = OF_getprop_alloc(node, "interrupt-map", 1, - (void **)&ii->opi_imap); - if (ii->opi_imapsz > 0) { - msksz = OF_getprop_alloc(node, "interrupt-map-mask", 1, - (void **)&ii->opi_imapmsk); - /* - * Failure to get the mask is ignored; a full mask is used then. - * Barf on bad mask sizes, however. - */ - if (msksz != -1 && msksz != ii->opi_addrc + intrsz) { - panic("ofw_bus_setup_iinfo: bad interrupt-map-mask " - "property!"); - } - } - -} - -int -ofw_bus_lookup_imap(phandle_t node, struct ofw_bus_iinfo *ii, void *reg, - int regsz, void *pintr, int pintrsz, void *mintr, int mintrsz, - void *maskbuf) -{ - int rv; - - if (ii->opi_imapsz <= 0) - return (0); - KASSERT(regsz >= ii->opi_addrc, - ("ofw_bus_lookup_imap: register size too small: %d < %d", - regsz, ii->opi_addrc)); - rv = OF_getprop(node, "reg", reg, regsz); - if (rv < regsz) - panic("ofw_bus_lookup_imap: could not get reg property"); - return (ofw_bus_search_intrmap(pintr, pintrsz, reg, ii->opi_addrc, - ii->opi_imap, ii->opi_imapsz, ii->opi_imapmsk, maskbuf, mintr, - mintrsz)); -} - -/* - * Map an interrupt using the firmware reg, interrupt-map and - * interrupt-map-mask properties. - * The interrupt property to be mapped must be of size intrsz, and pointed to - * by intr. The regs property of the node for which the mapping is done must - * be passed as regs. This property is an array of register specifications; - * the size of the address part of such a specification must be passed as - * physsz. Only the first element of the property is used. - * imap and imapsz hold the interrupt mask and it's size. - * imapmsk is a pointer to the interrupt-map-mask property, which must have - * a size of physsz + intrsz; it may be NULL, in which case a full mask is - * assumed. - * maskbuf must point to a buffer of length physsz + intrsz. - * The interrupt is returned in result, which must point to a buffer of length - * rintrsz (which gives the expected size of the mapped interrupt). - * Returns 1 if a mapping was found, 0 otherwise. - */ -int -ofw_bus_search_intrmap(void *intr, int intrsz, void *regs, int physsz, - void *imap, int imapsz, void *imapmsk, void *maskbuf, void *result, - int rintrsz) -{ - phandle_t parent; - u_int8_t *ref = maskbuf; - u_int8_t *uiintr = intr; - u_int8_t *uiregs = regs; - u_int8_t *uiimapmsk = imapmsk; - u_int8_t *mptr; - pcell_t pintrsz; - int i, rsz, tsz; - - rsz = -1; - if (imapmsk != NULL) { - for (i = 0; i < physsz; i++) - ref[i] = uiregs[i] & uiimapmsk[i]; - for (i = 0; i < intrsz; i++) - ref[physsz + i] = uiintr[i] & uiimapmsk[physsz + i]; - } else { - bcopy(regs, ref, physsz); - bcopy(intr, ref + physsz, intrsz); - } - - mptr = imap; - i = imapsz; - tsz = physsz + intrsz + sizeof(phandle_t) + rintrsz; - while (i > 0) { - KASSERT(i >= tsz, ("ofw_bus_search_intrmap: truncated map")); - bcopy(mptr + physsz + intrsz, &parent, sizeof(parent)); - if (ofw_bus_searchprop(parent, "#interrupt-cells", - &pintrsz, sizeof(pintrsz)) == -1) - pintrsz = 1; /* default */ - pintrsz *= sizeof(pcell_t); - if (pintrsz != rintrsz) - panic("ofw_bus_search_intrmap: expected interrupt cell " - "size incorrect: %d != %d", rintrsz, pintrsz); - if (bcmp(ref, mptr, physsz + intrsz) == 0) { - bcopy(mptr + physsz + intrsz + sizeof(parent), - result, rintrsz); - return (1); - } - mptr += tsz; - i -= tsz; - } - return (0); -} diff --git a/sys/sparc64/sparc64/ofw_machdep.c b/sys/sparc64/sparc64/ofw_machdep.c index 7efc807..bcacea7 100644 --- a/sys/sparc64/sparc64/ofw_machdep.c +++ b/sys/sparc64/sparc64/ofw_machdep.c @@ -43,7 +43,6 @@ __FBSDID("$FreeBSD$"); #include <machine/bus.h> #include <machine/idprom.h> -#include <machine/ofw_bus.h> #include <machine/ofw_machdep.h> void diff --git a/sys/sparc64/sparc64/support.S b/sys/sparc64/sparc64/support.S index a3f6501..821e694 100644 --- a/sys/sparc64/sparc64/support.S +++ b/sys/sparc64/sparc64/support.S @@ -745,9 +745,9 @@ ENTRY(setjmp) END(setjmp) /* - * void openfirmware(cell_t args[]) + * void ofw_entry(cell_t args[]) */ -ENTRY(openfirmware) +ENTRY(ofw_entry) save %sp, -CCFSZ, %sp SET(ofw_vec, %l7, %l6) ldx [%l6], %l6 @@ -758,12 +758,12 @@ ENTRY(openfirmware) wrpr %l7, 0, %pil ret restore %o0, %g0, %o0 -END(openfirmware) +END(ofw_entry) /* - * void openfirmware_exit(cell_t args[]) + * void ofw_exit(cell_t args[]) */ -ENTRY(openfirmware_exit) +ENTRY(ofw_exit) save %sp, -CCFSZ, %sp flushw wrpr %g0, PIL_TICK, %pil @@ -783,7 +783,7 @@ ENTRY(openfirmware_exit) call %l6 mov %i0, %o0 ! never to return -END(openfirmware_exit) +END(ofw_exit) #ifdef GPROF diff --git a/sys/sparc64/sparc64/trap.c b/sys/sparc64/sparc64/trap.c index 9de8e26..c10dbc4 100644 --- a/sys/sparc64/sparc64/trap.c +++ b/sys/sparc64/sparc64/trap.c @@ -71,6 +71,7 @@ __FBSDID("$FreeBSD$"); #include <security/audit/audit.h> #include <dev/ofw/openfirm.h> +#include <machine/ofw_machdep.h> #include <vm/vm.h> #include <vm/pmap.h> @@ -248,7 +249,7 @@ sun4u_set_traptable(void *tba_addr) }; args.tba_addr = (cell_t)tba_addr; - openfirmware(&args); + ofw_entry(&args); } void diff --git a/sys/sparc64/sparc64/vm_machdep.c b/sys/sparc64/sparc64/vm_machdep.c index c163fd8..b769753 100644 --- a/sys/sparc64/sparc64/vm_machdep.c +++ b/sys/sparc64/sparc64/vm_machdep.c @@ -334,7 +334,7 @@ cpu_reset(void) bspec[sizeof(bspec) - 1] = '\0'; } - openfirmware_exit(&args); + ofw_exit(&args); } /* diff --git a/sys/sun4v/conf/DEFAULTS b/sys/sun4v/conf/DEFAULTS index ba7c539..610d653 100644 --- a/sys/sun4v/conf/DEFAULTS +++ b/sys/sun4v/conf/DEFAULTS @@ -9,5 +9,5 @@ machine sun4v device mem # Memory and kernel memory devices # Default partitioning schemes -options GEOM_BSD -options GEOM_SUNLABEL +options GEOM_PART_BSD +options GEOM_PART_VTOC8 diff --git a/sys/sun4v/include/elf.h b/sys/sun4v/include/elf.h index 76e3a76..108ade1 100644 --- a/sys/sun4v/include/elf.h +++ b/sys/sun4v/include/elf.h @@ -78,18 +78,6 @@ __ElfType(Auxinfo); #define AT_BASE 7 /* Interpreter's base address. */ #define AT_FLAGS 8 /* Flags (unused). */ #define AT_ENTRY 9 /* Where interpreter should transfer control. */ - -/* - * The following non-standard values are used for passing information - * from John Polstra's testbed program to the dynamic linker. These - * are expected to go away soon. - * - * Unfortunately, these overlap the Linux non-standard values, so they - * must not be used in the same context. - */ -#define T_BRK 10 /* Starting point for sbrk and brk. */ -#define AT_DEBUG 11 /* Debugging level. */ - /* * The following non-standard values are used in Linux ELF binaries. */ diff --git a/sys/sun4v/include/ofw_bus.h b/sys/sun4v/include/ofw_bus.h deleted file mode 100644 index 1e9004e..0000000 --- a/sys/sun4v/include/ofw_bus.h +++ /dev/null @@ -1,53 +0,0 @@ -/*- - * Copyright (c) 2001 - 2003 by Thomas Moestl <tmm@FreeBSD.org>. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE 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 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 _MACHINE_OFW_BUS_H_ -#define _MACHINE_OFW_BUS_H_ - -#define ORIP_NOINT -1 -#define ORIR_NOTFOUND 0xffffffff - -/* - * Other than in Open Firmware calls, the size of a bus cell seems to be - * always the same. - */ -typedef u_int32_t pcell_t; - -struct ofw_bus_iinfo { - u_int8_t *opi_imap; - u_int8_t *opi_imapmsk; - int opi_imapsz; - pcell_t opi_addrc; -}; - -void ofw_bus_setup_iinfo(phandle_t, struct ofw_bus_iinfo *, int); -int ofw_bus_lookup_imap(phandle_t, struct ofw_bus_iinfo *, void *, int, - void *, int, void *, int, void *); -int ofw_bus_search_intrmap(void *, int, void *, int, void *, int, void *, - void *, void *, int); - -#endif /* !_MACHINE_OFW_BUS_H_ */ diff --git a/sys/sun4v/sun4v/machdep.c b/sys/sun4v/sun4v/machdep.c index 6281f00..b7c0869 100644 --- a/sys/sun4v/sun4v/machdep.c +++ b/sys/sun4v/sun4v/machdep.c @@ -310,18 +310,18 @@ sparc64_init(caddr_t mdp, u_long o1, u_long o2, u_long o3, ofw_vec_t *vec) end = 0; kmdp = NULL; - /* - * Initialize Open Firmware (needed for console). - */ - OF_init(vec); - - /* * XXX */ bootverbose = 1; /* + * Set up Open Firmware entry points + */ + ofw_tba = rdpr(tba); + ofw_vec = (u_long)vec; + + /* * Parse metadata if present and fetch parameters. Must be before the * console is inited so cninit gets the right value of boothowto. */ @@ -344,6 +344,12 @@ sparc64_init(caddr_t mdp, u_long o1, u_long o2, u_long o3, ofw_vec_t *vec) init_param1(); + /* + * Initialize Open Firmware (needed for console). + */ + OF_install(OFW_STD_DIRECT, 0); + OF_init(ofw_entry); + root = OF_peer(0); for (child = OF_child(root); child != 0; child = OF_peer(child)) { OF_getprop(child, "device_type", type, sizeof(type)); @@ -516,13 +522,6 @@ sparc64_init(caddr_t mdp, u_long o1, u_long o2, u_long o3, ofw_vec_t *vec) } void -set_openfirm_callback(ofw_vec_t *vec) -{ - ofw_tba = rdpr(tba); - ofw_vec = (u_long)vec; -} - -void sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) { struct trapframe *tf; diff --git a/sys/sun4v/sun4v/mp_machdep.c b/sys/sun4v/sun4v/mp_machdep.c index 8bd4ba6..5f4f632 100644 --- a/sys/sun4v/sun4v/mp_machdep.c +++ b/sys/sun4v/sun4v/mp_machdep.c @@ -272,7 +272,7 @@ start_ap_bycpuid(int cpuid, void *func, u_long arg) args.cpuid = cpuid; args.func = (cell_t)func; args.arg = (cell_t)arg; - openfirmware(&args); + ofw_entry(&args); return (int)args.result; } diff --git a/sys/sun4v/sun4v/support.S b/sys/sun4v/sun4v/support.S index e6bac5d..699a40f 100644 --- a/sys/sun4v/sun4v/support.S +++ b/sys/sun4v/sun4v/support.S @@ -622,9 +622,9 @@ ENTRY(setjmp) END(setjmp) /* - * void openfirmware(cell_t args[]) + * void ofw_entry(cell_t args[]) */ -ENTRY(openfirmware) +ENTRY(ofw_entry) save %sp, -CCFSZ, %sp SET(ofw_vec, %l7, %l6) ldx [%l6], %l6 @@ -635,14 +635,14 @@ ENTRY(openfirmware) wrpr %l7, 0, %pil ret restore %o0, %g0, %o0 -END(openfirmware) +END(ofw_entry) #ifdef notyet /* SUN4V_FIXME - uses a now illegal ASI */ /* * void ofw_exit(cell_t args[]) */ -ENTRY(openfirmware_exit) +ENTRY(ofw_exit) save %sp, -CCFSZ, %sp flushw wrpr %g0, PIL_TICK, %pil @@ -661,7 +661,7 @@ ENTRY(openfirmware_exit) call %l6 mov %i0, %o0 ! never to return -END(openfirmware_exit) +END(ofw_exit) #endif ENTRY(set_mmfsa_scratchpad) diff --git a/sys/sun4v/sun4v/trap.c b/sys/sun4v/sun4v/trap.c index f04c424..bac4f55 100644 --- a/sys/sun4v/sun4v/trap.c +++ b/sys/sun4v/sun4v/trap.c @@ -261,7 +261,7 @@ set_mmfsa_traptable(void *tba_addr, uint64_t mmfsa_ra) args.tba_addr = (cell_t)tba_addr; args.mmfsa_ra = mmfsa_ra; - openfirmware(&args); + ofw_entry(&args); } void diff --git a/sys/sys/buf_ring.h b/sys/sys/buf_ring.h index 6d0cb7d..efea85a 100644 --- a/sys/sys/buf_ring.h +++ b/sys/sys/buf_ring.h @@ -48,10 +48,11 @@ struct buf_ring { volatile uint32_t br_prod_tail; int br_prod_size; int br_prod_mask; + uint64_t br_drops; /* * Pad out to next L2 cache line */ - uint64_t _pad0[14]; + uint64_t _pad0[13]; volatile uint32_t br_cons_head; volatile uint32_t br_cons_tail; diff --git a/sys/sys/elf_common.h b/sys/sys/elf_common.h index 95f3352..688fab2 100644 --- a/sys/sys/elf_common.h +++ b/sys/sys/elf_common.h @@ -101,6 +101,7 @@ typedef struct { #define ELFOSABI_OPENBSD 12 /* OpenBSD */ #define ELFOSABI_OPENVMS 13 /* Open VMS */ #define ELFOSABI_NSK 14 /* HP Non-Stop Kernel */ +#define ELFOSABI_AROS 15 /* Amiga Research OS */ #define ELFOSABI_ARM 97 /* ARM */ #define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ @@ -169,6 +170,61 @@ typedef struct { #define EM_TINYJ 61 /* Advanced Logic Corp. TinyJ processor. */ #define EM_X86_64 62 /* Advanced Micro Devices x86-64 */ #define EM_AMD64 EM_X86_64 /* Advanced Micro Devices x86-64 (compat) */ +#define EM_PDSP 63 /* Sony DSP Processor. */ +#define EM_FX66 66 /* Siemens FX66 microcontroller. */ +#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 + microcontroller. */ +#define EM_ST7 68 /* STmicroelectronics ST7 8-bit + microcontroller. */ +#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller. */ +#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller. */ +#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller. */ +#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller. */ +#define EM_SVX 73 /* Silicon Graphics SVx. */ +#define EM_ST19 74 /* STMicroelectronics ST19 8-bit mc. */ +#define EM_VAX 75 /* Digital VAX. */ +#define EM_CRIS 76 /* Axis Communications 32-bit embedded + processor. */ +#define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded + processor. */ +#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor. */ +#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor. */ +#define EM_MMIX 80 /* Donald Knuth's educational 64-bit proc. */ +#define EM_HUANY 81 /* Harvard University machine-independent + object files. */ +#define EM_PRISM 82 /* SiTera Prism. */ +#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller. */ +#define EM_FR30 84 /* Fujitsu FR30. */ +#define EM_D10V 85 /* Mitsubishi D10V. */ +#define EM_D30V 86 /* Mitsubishi D30V. */ +#define EM_V850 87 /* NEC v850. */ +#define EM_M32R 88 /* Mitsubishi M32R. */ +#define EM_MN10300 89 /* Matsushita MN10300. */ +#define EM_MN10200 90 /* Matsushita MN10200. */ +#define EM_PJ 91 /* picoJava. */ +#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor. */ +#define EM_ARC_A5 93 /* ARC Cores Tangent-A5. */ +#define EM_XTENSA 94 /* Tensilica Xtensa Architecture. */ +#define EM_VIDEOCORE 95 /* Alphamosaic VideoCore processor. */ +#define EM_TMM_GPP 96 /* Thompson Multimedia General Purpose + Processor. */ +#define EM_NS32K 97 /* National Semiconductor 32000 series. */ +#define EM_TPC 98 /* Tenor Network TPC processor. */ +#define EM_SNP1K 99 /* Trebia SNP 1000 processor. */ +#define EM_ST200 100 /* STMicroelectronics ST200 microcontroller. */ +#define EM_IP2K 101 /* Ubicom IP2xxx microcontroller family. */ +#define EM_MAX 102 /* MAX Processor. */ +#define EM_CR 103 /* National Semiconductor CompactRISC + microprocessor. */ +#define EM_F2MC16 104 /* Fujitsu F2MC16. */ +#define EM_MSP430 105 /* Texas Instruments embedded microcontroller + msp430. */ +#define EM_BLACKFIN 106 /* Analog Devices Blackfin (DSP) processor. */ +#define EM_SE_C33 107 /* S1C33 Family of Seiko Epson processors. */ +#define EM_SEP 108 /* Sharp embedded microprocessor. */ +#define EM_ARCA 109 /* Arca RISC Microprocessor. */ +#define EM_UNICORE 110 /* Microprocessor series from PKU-Unity Ltd. + and MPRC of Peking University */ /* Non-standard or deprecated. */ #define EM_486 6 /* Intel i486. */ @@ -195,12 +251,12 @@ typedef struct { #define SHT_STRTAB 3 /* string table section */ #define SHT_RELA 4 /* relocation section with addends */ #define SHT_HASH 5 /* symbol hash table section */ -#define SHT_DYNAMIC 6 /* dynamic section */ +#define SHT_DYNAMIC 6 /* dynamic section */ #define SHT_NOTE 7 /* note section */ #define SHT_NOBITS 8 /* no space section */ #define SHT_REL 9 /* relocation section - no addends */ #define SHT_SHLIB 10 /* reserved - purpose unknown */ -#define SHT_DYNSYM 11 /* dynamic symbol table section */ +#define SHT_DYNSYM 11 /* dynamic symbol table section */ #define SHT_INIT_ARRAY 14 /* Initialization function pointers. */ #define SHT_FINI_ARRAY 15 /* Termination function pointers. */ #define SHT_PREINIT_ARRAY 16 /* Pre-initialization function ptrs. */ diff --git a/sys/sys/imgact_elf.h b/sys/sys/imgact_elf.h index 663a090..ec1d638 100644 --- a/sys/sys/imgact_elf.h +++ b/sys/sys/imgact_elf.h @@ -52,7 +52,6 @@ typedef struct { Elf_Size base; Elf_Size flags; Elf_Size entry; - Elf_Size trace; } __ElfN(Auxargs); typedef struct { diff --git a/sys/sys/kobj.h b/sys/sys/kobj.h index b744db8..64a666a 100644 --- a/sys/sys/kobj.h +++ b/sys/sys/kobj.h @@ -246,9 +246,4 @@ kobj_method_t* kobj_lookup_method(kobj_class_t cls, */ int kobj_error_method(void); -/* - * Machine-dependent initialisation call for boot-time kobj clients - */ -void kobj_machdep_init(void); - #endif /* !_SYS_KOBJ_H_ */ diff --git a/sys/sys/mount.h b/sys/sys/mount.h index 51cff5d..60086c6 100644 --- a/sys/sys/mount.h +++ b/sys/sys/mount.h @@ -316,6 +316,7 @@ void __mnt_vnode_markerfree(struct vnode **mvp, struct mount *mp); #define MNTK_SOFTDEP 0x00000004 /* async disabled by softdep */ #define MNTK_NOINSMNTQ 0x00000008 /* insmntque is not allowed */ #define MNTK_DRAINING 0x00000010 /* lock draining is happening */ +#define MNTK_REFEXPIRE 0x00000020 /* refcount expiring is happening */ #define MNTK_UNMOUNT 0x01000000 /* unmount in progress */ #define MNTK_MWAIT 0x02000000 /* waiting for unmount to finish */ #define MNTK_SUSPEND 0x08000000 /* request write suspension */ diff --git a/sys/sys/param.h b/sys/sys/param.h index 497b362..fad4d51 100644 --- a/sys/sys/param.h +++ b/sys/sys/param.h @@ -57,7 +57,7 @@ * is created, otherwise 1. */ #undef __FreeBSD_version -#define __FreeBSD_version 800058 /* Master, propagated to newvers */ +#define __FreeBSD_version 800060 /* Master, propagated to newvers */ #ifndef LOCORE #include <sys/types.h> diff --git a/sys/sys/ttyhook.h b/sys/sys/ttyhook.h index 7a0a0bc..2a6d088 100644 --- a/sys/sys/ttyhook.h +++ b/sys/sys/ttyhook.h @@ -66,7 +66,7 @@ struct ttyhook { th_close_t *th_close; }; -int ttyhook_register(struct tty **, struct thread *, int, +int ttyhook_register(struct tty **, struct proc *, int, struct ttyhook *, void *); void ttyhook_unregister(struct tty *); #define ttyhook_softc(tp) ((tp)->t_hooksoftc) diff --git a/sys/sys/vtoc.h b/sys/sys/vtoc.h index 83b8547..231da00 100644 --- a/sys/sys/vtoc.h +++ b/sys/sys/vtoc.h @@ -72,7 +72,7 @@ struct vtoc8 { struct { uint16_t tag; uint16_t flag; - } part[VTOC8_NPARTS]; + } part[VTOC8_NPARTS] __packed; uint16_t __alignment; uint32_t bootinfo[3]; uint32_t sanity; diff --git a/sys/ufs/ufs/ufs_vfsops.c b/sys/ufs/ufs/ufs_vfsops.c index 14ce4c6..ac1fbcf 100644 --- a/sys/ufs/ufs/ufs_vfsops.c +++ b/sys/ufs/ufs/ufs_vfsops.c @@ -118,9 +118,6 @@ ufs_quotactl(mp, cmds, id, arg, td) if ((u_int)type >= MAXQUOTAS) return (EINVAL); - if (vfs_busy(mp, MBF_NOWAIT)) - return (0); - switch (cmd) { case Q_QUOTAON: error = quotaon(td, mp, type, arg); @@ -150,7 +147,6 @@ ufs_quotactl(mp, cmds, id, arg, td) error = EINVAL; break; } - vfs_unbusy(mp); return (error); #endif } diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c index e5047e9..7b639e8 100644 --- a/sys/ufs/ufs/ufs_vnops.c +++ b/sys/ufs/ufs/ufs_vnops.c @@ -2013,7 +2013,7 @@ ufs_strategy(ap) bp->b_error = error; bp->b_ioflags |= BIO_ERROR; bufdone(bp); - return (error); + return (0); } if ((long)bp->b_blkno == -1) vfs_bio_clrbuf(bp); |