DF-5763 / btdisp_rig.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | /* * DF-5763 rig — drives the VERBATIM production sys/netbt/bt_proto.c * (linked unmodified into this KLD by build.sh) through the DragonFly * socket layer to interrogate the dom_dispose wiring: * * hw.btdisp.info (RD) wiring facts: domain name, dom_dispose * pointer, btsw[0] flags, pool pointers * hw.btdisp.arm (RW) writing 1 sets btsw[0].pr_flags |= PR_RIGHTS * — the ONE-BIT precondition that DragonFly's * sorflush()/so-receive PR_RIGHTS gate requires * before it will ever call dom_dispose * (sys/kern/uipc_socket.c:1986-1987,1609-1611). * Production btsw[] never sets PR_RIGHTS, so * production netbt_dispose is DEAD CODE. * * CONTROL: sockets + shutdown WITHOUT arm must never disturb the pools. * ARMED: the next sorflush runs production netbt_dispose() -> * zdestroy() of the three GLOBAL vm_zones (vm_zone.c:516-544, * kfree(z) at :543); any repeat destroys freed zones. * * netbt_dispose is static in bt_proto.c; its address is captured from the * module symbol table by build.sh (nm) and compared at runtime against * btdomain.dom_dispose printed by hw.btdisp.info. */ #include <sys/param.h> #include <sys/domain.h> #include <sys/kernel.h> #include <sys/protosw.h> #include <sys/socket.h> #include <sys/socketvar.h> #include <sys/socketvar2.h> #include <sys/msgport2.h> #include <sys/libkern.h> #include <sys/sysctl.h> #include <sys/systm.h> #include <netbt/bluetooth.h> #include <netbt/hci.h> #include <netbt/l2cap.h> #include <netbt/rfcomm.h> #include <netbt/sco.h> extern struct domain btdomain; /* production bt_proto.c */ extern struct protosw btsw[]; /* production bt_proto.c */ extern struct pr_usrreqs hci_usrreqs; /* production bt_proto.c:40 */ static int armed; /* * minimal pru_attach so socreate() succeeds (uipc_socket.c:217 requires * pru_attach != NULL). Real hci_sattach lives in hci_socket.c; we only * need the socket object for sorflush(). */ static void btdisp_stub_attach(union netmsg *msg) { struct socket *so = msg->attach.base.nm_so; lwkt_replymsg(&msg->attach.base.lmsg, soreserve(so, 4096, 4096, NULL)); } static int btdisp_info(SYSCTL_HANDLER_ARGS) { char buf[256]; ksnprintf(buf, sizeof(buf), "domain=%s fam=%d dom_dispose=%p btsw[0].pr_flags=0x%08x " "PR_RIGHTS=%d pools: pdu=%p req=%p credit=%p", btdomain.dom_name, btdomain.dom_family, btdomain.dom_dispose, btsw[0].pr_flags, !!(btsw[0].pr_flags & PR_RIGHTS), l2cap_pdu_pool, l2cap_req_pool, rfcomm_credit_pool); return (sysctl_handle_string(oidp, buf, sizeof(buf), req)); } static int btdisp_arm(SYSCTL_HANDLER_ARGS) { int error, val = armed; error = sysctl_handle_int(oidp, &val, 0, req); if (error != 0 || req->newptr == NULL) return (error); if (val && !armed) { kprintf("btdisp: ARMING btsw[0].pr_flags 0x%08x -> 0x%08x " "(set PR_RIGHTS; sorflush will now call dom_dispose)\n", btsw[0].pr_flags, btsw[0].pr_flags | PR_RIGHTS); btsw[0].pr_flags |= PR_RIGHTS; armed = 1; } return (0); } SYSCTL_NODE(_hw, OID_AUTO, btdisp, CTLFLAG_RW, 0, "DF-5763 rig"); SYSCTL_PROC(_hw_btdisp, OID_AUTO, info, CTLTYPE_STRING | CTLFLAG_RD, NULL, 0, btdisp_info, "A", "dom_dispose wiring facts"); SYSCTL_PROC(_hw_btdisp, OID_AUTO, arm, CTLTYPE_INT | CTLFLAG_RW, NULL, 0, btdisp_arm, "I", "set PR_RIGHTS on btsw[0]"); static void btdisp_init(void *dummy __unused) { /* make raw HCI sockets creatable through the production protosw */ hci_usrreqs.pru_attach = btdisp_stub_attach; } SYSINIT(btdisp_init, SI_BOOT2_KLD, SI_ORDER_ANY + 1, btdisp_init, NULL); |